Input untangled
Moderator: InsideQC Admins
7 posts
• Page 1 of 1
Input untangled
Quake's input code is a quantum entangled mess. I have no idea why I bother untangling the mess --- well it was probably rage against the machine.
The short versions goes like this:
The slight longer version is multiplatform involving ClipCursor and friends and other crapola I'm somewhat tired of reading at this point.. Quake's input code is truly terrible --- my only motivation was someone has to win and someone has to lose --- and although the battle is a Pyrrhic victory --- to do it right there has to be a loser to the battle and it's not gonna be me.
P.S: To clean up this mess I also had to rewrite all the co-conspirator code = all the video. Go figure --- it was easier to rewrite ALL OF IT, then clean it up. Seriously, the video code almost rivals the suck of the input code and that's saying something.
The short versions goes like this:
- Code: Select all
void IN_Think (in_think_type action)
{
switch (action)
{
case in_initialize:
Cmd_AddCommand ("force_centerview", Force_CenterView_f);
IN_Local_Keyboard_Startup (); // Stupid stickey keys
in_initialized = true;
break;
case in_startup:
if (!in_initialized)
IN_Think (in_initialize);
IN_Think (in_acquire_mouse);
IN_Think (in_acquire_keyboard);
break;
case in_acquire_mouse:
if (mouse_acquired == false)
{
IN_Local_Mouse_Clip_Cursor (window_rect); // GET New clip region + ClipCursor (&window_rect); + center_x
IN_Local_Acquire_Mouse (); // ShowCursor (FALSE); + SetCapture (wplat.mainwindow);
IN_Think (in_clear_mouse_movement_accum);
IN_Think (in_center_mouse_cursor);
}
mouse_acquired = true;
break;
case in_center_mouse_cursor:
IN_Local_Mouse_Cursor (window_center_x, window_center_y); //SetCursorPos (window_center_x, window_center_y);
break;
case in_update_mouse_region:
IN_Think (in_clear_mouse_accum);
IN_Local_Update_Mouse_Region (&mouseregion);
break;
case in_clear_mouse_movement_accum:
mouse_accum_x = mouse_accum_y = 0;
break;
case in_release_mouse_buttons:
Key_Release_Mouse_Buttons ();
break;
case in_unacquire_mouse:
IN_Think (in_release_mouse_buttons); // Fire -aliases
mouse_old_button_state = 0; // Now clear the buttons
IN_Think (in_clear_mouse_movement_accum); // Now clear the movement
if (mouse_acquired == false)
{
IN_Local_Release_Mouse (); // ClipCursor (NULL); ReleaseCapture (); ShowCursor (TRUE);
}
mouse_acquired = false;
break;
case in_unacquire_keyboard:
IN_Keyboard_Release_Keys (); // Key ups
IN_Local_Keyboard_Unacquire (); // Stupid Windows key
break;
case in_acquire_keyboard:
IN_Local_Keyboard_Acquire (); // Stupid Windows key
break;
case in_unacquire_all: // Lost focus
IN_Think (in_unacquire_mouse);
IN_Think (in_unacquire_keyboard); // Stupid windows key
break;
case in_acquire_all: // Got focus
IN_Think (in_acquire_keyboard); // Stupid windows key
IN_Think (in_acquire_mouse);
break;
case in_shutdown:
IN_Think (in_unaquire_all); // About same deal.
IN_Local_Keyboard_Restore (); // Stupid Stickey keys on Windows
break;
}
The slight longer version is multiplatform involving ClipCursor and friends and other crapola I'm somewhat tired of reading at this point.. Quake's input code is truly terrible --- my only motivation was someone has to win and someone has to lose --- and although the battle is a Pyrrhic victory --- to do it right there has to be a loser to the battle and it's not gonna be me.
P.S: To clean up this mess I also had to rewrite all the co-conspirator code = all the video. Go figure --- it was easier to rewrite ALL OF IT, then clean it up. Seriously, the video code almost rivals the suck of the input code and that's saying something.
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Re: Input untangled
I've found a lot of Quake's code to be considerably messy while working on OpenKatana and I agree sometimes it's easier to just rewrite all of it than to try cleaning it up. Despite the time it can take it seems there's usually more long-term benefits that way as you can then better document the code you write and it means you have to spend less time reading over the code to understand it which then in-turn obviously means you can make changes much more efficiently.
Just a shame it can sometimes take so much time and effort, but it's usually worth it... Usually
Just a shame it can sometimes take so much time and effort, but it's usually worth it... Usually
-

hogsy - Posts: 198
- Joined: Wed Aug 03, 2011 3:44 pm
- Location: UK
Re: Input untangled
I hope it becomes worth ithogsy wrote:it seems there's usually more long-term benefits ...
Just a shame it can sometimes take so much time and effort, but it's usually worth it... Usually
Revision 2: Far more streamlined than even the above + short. Modelled in part from MH's ideas of one place where input is handled.
- Code: Select all
#include "quakedef.h"
#define NUM_MOUSE_BUTTONS 5
#define MRECT_PRINT(_x) _x.left, _x.top, _x.right, _x.bottom, _x.center_x, _x.center_y
enum { GET_IT = 1, LOSE_IT = 2 };
keypair_t input_state_text [] =
{
KEYVALUE (input_none),
KEYVALUE (input_have_keyboard),
KEYVALUE (input_have_mouse_keyboard),
NULL, 0 }; // NULL termination
static inp_info_t inp;
static void Force_CenterView_f (void) { cl.viewangles[PITCH] = 0; }
static void IN_Info_f (void)
{
Con_Printf ("IN Info ...\n");
Con_Printf ("current_state: %s\n", Keypair_String (input_state_text, inp.current_state) );
Con_Printf ("initialized: %i\n", inp.initialized);
Con_Printf ("have_mouse: %i\n", inp.have_mouse);
Con_Printf ("have_keyboard: %i\n", inp.have_keyboard);
Con_Printf ("mouse_clip_screen_rect: (%i, %i)-(%i, %i) center: %i, %i\n", MRECT_PRINT(inp.mouse_clip_screen_rect) );
Con_Printf ("mouse_accum_x: %i\n", inp.mouse_accum_x);
Con_Printf ("mouse_accum_y: %i\n", inp.mouse_accum_y);
Con_Printf ("mouse_old_button_state: %i\n", inp.mouse_old_button_state);
}
void Input_Think (void)
{
input_state_t newstate = (inp.initialized && vid.ActiveApp && !vid.Minimized) ? input_have_keyboard : input_none;
// newstate upgrades from should have "keyboard" to should have "mouse"
// If the key_dest is game or we are binding keys in the menu
if (newstate == input_have_keyboard && key_dest == key_game || (key_dest == key_menu && m_keys_bind_grab) )
newstate = input_have_mouse_keyboard;
if (newstate != inp.current_state)
{ // New state.
char mouse_action = ( newstate == input_have_mouse_keyboard && inp.have_mouse == false) ? GET_IT : (( newstate != input_have_mouse_keyboard && inp.have_mouse == true) ? LOSE_IT : 0);
char keyboard_action = ( newstate != input_none && inp.have_keyboard == false) ? GET_IT : (( newstate == input_none && inp.have_keyboard == true) ? LOSE_IT : 0);
switch (mouse_action)
{
case GET_IT:
// Sticky keys, Window key disabled
IN_Local_Keyboard_Disable_Annoying_Keys (true);
inp.have_keyboard = true;
break;
case LOSE_IT:
// Key ups
Key_Release_Keys ();
#pragma message ("Note we still need our key ups when entering the console")
// Sticky keys, Window key reenabled
IN_Local_Keyboard_Disable_Annoying_Keys (false);
inp.have_keyboard = false;
break;
}
switch (mouse_action)
{
case GET_IT:
// Load window screen coords to mouse_clip_screen_rect
// And clip the mouse cursor to that area
IN_Local_Update_Mouse_Clip_Region (&inp.mouse_clip_screen_rect);
// Hide the mouse cursor and attach it
IN_Local_Capture_Mouse (true);
// Center the mouse on-screen
IN_Local_Mouse_Cursor_SetPos (inp.mouse_clip_screen_rect.center_x, inp.mouse_clip_screen_rect.center_y); //SetCursorPos (window_center_x, window_center_y);
// Clear movement accumulation
inp.mouse_accum_x = inp.mouse_accum_y = 0
;
inp.have_mouse = true;
break;
case LOSE_IT:
// Release mouse buttons so "-alias" get triggered
Key_Release_Mouse_Buttons ();
// Unclip the mouse
IN_Local_Unclip_Mouse_Movement ();
// Release the mouse and show the cursor
IN_Local_Capture_Mouse (false);
// Clear movement accumulation and buttons
inp.mouse_accum_x = inp.mouse_accum_y = inp.mouse_old_button_state = 0;
inp.have_mouse = false;
break;
}
inp.current_state = newstate;
}
// End of function
}
void Input_Mouse_Button_Event (int mstate)
{
if (inp.have_mouse /*|| (key_dest == key_menu && m_keys_bind_grab)*/ )
{ // perform button actions
int i;
for (i = 0 ; i < NUM_MOUSE_BUTTONS ; i ++)
{
int button_bit = (1 << i);
qboolean button_pressed = (mstate & button_bit) && !(inp.mouse_old_button_state & button_bit);
qboolean button_released = !(mstate & button_bit) && (inp.mouse_old_button_state & button_bit);
if (button_pressed || button_released)
Key_Event (K_MOUSE1 + i, button_pressed ? true : false);
}
inp.mouse_old_button_state = mstate;
}
}
void Input_Mouse_Accumulate (void)
{
int new_mouse_x, new_mouse_y;
#pragma message ("Need a clip region check here")
if (inp.have_mouse == false)
return;
IN_Local_Mouse_Cursor_GetPos (&new_mouse_x, &new_mouse_y); // GetCursorPos (¤t_pos);
inp.mouse_accum_x += new_mouse_x - inp.mouse_clip_screen_rect.center_x;
inp.mouse_accum_y += new_mouse_y - inp.mouse_clip_screen_rect.center_y;
// Re-center the mouse cursor
IN_Local_Mouse_Cursor_SetPos (inp.mouse_clip_screen_rect.center_x, inp.mouse_clip_screen_rect.center_y);
}
void Input_Mouse_Move (usercmd_t *cmd)
{
Input_Mouse_Accumulate ();
if (inp.mouse_accum_x || inp.mouse_accum_y)
{
int mouse_x = inp.mouse_accum_x *= sensitivity.value;
int mouse_y = inp.mouse_accum_y *= sensitivity.value;
// add mouse X/Y movement to cmd
if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
cmd->sidemove += m_side.value * mouse_x;
else cl.viewangles[YAW] -= m_yaw.value * mouse_x;
if (in_mlook.state & 1)
V_StopPitchDrift ();
if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
{
cl.viewangles[PITCH] += m_pitch.value * mouse_y;
cl.viewangles[PITCH] = CLAMP (cl_minpitch.value, cl.viewangles[PITCH], cl_maxpitch.value);
}
else
{
if ((in_strafe.state & 1) && cl.noclip_anglehack)
cmd->upmove -= m_forward.value * mouse_y;
else cmd->forwardmove -= m_forward.value * mouse_y;
}
inp.mouse_accum_x = inp.mouse_accum_y = 0;
}
}
void Input_Initialized (void)
{
Cmd_AddCommand ("in_info", IN_Info_f);
Cmd_AddCommand ("force_centerview", Force_CenterView_f);
inp.initialized = true;
}
void Input_Shutdown (void)
{
inp.initialized = false;
Input_Think (); // Will shut everything off
}
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Re: Input untangled
Final answer: Tested, debugged, short, only checks once per frame (like what MH did in DirectQ). All the IN_HideMouse stuff all over the source code is gone.
Nightmares -1.
Header look like:
in_win.c looks like:
Nightmares -1.
- Code: Select all
#include "quakedef.h"
typedef enum
{
input_none,
input_have_keyboard,
input_have_mouse_keyboard,
} input_state_t;
typedef struct
{
input_state_t current_state;
qboolean initialized, have_mouse, have_keyboard;
// Internals
mrect_t mouse_clip_screen_rect;
int mouse_accum_x, mouse_accum_y;
int mouse_old_button_state;
} inp_info_t;
#define NUM_MOUSE_BUTTONS 5
#define MRECT_PRINT(_x) _x.left, _x.top, _x.right, _x.bottom, _x.center_x, _x.center_y
enum { GET_IT = 1, LOSE_IT = 2 };
keypair_t input_state_text [] =
{
KEYVALUE (input_none),
KEYVALUE (input_have_keyboard),
KEYVALUE (input_have_mouse_keyboard),
NULL, 0 }; // NULL termination
static inp_info_t inp;
static void Force_CenterView_f (void) { cl.viewangles[PITCH] = 0; }
static void IN_Info_f (void)
{
Con_Printf ("IN Info ...\n");
Con_Printf ("current_state: %s\n", Keypair_String (input_state_text, inp.current_state) );
Con_Printf ("initialized: %i\n", inp.initialized);
Con_Printf ("have_mouse: %i\n", inp.have_mouse);
Con_Printf ("have_keyboard: %i\n", inp.have_keyboard);
Con_Printf ("mouse_clip_screen_rect: (%i, %i)-(%i, %i) center: %i, %i\n", MRECT_PRINT(inp.mouse_clip_screen_rect) );
Con_Printf ("mouse_accum_x: %i\n", inp.mouse_accum_x);
Con_Printf ("mouse_accum_y: %i\n", inp.mouse_accum_y);
Con_Printf ("mouse_old_button_state: %i\n", inp.mouse_old_button_state);
}
void Input_Think (void)
{
input_state_t newstate = (inp.initialized && vid.ActiveApp && !vid.Minimized && !vid.in_setmode) ? input_have_keyboard : input_none;
// newstate upgrades from should have "keyboard" to should have "mouse"
// If the key_dest is game or we are binding keys in the menu
if (newstate == input_have_keyboard && (key_dest == key_game || (key_dest == key_menu && m_keys_bind_grab)) )
newstate = input_have_mouse_keyboard;
// Con_Printf ("current_state: %s (init %i active %i mini %i)\n", Keypair_String (input_state_text, inp.current_state),
// inp.initialized, vid.ActiveApp, vid.Minimized);
if (newstate != inp.current_state)
{ // New state.
char mouse_action = ( newstate == input_have_mouse_keyboard && inp.have_mouse == false) ? GET_IT : (( newstate != input_have_mouse_keyboard && inp.have_mouse == true) ? LOSE_IT : 0);
char keyboard_action = ( newstate != input_none && inp.have_keyboard == false) ? GET_IT : (( newstate == input_none && inp.have_keyboard == true) ? LOSE_IT : 0);
// Con_Printf ("State change\n");
switch (keyboard_action)
{
case GET_IT:
// Sticky keys, Window key disabled
IN_Local_Keyboard_Disable_Annoying_Keys (true);
inp.have_keyboard = true;
break;
case LOSE_IT:
// Key ups
Key_Release_Keys ();
#pragma message ("Note we still need our key ups when entering the console")
// Sticky keys, Window key reenabled
IN_Local_Keyboard_Disable_Annoying_Keys (false);
inp.have_keyboard = false;
break;
}
switch (mouse_action)
{
case GET_IT:
// Load window screen coords to mouse_clip_screen_rect
// And clip the mouse cursor to that area
IN_Local_Update_Mouse_Clip_Region_Think (&inp.mouse_clip_screen_rect);
// Hide the mouse cursor and attach it
IN_Local_Capture_Mouse (true);
// Center the mouse on-screen
IN_Local_Mouse_Cursor_SetPos (inp.mouse_clip_screen_rect.center_x, inp.mouse_clip_screen_rect.center_y); //SetCursorPos (window_center_x, window_center_y);
// Clear movement accumulation
inp.mouse_accum_x = inp.mouse_accum_y = 0
;
inp.have_mouse = true;
break;
case LOSE_IT:
// Release mouse buttons so "-alias" get triggered. Even the keyboard keys.
// As if we lose the mouse, usually this is from entering the console.
// The exceptions to this are weird and uninteresting (like changing a mouse cvar via a bind)
Key_Release_Keys ();
// Release the mouse and show the cursor. Also unclips mouse.
IN_Local_Capture_Mouse (false);
// Clear movement accumulation and buttons
inp.mouse_accum_x = inp.mouse_accum_y = inp.mouse_old_button_state = 0;
inp.have_mouse = false;
break;
}
inp.current_state = newstate;
}
if (inp.have_mouse && IN_Local_Update_Mouse_Clip_Region_Think (&inp.mouse_clip_screen_rect) == true)
{
// Re-center the mouse cursor and clear mouse accumulation
IN_Local_Mouse_Cursor_SetPos (inp.mouse_clip_screen_rect.center_x, inp.mouse_clip_screen_rect.center_y);
inp.mouse_accum_x = inp.mouse_accum_y = 0;
}
// End of function
}
void Input_Mouse_Button_Event (int mstate)
{
if (inp.have_mouse /*|| (key_dest == key_menu && m_keys_bind_grab)*/ )
{ // perform button actions
int i;
for (i = 0 ; i < NUM_MOUSE_BUTTONS ; i ++)
{
int button_bit = (1 << i);
qboolean button_pressed = (mstate & button_bit) && !(inp.mouse_old_button_state & button_bit);
qboolean button_released = !(mstate & button_bit) && (inp.mouse_old_button_state & button_bit);
if (button_pressed || button_released)
Key_Event (K_MOUSE1 + i, button_pressed ? true : false);
}
inp.mouse_old_button_state = mstate;
}
}
void Input_Mouse_Accumulate (void)
{
int new_mouse_x, new_mouse_y;
#pragma message ("Need a clip region check here")
Input_Think ();
if (inp.have_mouse == false)
return;
IN_Local_Mouse_Cursor_GetPos (&new_mouse_x, &new_mouse_y); // GetCursorPos (¤t_pos);
inp.mouse_accum_x += new_mouse_x - inp.mouse_clip_screen_rect.center_x;
inp.mouse_accum_y += new_mouse_y - inp.mouse_clip_screen_rect.center_y;
// Re-center the mouse cursor
IN_Local_Mouse_Cursor_SetPos (inp.mouse_clip_screen_rect.center_x, inp.mouse_clip_screen_rect.center_y);
}
void Input_Mouse_Move (usercmd_t *cmd)
{
Input_Mouse_Accumulate ();
if (inp.mouse_accum_x || inp.mouse_accum_y)
{
int mouse_x = inp.mouse_accum_x *= sensitivity.value;
int mouse_y = inp.mouse_accum_y *= sensitivity.value;
// add mouse X/Y movement to cmd
if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
cmd->sidemove += m_side.value * mouse_x;
else cl.viewangles[YAW] -= m_yaw.value * mouse_x;
if (in_mlook.state & 1)
V_StopPitchDrift ();
if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
{
cl.viewangles[PITCH] += m_pitch.value * mouse_y;
cl.viewangles[PITCH] = CLAMP (cl_minpitch.value, cl.viewangles[PITCH], cl_maxpitch.value);
}
else
{
if ((in_strafe.state & 1) && cl.noclip_anglehack)
cmd->upmove -= m_forward.value * mouse_y;
else cmd->forwardmove -= m_forward.value * mouse_y;
}
inp.mouse_accum_x = inp.mouse_accum_y = 0;
}
}
void Input_Initialize (void)
{
Cmd_AddCommand ("in_info", IN_Info_f);
Cmd_AddCommand ("force_centerview", Force_CenterView_f);
inp.initialized = true;
}
void Input_Shutdown (void)
{
inp.initialized = false;
Input_Think (); // Will shut everything off
}
Header look like:
- Code: Select all
typedef struct mrect_s
{
int left, right, bottom, top;
int center_x, center_y;
int width, height;
} mrect_t;
void Input_Initialize (void);
void Input_Shutdown (void);
void Input_Think (void);
void Input_Mouse_Move (usercmd_t *cmd);
void Input_Mouse_Accumulate (void);
void Input_Mouse_Button_Event (int mstate);
// Platform
void IN_Local_Capture_Mouse (qboolean bDoCapture);
void IN_Local_Keyboard_Disable_Annoying_Keys (qboolean bDoDisable);
void IN_Local_Mouse_Cursor_SetPos (int x, int y);
void IN_Local_Mouse_Cursor_GetPos (int *x, int *y);
qboolean IN_Local_Update_Mouse_Clip_Region_Think (mrect_t* mouseregion);
in_win.c looks like:
- Code: Select all
void IN_Local_Capture_Mouse (qboolean bDoCapture)
{
static qboolean captured = false;
if (bDoCapture && !captured)
{
ShowCursor (FALSE); // Hides mouse cursor
SetCapture (mainwindow); // Captures mouse events
Con_DPrintf ("Mouse Captured\n");
captured = true;
}
if (!bDoCapture && captured)
{
ShowCursor (TRUE); // Hides mouse cursor
ReleaseCapture ();
ClipCursor (NULL); // Can't hurt
Con_DPrintf ("Mouse Released\n");
captured = false;
}
}
qboolean IN_Local_Update_Mouse_Clip_Region_Think (mrect_t* mouseregion)
{
mrect_t oldregion = *mouseregion;
WINDOWINFO windowinfo;
windowinfo.cbSize = sizeof (WINDOWINFO);
GetWindowInfo (mainwindow, &windowinfo); // client_area screen coordinates
// Fill in top left, bottom, right, center
mouseregion->left = windowinfo.rcClient.left;
mouseregion->right = windowinfo.rcClient.right;
mouseregion->bottom = windowinfo.rcClient.bottom;
mouseregion->top = windowinfo.rcClient.top;
if (memcmp (mouseregion, &oldregion, sizeof(mrect_t) ) != 0)
{ // Changed!
mouseregion->width = mouseregion->right - mouseregion->left;
mouseregion->height = mouseregion->bottom - mouseregion->top;
mouseregion->center_x = (mouseregion->left + mouseregion->right) / 2;
mouseregion->center_y = (mouseregion->top + mouseregion->bottom) / 2;
ClipCursor (&windowinfo.rcClient);
return true;
}
return false;
}
void IN_Local_Mouse_Cursor_SetPos (int x, int y)
{
SetCursorPos (x, y);
}
void IN_Local_Mouse_Cursor_GetPos (int *x, int *y)
{
POINT current_pos;
GetCursorPos (¤t_pos);
*x = current_pos.x;
*y = current_pos.y;
}
STICKYKEYS StartupStickyKeys = {sizeof (STICKYKEYS), 0};
TOGGLEKEYS StartupToggleKeys = {sizeof (TOGGLEKEYS), 0};
FILTERKEYS StartupFilterKeys = {sizeof (FILTERKEYS), 0};
void AllowAccessibilityShortcutKeys (qboolean bAllowKeys)
{
static qboolean initialized = false;
if (!initialized)
{ // Save the current sticky/toggle/filter key settings so they can be restored them later
SystemParametersInfo (SPI_GETSTICKYKEYS, sizeof (STICKYKEYS), &StartupStickyKeys, 0);
SystemParametersInfo (SPI_GETTOGGLEKEYS, sizeof (TOGGLEKEYS), &StartupToggleKeys, 0);
SystemParametersInfo (SPI_GETFILTERKEYS, sizeof (FILTERKEYS), &StartupFilterKeys, 0);
Con_DPrintf ("Accessibility key startup settings saved\n");
initialized = true;
}
if (bAllowKeys)
{
// Restore StickyKeys/etc to original state
// (note that this function is called "allow", not "enable"; if they were previously
// disabled it will put them back that way too, it doesn't force them to be enabled.)
SystemParametersInfo (SPI_SETSTICKYKEYS, sizeof (STICKYKEYS), &StartupStickyKeys, 0);
SystemParametersInfo (SPI_SETTOGGLEKEYS, sizeof (TOGGLEKEYS), &StartupToggleKeys, 0);
SystemParametersInfo (SPI_SETFILTERKEYS, sizeof (FILTERKEYS), &StartupFilterKeys, 0);
Con_DPrintf ("Accessibility keys enabled\n");
}
else
{
// Disable StickyKeys/etc shortcuts but if the accessibility feature is on,
// then leave the settings alone as its probably being usefully used
STICKYKEYS skOff = StartupStickyKeys;
TOGGLEKEYS tkOff = StartupToggleKeys;
FILTERKEYS fkOff = StartupFilterKeys;
if ((skOff.dwFlags & SKF_STICKYKEYSON) == 0)
{
// Disable the hotkey and the confirmation
skOff.dwFlags &= ~SKF_HOTKEYACTIVE;
skOff.dwFlags &= ~SKF_CONFIRMHOTKEY;
SystemParametersInfo (SPI_SETSTICKYKEYS, sizeof (STICKYKEYS), &skOff, 0);
}
if ((tkOff.dwFlags & TKF_TOGGLEKEYSON) == 0)
{
// Disable the hotkey and the confirmation
tkOff.dwFlags &= ~TKF_HOTKEYACTIVE;
tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY;
SystemParametersInfo (SPI_SETTOGGLEKEYS, sizeof (TOGGLEKEYS), &tkOff, 0);
}
if ((fkOff.dwFlags & FKF_FILTERKEYSON) == 0)
{
// Disable the hotkey and the confirmation
fkOff.dwFlags &= ~FKF_HOTKEYACTIVE;
fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY;
SystemParametersInfo (SPI_SETFILTERKEYS, sizeof (FILTERKEYS), &fkOff, 0);
}
Con_DPrintf ("Accessibility keys disabled\n");
}
}
LRESULT CALLBACK LLWinKeyHook(int Code, WPARAM wParam, LPARAM lParam)
{
PKBDLLHOOKSTRUCT p;
p = (PKBDLLHOOKSTRUCT) lParam;
if (vid.ActiveApp)
{
switch(p->vkCode)
{
case VK_LWIN: // Left Windows Key
case VK_RWIN: // Right Windows key
case VK_APPS: // Context Menu key
return 1; // Ignore these keys
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
void AllowWindowsShortcutKeys (qboolean bAllowKeys)
{
static qboolean WinKeyHook_isActive = false;
static HHOOK WinKeyHook;
if (!bAllowKeys)
{
// Disable if not already disabled
if (!WinKeyHook_isActive)
{
if (!(WinKeyHook = SetWindowsHookEx(13, LLWinKeyHook, global_hInstance, 0)))
{
Con_Printf("Failed to install winkey hook.\n");
Con_Printf("Microsoft Windows NT 4.0, 2000 or XP is required.\n");
return;
}
WinKeyHook_isActive = true;
Con_DPrintf ("Windows and context menu key disabled\n");
}
}
if (bAllowKeys)
{ // Keys allowed .. stop hook
if (WinKeyHook_isActive)
{
UnhookWindowsHookEx(WinKeyHook);
WinKeyHook_isActive = false;
Con_DPrintf ("Windows and context menu key enabled\n");
}
}
}
void IN_Local_Keyboard_Disable_Annoying_Keys (qboolean bDoDisable)
{
if (bDoDisable)
{
AllowAccessibilityShortcutKeys (false);
AllowWindowsShortcutKeys (false);
}
else
{
AllowAccessibilityShortcutKeys (true);
AllowWindowsShortcutKeys (true);
}
}
/*
=======
MapKey
Map from windows to quake keynums
=======
*/
int IN_Local_MapKey (int windowskey)
{
static byte scantokey[128] =
{
0 , 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', K_BACKSPACE,
9, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 13 ,
K_CTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
K_SHIFT,'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',K_ALT,' ', 0 ,
K_F1, K_F2, K_F3, K_F4, K_F5,K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0,
K_HOME, K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END,
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0,
};
int key = (windowskey >> 16) & 255;
if (key > 127)
return 0;
key = scantokey[key];
/*
switch (key)
{
case K_KP_STAR: return '*';
case K_KP_MINUS: return '-';
case K_KP_5: return '5';
case K_KP_PLUS: return '+';
}
*/
return key;
}
qboolean IN_ReadInputMessages (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
int button_bits = 0;
switch (Msg)
{
case WM_MOUSEWHEEL:
if ((short) HIWORD(wParam) > 0)
{
Key_Event(K_MWHEELUP, true);
Key_Event(K_MWHEELUP, false);
}
else
{
Key_Event(K_MWHEELDOWN, true);
Key_Event(K_MWHEELDOWN, false);
}
return true;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON) button_bits |= 1;
if (wParam & MK_RBUTTON) button_bits |= 2;
if (wParam & MK_MBUTTON) button_bits |= 4;
if (wParam & MK_XBUTTON1) button_bits |= 8;
if (wParam & MK_XBUTTON2) button_bits |= 16;
Input_Mouse_Button_Event (button_bits);
return true;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
Key_Event (IN_Local_MapKey (lParam), true);
return true;
case WM_KEYUP:
case WM_SYSKEYUP:
Key_Event (IN_Local_MapKey(lParam), false);
return true;
default:
return false;
}
}
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
Re: Input untangled
dude, that's disgusting.
shift+2 should be a " char, not an @
fix it. fix it now.
before I vomit.
more seriously though, code that ignores your keymap is really insanely annoying. especially if you're an azerty user, or indeed any other european or other non-american.
shift+2 should be a " char, not an @
fix it. fix it now.
before I vomit.
more seriously though, code that ignores your keymap is really insanely annoying. especially if you're an azerty user, or indeed any other european or other non-american.
- Spike
- Posts: 2892
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
Re: Input untangled
I agree with that. Since it is my understanding that Quakespasm does this well, I may adopt the Quakespasm keyboard input code. I'm trying to solve things one step at a time.Spike wrote:dude, that's disgusting.
shift+2 should be a " char, not an @
fix it. fix it now.
before I vomit.
more seriously though, code that ignores your keymap is really insanely annoying. especially if you're an azerty user, or indeed any other european or other non-american.
p.s. I get the joke.
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
-

Baker - Posts: 3666
- Joined: Tue Mar 14, 2006 5:15 am
7 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest