Skip to content
FastVideo
Esc
↑↓navigate↵open⌘Jpreview
On this page

utils

fastvideo.models.dits.matrixgame2.utils.get_local_torch_device

get_local_torch_device() -> torch.device

Return the torch device for the current rank.

fastvideo.models.dits.matrixgame2.utils.retain_kv_with_sink

retain_kv_with_sink(k: torch.Tensor, v: torch.Tensor, target_len: int, sink_size: int) -> tuple[torch.Tensor, torch.Tensor]
Source
def retain_kv_with_sink(
    k: torch.Tensor,
    v: torch.Tensor,
    target_len: int,
    sink_size: int,
) -> tuple[torch.Tensor, torch.Tensor]:
    if k.shape[1] <= target_len or sink_size <= 0:
        return k[:, -target_len:], v[:, -target_len:]
sink_len = min(int(sink_size), target_len, k.shape&#91;1&#93;)
tail_len = target_len - sink_len
sink_k = k&#91;:, :sink_len&#93;
sink_v = v&#91;:, :sink_len&#93;
if tail_len &lt;= 0:
    return sink_k, sink_v

tail_k = k&#91;:, sink_len:&#93;&#91;:, -tail_len:&#93;
tail_v = v&#91;:, sink_len:&#93;&#91;:, -tail_len:&#93;
return torch.cat(&#91;sink_k, tail_k&#93;, dim=1), torch.cat(&#91;sink_v, tail_v&#93;, dim=1)</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.draw_rounded_rectangle

draw_rounded_rectangle(image: np.ndarray, top_left: tuple[int, int], bottom_right: tuple[int, int], color: tuple[int, int, int], radius: int = 10, alpha: float = 0.5) -> None
Source
def draw_rounded_rectangle(
    image: np.ndarray,
    top_left: tuple[int, int],
    bottom_right: tuple[int, int],
    color: tuple[int, int, int],
    radius: int = 10,
    alpha: float = 0.5,
) -> None:
    if not _require_cv2():
        return
overlay = image.copy()
x1, y1 = top_left
x2, y2 = bottom_right

cv2.rectangle(overlay, (x1 + radius, y1), (x2 - radius, y2), color, -1)
cv2.rectangle(overlay, (x1, y1 + radius), (x2, y2 - radius), color, -1)
cv2.ellipse(overlay, (x1 + radius, y1 + radius), (radius, radius), 180, 0, 90, color, -1)
cv2.ellipse(overlay, (x2 - radius, y1 + radius), (radius, radius), 270, 0, 90, color, -1)
cv2.ellipse(overlay, (x1 + radius, y2 - radius), (radius, radius), 90, 0, 90, color, -1)
cv2.ellipse(overlay, (x2 - radius, y2 - radius), (radius, radius), 0, 0, 90, color, -1)
cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0, image)</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.draw_keys_on_frame

draw_keys_on_frame(frame: np.ndarray, keys: dict[str, bool], key_size: tuple[int, int] = (30, 30), top_margin: int = 15) -> None
Source
def draw_keys_on_frame(
        frame: np.ndarray,
        keys: dict[str, bool],
        key_size: tuple[int, int] = (30, 30),
        top_margin: int = 15,
) -> None:
    if not _require_cv2():
        return
left_margin = 15
gap = 3
key_positions = &#123;
    &quot;W&quot;: (left_margin + key_size&#91;0&#93; + gap, top_margin),
    &quot;A&quot;: (left_margin, top_margin + key_size&#91;1&#93; + gap),
    &quot;S&quot;: (left_margin + key_size&#91;0&#93; + gap, top_margin + key_size&#91;1&#93; + gap),
    &quot;D&quot;: (
        left_margin + (key_size&#91;0&#93; + gap) * 2,
        top_margin + key_size&#91;1&#93; + gap,
    ),
&#125;

for key, (x, y) in key_positions.items():
    pressed = keys.get(key, False)
    color = (0, 255, 0) if pressed else (200, 200, 200)
    alpha = 0.8 if pressed else 0.5
    draw_rounded_rectangle(
        frame,
        (x, y),
        (x + key_size&#91;0&#93;, y + key_size&#91;1&#93;),
        color,
        radius=5,
        alpha=alpha,
    )
    text_size = cv2.getTextSize(key, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)&#91;0&#93;
    text_x = x + (key_size&#91;0&#93; - text_size&#91;0&#93;) // 2
    text_y = y + (key_size&#91;1&#93; + text_size&#91;1&#93;) // 2
    cv2.putText(
        frame,
        key,
        (text_x, text_y),
        cv2.FONT_HERSHEY_SIMPLEX,
        0.5,
        (0, 0, 0),
        1,
    )</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.draw_mouse_on_frame

draw_mouse_on_frame(frame: np.ndarray, yaw: float, pitch: float, top_margin: int = 15) -> None
Source
def draw_mouse_on_frame(
    frame: np.ndarray,
    yaw: float,
    pitch: float,
    top_margin: int = 15,
) -> None:
    if not _require_cv2():
        return
_, width, _ = frame.shape
right_margin = 15
crosshair_radius = 25
crosshair_x = width - right_margin - crosshair_radius
crosshair_y = top_margin + crosshair_radius

dx = int(yaw * crosshair_radius * 8)
dy = int(-pitch * crosshair_radius * 8)
max_arrow = crosshair_radius - 5
dx = max(-max_arrow, min(max_arrow, dx))
dy = max(-max_arrow, min(max_arrow, dy))

cv2.circle(frame, (crosshair_x, crosshair_y), crosshair_radius, (50, 50, 50), -1)
cv2.circle(frame, (crosshair_x, crosshair_y), crosshair_radius, (200, 200, 200), 1)
cv2.line(
    frame,
    (crosshair_x - crosshair_radius + 5, crosshair_y),
    (crosshair_x + crosshair_radius - 5, crosshair_y),
    (100, 100, 100),
    1,
)
cv2.line(
    frame,
    (crosshair_x, crosshair_y - crosshair_radius + 5),
    (crosshair_x, crosshair_y + crosshair_radius - 5),
    (100, 100, 100),
    1,
)

if abs(dx) &gt; 1 or abs(dy) &gt; 1:
    cv2.arrowedLine(
        frame,
        (crosshair_x, crosshair_y),
        (crosshair_x + dx, crosshair_y + dy),
        (0, 255, 0),
        2,
        tipLength=0.3,
    )</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.overlay_validation_actions_on_frames

overlay_validation_actions_on_frames(frames: list[np.ndarray], keyboard_cond: np.ndarray | torch.Tensor | None = None, mouse_cond: np.ndarray | torch.Tensor | None = None) -> list[np.ndarray]
Source
def overlay_validation_actions_on_frames(
    frames: list[np.ndarray],
    keyboard_cond: np.ndarray | torch.Tensor | None = None,
    mouse_cond: np.ndarray | torch.Tensor | None = None,
) -> list[np.ndarray]:
    if (keyboard_cond is None and mouse_cond is None) or not _require_cv2():
        return frames
if keyboard_cond is not None and torch.is_tensor(keyboard_cond):
    keyboard_cond = keyboard_cond.detach().cpu().float().numpy()
if mouse_cond is not None and torch.is_tensor(mouse_cond):
    mouse_cond = mouse_cond.detach().cpu().float().numpy()

if keyboard_cond is not None:
    keyboard_cond = np.asarray(keyboard_cond, dtype=np.float32)
    if keyboard_cond.ndim == 3 and keyboard_cond.shape&#91;0&#93; == 1:
        keyboard_cond = keyboard_cond&#91;0&#93;
if mouse_cond is not None:
    mouse_cond = np.asarray(mouse_cond, dtype=np.float32)
    if mouse_cond.ndim == 3 and mouse_cond.shape&#91;0&#93; == 1:
        mouse_cond = mouse_cond&#91;0&#93;

processed_frames: list&#91;np.ndarray&#93; = &#91;&#93;
for frame_idx, frame in enumerate(frames):
    frame = np.ascontiguousarray(frame.copy())
    if keyboard_cond is not None and frame_idx &lt; len(keyboard_cond):
        draw_keys_on_frame(
            frame,
            _matrixgame2_overlay_keys_from_keyboard(keyboard_cond&#91;frame_idx&#93;),
        )
    if mouse_cond is not None and frame_idx &lt; len(mouse_cond):
        # MG action convention: mouse&#91;0&#93;=pitch, mouse&#91;1&#93;=yaw.
        pitch = float(mouse_cond&#91;frame_idx, 0&#93;)
        yaw = float(mouse_cond&#91;frame_idx, 1&#93;)
        draw_mouse_on_frame(frame, yaw=yaw, pitch=pitch)
    processed_frames.append(frame)

return processed_frames</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.scale_keyboard_condition

scale_keyboard_condition(keyboard_condition: torch.Tensor, scale: float) -> torch.Tensor
Source
def scale_keyboard_condition(
    keyboard_condition: torch.Tensor,
    scale: float,
) -> torch.Tensor:
    if float(scale) == 1.0:
        return keyboard_condition
    return keyboard_condition * float(scale)

fastvideo.models.dits.matrixgame2.utils.expand_action_to_frames

expand_action_to_frames(action: dict, num_frames: int) -> tuple[torch.Tensor, torch.Tensor]
Source
def expand_action_to_frames(action: dict, num_frames: int) -> tuple[torch.Tensor, torch.Tensor]:
    result = {}
    for key, tensor in action.items():
        if tensor is not None:
            # Expand to [num_frames, D] then unsqueeze to [1, num_frames, D]
            result[key] = tensor.unsqueeze(0).repeat(num_frames, 1).unsqueeze(0)
        else:
            result[key] = None
if &quot;mouse&quot; not in result or result&#91;&quot;mouse&quot;&#93; is None:
    # keyboard device if available, otherwise default
    device = result.get(&quot;keyboard&quot;, torch.tensor(
        &#91;&#93;)).device if result.get(&quot;keyboard&quot;) is not None else get_local_torch_device()
    result&#91;&quot;mouse&quot;&#93; = torch.zeros(1, num_frames, 2, device=device)

return result&#91;&quot;keyboard&quot;&#93;, result&#91;&quot;mouse&quot;&#93;</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.get_current_action

get_current_action(mode = 'universal')
Source
def get_current_action(mode="universal"):
CAM_VALUE = 0.1
if mode == &#x27;universal&#x27;:
    logger.info(&quot;&quot;)
    logger.info(&#x27;-&#x27; * 30)
    logger.info(&quot;PRESS &#91;I, K, J, L, U&#93; FOR CAMERA TRANSFORM\n (I: up, K: down, J: left, L: right, U: no move)&quot;)
    logger.info(&quot;PRESS &#91;W, S, A, D, Q&#93; FOR MOVEMENT\n (W: forward, S: back, A: left, D: right, Q: no move)&quot;)
    logger.info(&#x27;-&#x27; * 30)
    CAMERA_VALUE_MAP = &#123;
        &quot;i&quot;: &#91;CAM_VALUE, 0&#93;,
        &quot;k&quot;: &#91;-CAM_VALUE, 0&#93;,
        &quot;j&quot;: &#91;0, -CAM_VALUE&#93;,
        &quot;l&quot;: &#91;0, CAM_VALUE&#93;,
        &quot;u&quot;: &#91;0, 0&#93;
    &#125;
    KEYBOARD_IDX = &#123;&quot;w&quot;: &#91;1, 0, 0, 0&#93;, &quot;s&quot;: &#91;0, 1, 0, 0&#93;, &quot;a&quot;: &#91;0, 0, 1, 0&#93;, &quot;d&quot;: &#91;0, 0, 0, 1&#93;, &quot;q&quot;: &#91;0, 0, 0, 0&#93;&#125;
    flag = 0
    while flag != 1:
        try:
            idx_mouse = input(&#x27;Please input the mouse action (e.g. `U`):\n&#x27;).strip().lower()
            idx_keyboard = input(&#x27;Please input the keyboard action (e.g. `W`):\n&#x27;).strip().lower()
            if idx_mouse in CAMERA_VALUE_MAP and idx_keyboard in KEYBOARD_IDX:
                flag = 1
        except Exception:
            pass
    mouse_cond = torch.tensor(CAMERA_VALUE_MAP&#91;idx_mouse&#93;).cuda()
    keyboard_cond = torch.tensor(KEYBOARD_IDX&#91;idx_keyboard&#93;).cuda()
elif mode == &#x27;gta_drive&#x27;:
    logger.info(&quot;&quot;)
    logger.info(&#x27;-&#x27; * 30)
    logger.info(&quot;PRESS &#91;W, S, A, D, Q&#93; FOR MOVEMENT\n (W: forward, S: back, A: left, D: right, Q: no move)&quot;)
    logger.info(&#x27;-&#x27; * 30)
    CAMERA_VALUE_MAP = &#123;&quot;a&quot;: &#91;0, -CAM_VALUE&#93;, &quot;d&quot;: &#91;0, CAM_VALUE&#93;, &quot;q&quot;: &#91;0, 0&#93;&#125;
    KEYBOARD_IDX = &#123;&quot;w&quot;: &#91;1, 0&#93;, &quot;s&quot;: &#91;0, 1&#93;, &quot;q&quot;: &#91;0, 0&#93;&#125;
    flag = 0
    while flag != 1:
        try:
            indexes = input(
                &#x27;Please input the actions (split with ` `):\n(e.g. `W` for forward, `W A` for forward and left)\n&#x27;
            ).strip().lower().split(&#x27; &#x27;)
            idx_mouse = &#91;&#93;
            idx_keyboard = &#91;&#93;
            for i in indexes:
                if i in CAMERA_VALUE_MAP.keys():
                    idx_mouse += &#91;i&#93;
                elif i in KEYBOARD_IDX.keys():
                    idx_keyboard += &#91;i&#93;
            if len(idx_mouse) == 0:
                idx_mouse += &#91;&#x27;q&#x27;&#93;
            if len(idx_keyboard) == 0:
                idx_keyboard += &#91;&#x27;q&#x27;&#93;
            assert idx_mouse in &#91;&#91;&#x27;a&#x27;&#93;, &#91;&#x27;d&#x27;&#93;, &#91;&#x27;q&#x27;&#93;&#93; and idx_keyboard in &#91;&#91;&#x27;q&#x27;&#93;, &#91;&#x27;w&#x27;&#93;, &#91;&#x27;s&#x27;&#93;&#93;
            flag = 1
        except Exception:
            pass
    mouse_cond = torch.tensor(CAMERA_VALUE_MAP&#91;idx_mouse&#91;0&#93;&#93;).cuda()
    keyboard_cond = torch.tensor(KEYBOARD_IDX&#91;idx_keyboard&#91;0&#93;&#93;).cuda()
elif mode == &#x27;templerun&#x27;:
    logger.info(&quot;&quot;)
    logger.info(&#x27;-&#x27; * 30)
    logger.info(
        &quot;PRESS &#91;W, S, A, D, Z, C, Q&#93; FOR ACTIONS\n (W: jump, S: slide, A: left side, D: right side, Z: turn left, C: turn right, Q: no move)&quot;
    )
    logger.info(&#x27;-&#x27; * 30)
    KEYBOARD_IDX = &#123;
        &quot;w&quot;: &#91;0, 1, 0, 0, 0, 0, 0&#93;,
        &quot;s&quot;: &#91;0, 0, 1, 0, 0, 0, 0&#93;,
        &quot;a&quot;: &#91;0, 0, 0, 0, 0, 1, 0&#93;,
        &quot;d&quot;: &#91;0, 0, 0, 0, 0, 0, 1&#93;,
        &quot;z&quot;: &#91;0, 0, 0, 1, 0, 0, 0&#93;,
        &quot;c&quot;: &#91;0, 0, 0, 0, 1, 0, 0&#93;,
        &quot;q&quot;: &#91;1, 0, 0, 0, 0, 0, 0&#93;
    &#125;
    flag = 0
    while flag != 1:
        try:
            idx_keyboard = input(
                &#x27;Please input the action: \n(e.g. `W` for forward, `Z` for turning left)\n&#x27;).strip().lower()
            if idx_keyboard in KEYBOARD_IDX.keys():
                flag = 1
        except Exception:
            pass
    keyboard_cond = torch.tensor(KEYBOARD_IDX&#91;idx_keyboard&#93;).cuda()

if mode != &#x27;templerun&#x27;:
    return &#123;&quot;mouse&quot;: mouse_cond, &quot;keyboard&quot;: keyboard_cond&#125;
return &#123;&quot;keyboard&quot;: keyboard_cond&#125;</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.get_current_action_async

get_current_action_async(mode = 'universal')
Source
async def get_current_action_async(mode="universal"):
    return await asyncio.to_thread(get_current_action, mode)

fastvideo.models.dits.matrixgame2.utils.load_initial_image

load_initial_image(image_path: str = None) -> Image.Image
Source
def load_initial_image(image_path: str = None) -> Image.Image:
    if image_path and os.path.exists(image_path):
        return Image.open(image_path).convert("RGB")
    logger.warning("No image provided, creating placeholder...")
    return Image.new("RGB", (640, 352), (128, 128, 128))

fastvideo.models.dits.matrixgame2.utils.create_action_presets

create_action_presets(num_frames: int, keyboard_dim: int = 4, seed: int = None)
Source
def create_action_presets(num_frames: int, keyboard_dim: int = 4, seed: int = None):
    if keyboard_dim not in (2, 4, 6, 7):
        raise ValueError(f"keyboard_dim must be 2, 4, 6, or 7, got {keyboard_dim}")
    if num_frames % 4 != 1:
        raise ValueError("Matrix-Game conditioning expects num_frames to be 4k+1.")
# Set seed for reproducibility if provided
if seed is not None:
    random.seed(seed)

num_samples_per_action = 4

# Define actions based on keyboard_dim
if keyboard_dim == 4:
    # Universal model: W, S, A, D
    actions_single_action = &#91;&quot;forward&quot;, &quot;left&quot;, &quot;right&quot;&#93;
    actions_double_action = &#91;&quot;forward_left&quot;, &quot;forward_right&quot;&#93;
    actions_single_camera = &#91;&quot;camera_l&quot;, &quot;camera_r&quot;&#93;
    keyboard_idx = &#123;&quot;forward&quot;: 0, &quot;back&quot;: 1, &quot;left&quot;: 2, &quot;right&quot;: 3&#125;
elif keyboard_dim == 2:
    # GTA model: W, S only (steering via mouse)
    actions_single_action = &#91;&quot;forward&quot;, &quot;back&quot;&#93;
    actions_double_action = &#91;&#93;
    actions_single_camera = &#91;&quot;camera_l&quot;, &quot;camera_r&quot;&#93;
    keyboard_idx = &#123;&quot;forward&quot;: 0, &quot;back&quot;: 1&#125;
elif keyboard_dim == 6:
    actions_single_action = &#91;&quot;forward&quot;, &quot;back&quot;, &quot;left&quot;, &quot;right&quot;&#93;
    actions_double_action = &#91;&quot;forward_left&quot;, &quot;forward_right&quot;&#93;
    actions_single_camera = &#91;&quot;camera_l&quot;, &quot;camera_r&quot;&#93;
    keyboard_idx = &#123;&quot;forward&quot;: 0, &quot;back&quot;: 1, &quot;left&quot;: 2, &quot;right&quot;: 3, &quot;t1&quot;: 4, &quot;t2&quot;: 5&#125;
else:  # keyboard_dim == 7
    # Temple Run model: still, w, s, left, right, a, d (no mouse)
    actions_single_action = &#91;&quot;forward&quot;, &quot;back&quot;, &quot;left&quot;, &quot;right&quot;&#93;
    actions_double_action = &#91;&#93;
    actions_single_camera = &#91;&#93;  # No mouse for Temple Run
    keyboard_idx = &#123;&quot;still&quot;: 0, &quot;forward&quot;: 1, &quot;back&quot;: 2, &quot;left&quot;: 3, &quot;right&quot;: 4, &quot;a&quot;: 5, &quot;d&quot;: 6&#125;

actions_to_test = (actions_double_action * 5 + actions_single_camera * 5 + actions_single_action * 5)
for action in (actions_single_action + actions_double_action):
    for camera in actions_single_camera:
        actions_to_test.append(f&quot;&#123;action&#125;_&#123;camera&#125;&quot;)

# Ensure we have at least some actions
if not actions_to_test:
    actions_to_test = actions_single_action * 5

base_action = actions_single_action + actions_single_camera
cam_value = 0.1
camera_value_map = &#123;
    &quot;camera_up&quot;: &#91;cam_value, 0&#93;,
    &quot;camera_down&quot;: &#91;-cam_value, 0&#93;,
    &quot;camera_l&quot;: &#91;0, -cam_value&#93;,
    &quot;camera_r&quot;: &#91;0, cam_value&#93;,
    &quot;camera_ur&quot;: &#91;cam_value, cam_value&#93;,
    &quot;camera_ul&quot;: &#91;cam_value, -cam_value&#93;,
    &quot;camera_dr&quot;: &#91;-cam_value, cam_value&#93;,
    &quot;camera_dl&quot;: &#91;-cam_value, -cam_value&#93;,
&#125;

data = &#91;&#93;
for action_name in actions_to_test:
    keyboard_condition = torch.zeros((num_samples_per_action, keyboard_dim))
    mouse_condition = torch.zeros((num_samples_per_action, 2))

    for sub_act in base_action:
        if sub_act not in action_name:
            continue
        if sub_act in camera_value_map:
            mouse_condition = torch.tensor(
                &#91;camera_value_map&#91;sub_act&#93; for _ in range(num_samples_per_action)&#93;,
                dtype=mouse_condition.dtype,
            )
        elif sub_act in keyboard_idx:
            keyboard_condition&#91;:, keyboard_idx&#91;sub_act&#93;&#93; = 1

    data.append(&#123;
        &quot;keyboard_condition&quot;: keyboard_condition,
        &quot;mouse_condition&quot;: mouse_condition,
    &#125;)

keyboard_condition = torch.zeros((num_frames, keyboard_dim))
mouse_condition = torch.zeros((num_frames, 2))
current_frame = 0
selections = &#91;12&#93;

while current_frame &lt; num_frames:
    rd_frame = selections&#91;random.randint(0, len(selections) - 1)&#93;
    entry = data&#91;random.randint(0, len(data) - 1)&#93;
    key_seq = entry&#91;&quot;keyboard_condition&quot;&#93;
    mouse_seq = entry&#91;&quot;mouse_condition&quot;&#93;

    if current_frame == 0:
        keyboard_condition&#91;:1&#93; = key_seq&#91;:1&#93;
        mouse_condition&#91;:1&#93; = mouse_seq&#91;:1&#93;
        current_frame = 1
    else:
        rd_frame = min(rd_frame, num_frames - current_frame)
        repeat_time = rd_frame // 4
        keyboard_condition&#91;current_frame:current_frame + rd_frame&#93; = key_seq.repeat(repeat_time, 1)
        mouse_condition&#91;current_frame:current_frame + rd_frame&#93; = mouse_seq.repeat(repeat_time, 1)
        current_frame += rd_frame

return &#123;&quot;keyboard&quot;: keyboard_condition, &quot;mouse&quot;: mouse_condition&#125;</code></pre></details>

fastvideo.models.dits.matrixgame2.utils.parse_config

parse_config(config, mode = 'universal')
Source
def parse_config(config, mode="universal"):
    assert mode in ['universal', 'gta_drive', 'templerun']
    key_data = {}
    mouse_data = {}
    if mode != 'templerun':
        key, mouse = config
    else:
        key = config
for i in range(len(key)):
    if mode == &#x27;templerun&#x27;:
        still, w, s, left, right, a, d = key&#91;i&#93;
    elif mode == &#x27;universal&#x27;:
        w, s, a, d = key&#91;i&#93;
    else:
        w, s, a, d = key&#91;i&#93;&#91;0&#93;, key&#91;i&#93;&#91;1&#93;, mouse&#91;i&#93;&#91;1&#93; &lt; 0, mouse&#91;i&#93;&#91;1&#93; &gt; 0
    if mode == &#x27;universal&#x27;:
        mouse_y, mouse_x = mouse&#91;i&#93;
        mouse_y = -1 * mouse_y

    key_data&#91;i&#93; = &#123;&quot;W&quot;: bool(w), &quot;A&quot;: bool(a), &quot;S&quot;: bool(s), &quot;D&quot;: bool(d)&#125;
    if mode == &#x27;templerun&#x27;:
        key_data&#91;i&#93;.update(&#123;&quot;left&quot;: bool(left), &quot;right&quot;: bool(right)&#125;)

    if mode == &#x27;universal&#x27;:
        if i == 0:
            mouse_data&#91;i&#93; = (320, 352 // 2)
        else:
            global_scale_factor = 0.1
            mouse_scale_x = 15 * global_scale_factor
            mouse_scale_y = 15 * 4 * global_scale_factor
            mouse_data&#91;i&#93; = (
                mouse_data&#91;i - 1&#93;&#91;0&#93; + mouse_x * mouse_scale_x,
                mouse_data&#91;i - 1&#93;&#91;1&#93; + mouse_y * mouse_scale_y,
            )
return key_data, mouse_data</code></pre></details>

Was this page helpful?