From dd572db7d619a7b8cba95588111f1450ccbfdb18 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Sat, 3 Oct 2009 23:35:07 +0000 Subject: [PATCH] Rewrite of key event processing, thanks to /dev/humancontroller and Ben Millwood. https://bugzilla.icculus.org/show_bug.cgi?id=3374 --- code/client/cl_keys.c | 239 ++++++++++++++++++------------------------ 1 file changed, 103 insertions(+), 136 deletions(-) diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index f2932d96..b6eb2087 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -1118,94 +1118,72 @@ void CL_InitKeyCommands( void ) { /* =================== -CL_AddKeyUpCommands +CL_ParseBinding + +Execute the commands in the bind string =================== */ -void CL_AddKeyUpCommands( int key, char *kb, unsigned time) { - int i; - char button[1024], *buttonPtr; - char cmd[1024]; - qboolean keyevent; +void CL_ParseBinding( int key, qboolean down, unsigned time ) +{ + char buf[ MAX_STRING_CHARS ], *p = buf, *end; - if ( !kb ) { + if( !keys[key].binding || !keys[key].binding[0] ) return; - } - keyevent = qfalse; - buttonPtr = button; - for ( i = 0; ; i++ ) { - if ( kb[i] == ';' || !kb[i] ) { - *buttonPtr = '\0'; - if ( button[0] == '+') { - // button commands add keynum and time as parms so that multiple - // sources can be discriminated and subframe corrected - Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", button+1, key, time); - Cbuf_AddText (cmd); - keyevent = qtrue; - } else { - if (keyevent) { - // down-only command - Cbuf_AddText (button); - Cbuf_AddText ("\n"); - } - } - buttonPtr = button; - while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) { - i++; - } + Q_strncpyz( buf, keys[key].binding, sizeof( buf ) ); + + while( 1 ) + { + while( isspace( *p ) ) + p++; + end = strchr( p, ';' ); + if( end ) + *end = '\0'; + if( *p == '+' ) + { + // button commands add keynum and time as parameters + // so that multiple sources can be discriminated and + // subframe corrected + char cmd[1024]; + Com_sprintf( cmd, sizeof( cmd ), "%c%s %d %d\n", + ( down ) ? '+' : '-', p + 1, key, time ); + Cbuf_AddText( cmd ); } - *buttonPtr++ = kb[i]; - if ( !kb[i] ) { + else if( down ) + { + // normal commands only execute on key press + Cbuf_AddText( p ); + Cbuf_AddText( "\n" ); + } + if( !end ) break; - } + p = end + 1; } } /* =================== -CL_KeyEvent +CL_KeyDownEvent -Called by the system for both key up and key down events +Called by CL_KeyEvent to handle a keypress =================== */ -void CL_KeyEvent (int key, qboolean down, unsigned time) { - char *kb; - char cmd[1024]; +void CL_KeyDownEvent( int key, unsigned time ) +{ + keys[key].down = qtrue; + keys[key].repeats++; + if( keys[key].repeats == 1 ) + anykeydown++; - // update auto-repeat status and BUTTON_ANY status - keys[key].down = down; - - if (down) { - keys[key].repeats++; - if ( keys[key].repeats == 1) { - anykeydown++; - } - } else { - keys[key].repeats = 0; - anykeydown--; - if (anykeydown < 0) { - anykeydown = 0; - } - } - - if (key == K_ENTER) + if( keys[K_ALT].down && key == K_ENTER ) { - if (down) - { - if (keys[K_ALT].down) - { - Cvar_SetValue( "r_fullscreen", - !Cvar_VariableIntegerValue( "r_fullscreen" ) ); - return; - } - } + Cvar_SetValue( "r_fullscreen", + !Cvar_VariableIntegerValue( "r_fullscreen" ) ); + return; } // console key is hardcoded, so the user can never unbind it - if (key == K_CONSOLE || - ( key == K_ESCAPE && keys[K_SHIFT].down ) ) { - if (!down) { - return; - } + if( key == K_CONSOLE || ( keys[K_SHIFT].down && key == K_ESCAPE ) ) + { Con_ToggleConsole_f (); Key_ClearStates (); return; @@ -1213,7 +1191,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { // keys can still be used for bound actions - if ( down && ( key < 128 || key == K_MOUSE1 ) && + if ( ( key < 128 || key == K_MOUSE1 ) && ( clc.demoplaying || cls.state == CA_CINEMATIC ) && Key_GetCatcher( ) == 0 ) { if (Cvar_VariableValue ("com_cameraMode") == 0) { @@ -1222,9 +1200,8 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { } } - // escape is always handled special - if ( key == K_ESCAPE && down ) { + if ( key == K_ESCAPE ) { if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) { // clear message mode Message_Key( key ); @@ -1250,43 +1227,20 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { return; } - VM_Call( uivm, UI_KEY_EVENT, key, down ); + VM_Call( uivm, UI_KEY_EVENT, key, qtrue ); return; } - // - // key up events only perform actions if the game key binding is - // a button command (leading + sign). These will be processed even in - // console mode and menu mode, to keep the character from continuing - // an action started before a mode switch. - // - if (!down ) { - if ( cls.state != CA_DISCONNECTED ) { - kb = keys[key].binding; - - CL_AddKeyUpCommands( key, kb, time ); - } - - if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) { - VM_Call( uivm, UI_KEY_EVENT, key, down ); - } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME && cgvm ) { - VM_Call( cgvm, CG_KEY_EVENT, key, down ); - } - - return; - } - - // distribute the key down event to the apropriate handler if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) { Console_Key( key ); } else if ( Key_GetCatcher( ) & KEYCATCH_UI ) { if ( uivm ) { - VM_Call( uivm, UI_KEY_EVENT, key, down ); + VM_Call( uivm, UI_KEY_EVENT, key, qtrue ); } } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME ) { if ( cgvm ) { - VM_Call( cgvm, CG_KEY_EVENT, key, down ); + VM_Call( cgvm, CG_KEY_EVENT, key, qtrue ); } } else if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE ) { Message_Key( key ); @@ -1294,47 +1248,60 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { Console_Key( key ); } else { // send the bound action - kb = keys[key].binding; - if ( !kb ) { - if (key >= 200) { - Com_Printf ("%s is unbound, use controls menu to set.\n" - , Key_KeynumToString( key ) ); - } - } else if (kb[0] == '+') { - int i; - char button[1024], *buttonPtr; - buttonPtr = button; - for ( i = 0; ; i++ ) { - if ( kb[i] == ';' || !kb[i] ) { - *buttonPtr = '\0'; - if ( button[0] == '+') { - // button commands add keynum and time as parms so that multiple - // sources can be discriminated and subframe corrected - Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", button, key, time); - Cbuf_AddText (cmd); - } else { - // down-only command - Cbuf_AddText (button); - Cbuf_AddText ("\n"); - } - buttonPtr = button; - while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) { - i++; - } - } - *buttonPtr++ = kb[i]; - if ( !kb[i] ) { - break; - } - } - } else { - // down-only command - Cbuf_AddText (kb); - Cbuf_AddText ("\n"); - } + CL_ParseBinding( key, qtrue, time ); + } + return; +} + +/* +=================== +CL_KeyUpEvent + +Called by CL_KeyEvent to handle a keyrelease +=================== +*/ +void CL_KeyUpEvent( int key, unsigned time ) +{ + keys[key].repeats = 0; + keys[key].down = qfalse; + anykeydown--; + if (anykeydown < 0) { + anykeydown = 0; + } + + // don't process key-up events for the console key + if ( key == K_CONSOLE || ( key == K_ESCAPE && keys[K_SHIFT].down ) ) + return; + + // + // key up events only perform actions if the game key binding is + // a button command (leading + sign). These will be processed even in + // console mode and menu mode, to keep the character from continuing + // an action started before a mode switch. + // + if( cls.state != CA_DISCONNECTED ) + CL_ParseBinding( key, qfalse, time ); + + if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) { + VM_Call( uivm, UI_KEY_EVENT, key, qfalse ); + } else if ( Key_GetCatcher( ) & KEYCATCH_CGAME && cgvm ) { + VM_Call( cgvm, CG_KEY_EVENT, key, qfalse ); } } +/* +=================== +CL_KeyEvent + +Called by the system for both key up and key down events +=================== +*/ +void CL_KeyEvent (int key, qboolean down, unsigned time) { + if( down ) + CL_KeyDownEvent( key, time ); + else + CL_KeyUpEvent( key, time ); +} /* ===================