Skip to content

Keyboard (and mouse) input silently dropped on Windows ARM64 #614

@andreban

Description

@andreban

all keyboard and mouse events are silently dropped. The application window opens and renders correctly, but is_key_down, is_key_pressed, and all other input queries always return false/no events.

The same binary compiled for x86_64-pc-windows-msvc works correctly on x86-64 Windows hardware.


Root Cause

In src/native/windows.rs, the run() function stores a pointer to WindowsDisplay in the window's user data slot via SetWindowLongPtrA. This pointer is later retrieved by the window procedure (win32_wndproc) to dispatch events. The storage call is guarded by architecture #[cfg] attributes, but aarch64 is not covered:

// src/native/windows.rs — run() function, ~line 945

#[cfg(target_arch = "x86_64")]
SetWindowLongPtrA(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);
#[cfg(target_arch = "x86")]
SetWindowLong(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);

On aarch64, neither cfg block is compiled, so SetWindowLongPtrA is never called. The user data slot remains 0.

The window procedure retrieves the pointer using target_pointer_width = "64" (which correctly covers aarch64), but always reads 0:

// src/native/windows.rs — win32_wndproc()

#[cfg(target_pointer_width = "64")]
{
    display_ptr = GetWindowLongPtrA(hwnd, GWLP_USERDATA)  // always returns 0 on aarch64
}

if display_ptr == 0 {
    return DefWindowProcW(hwnd, umsg, wparam, lparam);  // every event is dropped here
}

Because display_ptr is always 0, win32_wndproc returns early for every window message, including WM_KEYDOWN, WM_KEYUP, WM_MOUSEMOVE, etc. No events ever reach the application.

The same bug exists in the set_fullscreen method (~line 164), which has the identical architecture gap:

#[cfg(target_arch = "x86_64")]
SetWindowLongPtrA(self.wnd, GWL_STYLE, win_style as _);
#[cfg(target_arch = "x86")]
SetWindowLong(self.wnd, GWL_STYLE, win_style as _);
// aarch64 → neither branch compiles → window style is never updated

Fix

Add aarch64 to the x86_64 branch in both locations, since ARM64 Windows is a 64-bit platform and uses SetWindowLongPtrA (not the 32-bit SetWindowLong):

run() function:

// Before
#[cfg(target_arch = "x86_64")]
SetWindowLongPtrA(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);
#[cfg(target_arch = "x86")]
SetWindowLong(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);

// After
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
SetWindowLongPtrA(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);
#[cfg(target_arch = "x86")]
SetWindowLong(wnd, GWLP_USERDATA, &mut display as *mut _ as isize);

set_fullscreen() method:

// Before
#[cfg(target_arch = "x86_64")]
SetWindowLongPtrA(self.wnd, GWL_STYLE, win_style as _);
#[cfg(target_arch = "x86")]
SetWindowLong(self.wnd, GWL_STYLE, win_style as _);

// After
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
SetWindowLongPtrA(self.wnd, GWL_STYLE, win_style as _);
#[cfg(target_arch = "x86")]
SetWindowLong(self.wnd, GWL_STYLE, win_style as _);

Reproduction

  1. Any macroquad/miniquad application that reads keyboard or mouse input
  2. Compile for aarch64-pc-windows-msvc
  3. Run on a Windows ARM64 machine (e.g. Snapdragon X, Surface Pro X)
  4. Observe: window opens, renders, but all input is ignored

Not reproducible when the same code is compiled for x86_64-pc-windows-msvc and run on x86-64 Windows.


Notes

  • The win32_wndproc retrieval already uses target_pointer_width = "64" (correct for aarch64), so only the storage side needs fixing.
  • Alternatively, both sites could be simplified to use target_pointer_width consistently to future-proof against other 64-bit Windows targets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions