Skip to content

Commit

Permalink
Fix quick shift key presses getting ignored on dinput driver (#17185)
Browse files Browse the repository at this point in the history
Because shift keys were ignored in the event message  and only issued during polling, a quick key press and release between polling would get ignored.
This change also fixes left alt up key events getting issued (and sent to the core) twice.
  • Loading branch information
schellingb authored Nov 14, 2024
1 parent 6135771 commit c039576
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 82 deletions.
15 changes: 9 additions & 6 deletions gfx/common/win32_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1354,15 +1354,18 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd,
if (extended)
keysym |= 0x80;

keycode = input_keymaps_translate_keysym_to_rk(keysym);
switch (keycode)
/* tell the driver about shift and alt key events */
if (keysym == 0x2A/*DIK_LSHIFT*/ || keysym == 0x36/*DIK_RSHIFT*/
|| keysym == 0x38/*DIK_LMENU*/ || keysym == 0xB8/*DIK_RMENU*/)
{
/* L+R Shift handling done in dinput_poll */
case RETROK_LSHIFT:
case RETROK_RSHIFT:
return 0;
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
if (input_data && dinput_handle_message(input_data,
message, wparam, lparam))
return 0; /* key up already handled by the driver */
}

keycode = input_keymaps_translate_keysym_to_rk(keysym);

if (GetKeyState(VK_SHIFT) & 0x80)
mod |= RETROKMOD_SHIFT;
if (GetKeyState(VK_CONTROL) & 0x80)
Expand Down
145 changes: 69 additions & 76 deletions input/drivers/dinput.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,17 @@ enum dinput_input_flags
DINP_FLAG_SHIFT_L = (1 << 0),
DINP_FLAG_SHIFT_R = (1 << 1),
DINP_FLAG_ALT_L = (1 << 2),
DINP_FLAG_DBCLK_ON_TITLEBAR = (1 << 3),
DINP_FLAG_MOUSE_L_BTN = (1 << 4),
DINP_FLAG_MOUSE_R_BTN = (1 << 5),
DINP_FLAG_MOUSE_M_BTN = (1 << 6),
DINP_FLAG_MOUSE_B4_BTN = (1 << 7),
DINP_FLAG_MOUSE_B5_BTN = (1 << 8),
DINP_FLAG_MOUSE_WU_BTN = (1 << 9),
DINP_FLAG_MOUSE_WD_BTN = (1 << 10),
DINP_FLAG_MOUSE_HWU_BTN = (1 << 11),
DINP_FLAG_MOUSE_HWD_BTN = (1 << 12)
DINP_FLAG_ALT_R = (1 << 3),
DINP_FLAG_DBCLK_ON_TITLEBAR = (1 << 4),
DINP_FLAG_MOUSE_L_BTN = (1 << 5),
DINP_FLAG_MOUSE_R_BTN = (1 << 6),
DINP_FLAG_MOUSE_M_BTN = (1 << 7),
DINP_FLAG_MOUSE_B4_BTN = (1 << 8),
DINP_FLAG_MOUSE_B5_BTN = (1 << 9),
DINP_FLAG_MOUSE_WU_BTN = (1 << 10),
DINP_FLAG_MOUSE_WD_BTN = (1 << 11),
DINP_FLAG_MOUSE_HWU_BTN = (1 << 12),
DINP_FLAG_MOUSE_HWD_BTN = (1 << 13)
};

struct dinput_input
Expand Down Expand Up @@ -219,67 +220,6 @@ static uint16_t dinput_get_active_keyboard_mods()
return mod;
}

static void dinput_keyboard_mods(struct dinput_input *di, int mod)
{
switch (mod)
{
case RETROKMOD_SHIFT:
{
unsigned vk_shift_l = GetAsyncKeyState(VK_LSHIFT) >> 1;
unsigned vk_shift_r = GetAsyncKeyState(VK_RSHIFT) >> 1;

if ( ( vk_shift_l && (!(di->flags & DINP_FLAG_SHIFT_L)))
|| (!vk_shift_l && (di->flags & DINP_FLAG_SHIFT_L)))
{
input_keyboard_event(vk_shift_l, RETROK_LSHIFT,
0, dinput_get_active_keyboard_mods() | RETROKMOD_SHIFT,
RETRO_DEVICE_KEYBOARD);
if (di->flags & DINP_FLAG_SHIFT_L)
di->flags &= ~DINP_FLAG_SHIFT_L;
else
di->flags |= DINP_FLAG_SHIFT_L;
}

if ( ( vk_shift_r && (!(di->flags & DINP_FLAG_SHIFT_R)))
|| (!vk_shift_r && (di->flags & DINP_FLAG_SHIFT_R)))
{
input_keyboard_event(vk_shift_r, RETROK_RSHIFT,
0, dinput_get_active_keyboard_mods() | RETROKMOD_SHIFT,
RETRO_DEVICE_KEYBOARD);
if (di->flags & DINP_FLAG_SHIFT_R)
di->flags &= ~DINP_FLAG_SHIFT_R;
else
di->flags |= DINP_FLAG_SHIFT_R;
}
}
break;

case RETROKMOD_ALT:
{
unsigned vk_alt_l = GetAsyncKeyState(VK_LMENU) >> 1;

if (vk_alt_l && (!(di->flags & DINP_FLAG_ALT_L)))
{
if (di->flags & DINP_FLAG_ALT_L)
di->flags &= ~DINP_FLAG_ALT_L;
else
di->flags |= DINP_FLAG_ALT_L;
}
else if (!vk_alt_l && (di->flags & DINP_FLAG_ALT_L))
{
input_keyboard_event(vk_alt_l, RETROK_LALT,
0, dinput_get_active_keyboard_mods() | RETROKMOD_ALT,
RETRO_DEVICE_KEYBOARD);
if (di->flags & DINP_FLAG_ALT_L)
di->flags &= ~DINP_FLAG_ALT_L;
else
di->flags |= DINP_FLAG_ALT_L;
}
}
break;
}
}

static void dinput_poll(void *data)
{
struct dinput_input *di = (struct dinput_input*)data;
Expand Down Expand Up @@ -312,15 +252,39 @@ static void dinput_poll(void *data)
}
else
{
/* Shifts only when window focused */
dinput_keyboard_mods(di, RETROKMOD_SHIFT);

/* Ignore 'unknown/undefined' key */
di->state[RETROK_UNKNOWN] = 0;
}

/* Left alt keyup when unfocused, to prevent alt-tab sticky */
dinput_keyboard_mods(di, RETROKMOD_ALT);
/* If both shift keys are pressed simultaneously, the OS will not issue
* a WM_KEYUP for the first one. That up event will be issued here. */
if ((di->flags & DINP_FLAG_SHIFT_L) && !(GetAsyncKeyState(VK_LSHIFT) >> 1))
{
input_keyboard_event(false, RETROK_LSHIFT, 0,
dinput_get_active_keyboard_mods(), RETRO_DEVICE_KEYBOARD);
di->flags &= ~DINP_FLAG_SHIFT_L;
}
if ((di->flags & DINP_FLAG_SHIFT_R) && !(GetAsyncKeyState(VK_RSHIFT) >> 1))
{
input_keyboard_event(false, RETROK_RSHIFT, 0,
dinput_get_active_keyboard_mods(), RETRO_DEVICE_KEYBOARD);
di->flags &= ~DINP_FLAG_SHIFT_R;
}

/* When using alt-tab, the alt key won't get a WM_KEYUP message from the
* OS. Instead we issue it here when ALT isn't pressed down anymore. */
if ((di->flags & DINP_FLAG_ALT_L) && !(GetAsyncKeyState(VK_LMENU) >> 1))
{
input_keyboard_event(false, RETROK_LALT, 0,
dinput_get_active_keyboard_mods(), RETRO_DEVICE_KEYBOARD);
di->flags &= ~DINP_FLAG_ALT_L;
}
if ((di->flags & DINP_FLAG_ALT_R) && !(GetAsyncKeyState(VK_RMENU) >> 1))
{
input_keyboard_event(false, RETROK_RALT, 0,
dinput_get_active_keyboard_mods(), RETRO_DEVICE_KEYBOARD);
di->flags &= ~DINP_FLAG_ALT_R;
}
}

if (di->mouse)
Expand Down Expand Up @@ -1049,6 +1013,35 @@ bool dinput_handle_message(void *data,
if (((short) HIWORD(wParam))/120 < 0)
di->flags |= DINP_FLAG_MOUSE_HWD_BTN;
break;
case WM_KEYUP: /* Key released */
case WM_SYSKEYUP: /* Key released */
case WM_KEYDOWN: /* Key pressed */
case WM_SYSKEYDOWN: /* Key pressed */
{
unsigned keysym = (lParam >> 16) & 0xff;
bool extended = (lParam >> 24) & 0x1;
uint16_t flag = 0;

/* extended keys will map to dinput if the high bit is set */
if (extended)
keysym |= 0x80;

switch (keysym)
{
case DIK_LSHIFT: flag = DINP_FLAG_SHIFT_L; break;
case DIK_RSHIFT: flag = DINP_FLAG_SHIFT_R; break;
case DIK_LMENU: flag = DINP_FLAG_ALT_L; break;
case DIK_RMENU: flag = DINP_FLAG_ALT_R; break;
}

if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
di->flags |= flag;
else if (di->flags & flag)
di->flags &= ~flag;
else if (flag) /* key up already issued or down never happened */
return true;
}
break;
}

return false;
Expand Down

0 comments on commit c039576

Please sign in to comment.