/* =================== Key_Event Called by the system for both key up and key down events =================== */ void Key_Event( int key, qboolean down ) { const char *kb; char cmd[1024]; //Con_Printf( "Keycode %d\n", key ); if ( key > 255 || key < 0) { Con_Printf ("Keynum %d out of range\n", key); return; } // update auto-repeat status and BUTTON_ANY status keys[key].down = down; if( down ) { //keys[key].repeats++; if( key != K_BACKSPACE && key != K_PAUSE && keys[key].repeats > 1 ) { if( cls.key_dest == key_game ) { // ignore most autorepeats return; } } } else { keys[key].repeats = 0; } // console key is hardcoded, so the user can never unbind it if( key == '`' || key == '~' ) { // we are in typing mode, so don't switch to console if( cls.key_dest == key_message || !down ) return; Con_ToggleConsole_f(); return; } // escape is always handled specially if( key == K_ESCAPE && down ) { switch( cls.key_dest ) { case key_game: if( host.mouse_visible && cls.state != ca_cinematic ) { clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding ); return; // handled in client.dll } break; case key_message: Key_Message( key ); return; case key_console: if( cls.state == ca_active && !cl.background ) Key_SetKeyDest( key_game ); else UI_SetActiveMenu( true ); return; case key_menu: UI_KeyEvent( key, true ); return; default: MsgDev( D_ERROR, "Key_Event: bad cls.key_dest\n" ); return; } } if( cls.key_dest == key_menu ) { // only non printable keys passed UI_KeyEvent( key, 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( !down ) { kb = keys[key].binding; if( cls.key_dest == key_game && ( key != K_ESCAPE )) clgame.dllFuncs.pfnKey_Event( down, key, kb ); Key_AddKeyUpCommands( key, kb ); return; } // distribute the key down event to the apropriate handler if( cls.key_dest == key_game ) { if( cls.state == ca_cinematic ) { // only escape passed when cinematic is playing // HLFX 0.6 bug: crash in vgui3.dll while press +attack during movie playback if( key != K_ESCAPE || !down ) return; } else if( host.mouse_visible ) return; // send the bound action kb = keys[key].binding; if( !clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding )) { // handled in client.dll } else if( kb != NULL ) { if( kb[0] == '+' ) { int i; char button[1024], *buttonPtr; for( i = 0, buttonPtr = button; ; i++ ) { if( kb[i] == ';' || !kb[i] ) { *buttonPtr = '\0'; if( button[0] == '+' ) { Q_sprintf( cmd, "%s %i\n", button, key ); 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" ); } } } else if( cls.key_dest == key_console ) { Key_Console( key ); } else if( cls.key_dest == key_message ) { Key_Message( key ); } }
/** * @brief Called by the system between frames for both key up and key down events * @note Should NOT be called during an interrupt! * @sa Key_Message */ void Key_Event (unsigned int key, unsigned short unicode, qboolean down, unsigned time) { char cmd[MAX_STRING_CHARS]; /* unbindable key */ if (key >= K_KEY_SIZE) return; /* any key (except F1-F12) during the sequence mode will bring up the menu */ if (cls.keyDest == key_game && down) { if (UI_KeyPressed(key, unicode)) return; } /* menu key is hardcoded, so the user can never unbind it */ if (key == K_ESCAPE) { if (!down) return; switch (cls.keyDest) { case key_console: Con_ToggleConsole_f(); break; default: Com_Error(ERR_FATAL, "Bad cls.key_dest"); } return; } /* track if any key is down for BUTTON_ANY */ keyDown[key] = down; if (!down) { int i; /* key up events only generate commands if the game key binding is * a button command (leading + sign). These will occur even in console mode, * to keep the character from continuing an action started before a console * switch. Button commands include the kenum as a parameter, so multiple * downs can be matched with ups */ const char *kb = menuKeyBindings[key]; /* this loop ensures, that every down event reaches it's proper kbutton_t */ for (i = 0; i < 3; i++) { if (kb && kb[0] == '+') { /* '-' means we have released the key * the key number is used to determine whether the kbutton_t is really * released or whether any other bound key will still ensure that the * kbutton_t is pressed * the time is the msec value when the key was released */ Com_sprintf(cmd, sizeof(cmd), "-%s %i %i\n", kb + 1, key, time); Cbuf_AddText(cmd); } if (i == 0) kb = keyBindings[key]; else kb = battleKeyBindings[key]; } return; } /* if not a consolekey, send to the interpreter no matter what mode is */ if (cls.keyDest == key_game || (key >= K_MOUSE1 && key <= K_MWHEELUP)) { /* Some keyboards need modifiers to access key values that are * present as bare keys on other keyboards. Smooth over the difference * here by using the translated value if there is a binding for it. */ const char *kb = NULL; if (mouseSpace == MS_UI && unicode >= 32 && unicode < 127) kb = menuKeyBindings[unicode]; if (!kb && mouseSpace == MS_UI) kb = menuKeyBindings[key]; if (!kb && unicode >= 32 && unicode < 127) kb = keyBindings[unicode]; if (!kb) kb = keyBindings[key]; if (!kb && CL_OnBattlescape()) kb = battleKeyBindings[key]; if (kb) { if (kb[0] == '+') { /* button commands add keynum and time as a parm */ /* '+' means we have pressed the key * the key number is used because the kbutton_t can be 'pressed' by several keys * the time is the msec value when the key was pressed */ Com_sprintf(cmd, sizeof(cmd), "%s %i %i\n", kb, key, time); Cbuf_AddText(cmd); } else { Cbuf_AddText(kb); Cbuf_AddText("\n"); } if (cls.keyDest == key_game) return; } } if (!down) return; /* other systems only care about key down events */ switch (cls.keyDest) { case key_game: case key_console: Key_Console(key, unicode); break; default: Com_Error(ERR_FATAL, "Bad cls.key_dest"); } }
/* =================== Key_Event Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ void Key_Event(unsigned key, qboolean down, unsigned time) { char *kb; char cmd[MAX_STRING_CHARS]; if (key >= 256) { Com_Error(ERR_FATAL, "%s: bad key", __func__); } Com_DDDPrintf("%u: %c%s\n", time, down ? '+' : '-', Key_KeynumToString(key)); // hack for menu key binding if (key_wait_cb && down && !key_wait_cb(key_wait_arg, key)) { return; } // update key down and auto-repeat status if (down) { if (keydown[key] < 255) keydown[key]++; } else { keydown[key] = 0; } // console key is hardcoded, so the user can never unbind it if (!Key_IsDown(K_SHIFT) && (key == '`' || key == '~')) { if (keydown[key] == 1) { Con_ToggleConsole_f(); } return; } // Alt+Enter is hardcoded for all systems if (Key_IsDown(K_ALT) && key == K_ENTER) { if (keydown[key] == 1) { VID_ToggleFullscreen(); } return; } // menu key is hardcoded, so the user can never unbind it if (key == K_ESCAPE) { if (!down) { return; } if (cls.key_dest == KEY_GAME && cl.frame.ps.stats[STAT_LAYOUTS] && cls.demo.playback == qfalse) { if (keydown[key] == 2) { // force main menu if escape is held UI_OpenMenu(UIMENU_GAME); } else if (keydown[key] == 1) { // put away help computer / inventory CL_ClientCommand("putaway"); } return; } // ignore autorepeats if (keydown[key] > 1) { return; } if (cls.key_dest & KEY_CONSOLE) { if (cls.state < ca_active && !(cls.key_dest & KEY_MENU)) { UI_OpenMenu(UIMENU_MAIN); } else { Con_Close(qtrue); } } else if (cls.key_dest & KEY_MENU) { UI_Keydown(key); } else if (cls.key_dest & KEY_MESSAGE) { Key_Message(key); } else if (cls.state == ca_active) { UI_OpenMenu(UIMENU_GAME); } else { UI_OpenMenu(UIMENU_MAIN); } return; } // track if any key is down for BUTTON_ANY if (down) { if (keydown[key] == 1) anykeydown++; } else { anykeydown--; if (anykeydown < 0) anykeydown = 0; } // hack for demo freelook in windowed mode if (cls.key_dest == KEY_GAME && cls.demo.playback && key == K_SHIFT && keydown[key] <= 1) { IN_Activate(); } // // if not a consolekey, send to the interpreter no matter what mode is // if ((cls.key_dest == KEY_GAME) || ((cls.key_dest & KEY_CONSOLE) && !Q_IsBitSet(consolekeys, key)) || ((cls.key_dest & KEY_MENU) && (key >= K_F1 && key <= K_F12)) || (!down && Q_IsBitSet(buttondown, key))) { // // Key up events only generate commands if the game key binding is a button // command (leading + sign). These will occur even in console mode, to keep the // character from continuing an action started before a console switch. Button // commands include the kenum as a parameter, so multiple downs can be matched // with ups. // if (!down) { kb = keybindings[key]; if (kb && kb[0] == '+') { Q_snprintf(cmd, sizeof(cmd), "-%s %i %i\n", kb + 1, key, time); Cbuf_AddText(&cmd_buffer, cmd); } Q_ClearBit(buttondown, key); return; } // ignore autorepeats if (keydown[key] > 1) { return; } // generate button up command when released Q_SetBit(buttondown, key); kb = keybindings[key]; if (kb) { if (kb[0] == '+') { // button commands add keynum and time as a parm Q_snprintf(cmd, sizeof(cmd), "%s %i %i\n", kb, key, time); Cbuf_AddText(&cmd_buffer, cmd); } else { Cbuf_AddText(&cmd_buffer, kb); Cbuf_AddText(&cmd_buffer, "\n"); } } return; } if (cls.key_dest == KEY_GAME) return; if (!down) return; // other subsystems only care about key down events if (cls.key_dest & KEY_CONSOLE) { Key_Console(key); } else if (cls.key_dest & KEY_MENU) { UI_Keydown(key); } else if (cls.key_dest & KEY_MESSAGE) { Key_Message(key); } if (Key_IsDown(K_CTRL) || Key_IsDown(K_ALT)) { return; } switch (key) { case K_KP_SLASH: key = '/'; break; case K_KP_MULTIPLY: key = '*'; break; case K_KP_MINUS: key = '-'; break; case K_KP_PLUS: key = '+'; break; case K_KP_HOME: key = '7'; break; case K_KP_UPARROW: key = '8'; break; case K_KP_PGUP: key = '9'; break; case K_KP_LEFTARROW: key = '4'; break; case K_KP_5: key = '5'; break; case K_KP_RIGHTARROW: key = '6'; break; case K_KP_END: key = '1'; break; case K_KP_DOWNARROW: key = '2'; break; case K_KP_PGDN: key = '3'; break; case K_KP_INS: key = '0'; break; case K_KP_DEL: key = '.'; break; } // if key is printable, generate char events if (key < 32 || key >= 127) { return; } if (Key_IsDown(K_SHIFT)) { key = keyshift[key]; } if (cls.key_dest & KEY_CONSOLE) { Char_Console(key); } else if (cls.key_dest & KEY_MENU) { UI_CharEvent(key); } else if (cls.key_dest & KEY_MESSAGE) { Char_Message(key); } }
/* =================== Key_Event Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ void Key_Event (int key, qboolean down, uint32 time) { char *kb; char cmd[1024]; // hack for modal presses /*if (key_waiting == -1) { if (down) key_waiting = key; return; }*/ //Com_Printf ("%d is %d for %u\n", LOG_GENERAL, key, down, time); // update auto-repeat status if (down) { key_repeats[key]++; if (cls.key_dest != key_console && key != K_BACKSPACE && key != K_DEL && key != K_LEFTARROW && key != K_RIGHTARROW && key != K_PAUSE && key != K_PGUP && key != K_KP_PGUP && key != K_PGDN && key != K_KP_PGDN && key_repeats[key] > 1) return; // ignore most autorepeats if (key >= 200 && !keybindings[key]) Com_Printf ("%s is unbound, hit F4 to set.\n", LOG_CLIENT, Key_KeynumToString (key) ); } else { key_repeats[key] = 0; } //for dinput if (down && keydown[K_ALT]) { if (key == K_ENTER) { Com_Printf ("ALT+Enter, setting fullscreen %d.\n", LOG_CLIENT, !vid_fullscreen->intvalue); Cvar_SetValue( "vid_fullscreen", (float)!vid_fullscreen->intvalue ); return; } else if (key == K_TAB) { //prevent executing action on alt+tab return; } } if (key == K_SHIFT) shift_down = down; // console key is hardcoded, so the user can never unbind it if ((key == '`' || key == '~') && !shift_down) { if (!down) return; Con_ToggleConsole_f (); return; } // any key during the attract mode will bring up the menu /*if (cl.attractloop && cls.key_dest != key_menu && !(key >= K_F1 && key <= K_F12)) key = K_ESCAPE;*/ // menu key is hardcoded, so the user can never unbind it if (key == K_ESCAPE) { if (!down) return; if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game) { // put away help computer / inventory Cbuf_AddText ("cmd putaway\n"); return; } switch (cls.key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: M_Menu_Main_f (); break; default: Com_Error (ERR_FATAL, "Bad cls.key_dest"); } return; } if (!keydown[key]) key_lastrepeat[key] = curtime + key_repeatdelay; // track if any key is down for BUTTON_ANY keydown[key] = down; if (down) { if (key_repeats[key] == 1) anykeydown++; } else { key_lastrepeat[key] = 0; anykeydown--; if (anykeydown < 0) anykeydown = 0; } // // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, // to keep the character from continuing an action started before a console // switch. Button commands include the kenum as a parameter, so multiple // downs can be matched with ups // if (!down) { //r1ch: only generate -events if key was down (prevents -binds in menu / messagemode) if (buttondown[key]) { kb = keybindings[key]; if (kb && kb[0] == '+') { Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time); Cbuf_AddText (cmd); } if (keyshift[key] != key) { kb = keybindings[keyshift[key]]; if (kb && kb[0] == '+') { Com_sprintf (cmd, sizeof(cmd), "-%s %i %u\n", kb+1, key, time); Cbuf_AddText (cmd); } } buttondown[key] = false; } return; } // // if not a consolekey, send to the interpreter no matter what mode is // if ( (cls.key_dest == key_menu && menubound[key]) || (cls.key_dest == key_console && !consolekeys[key]) || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) ) { kb = keybindings[key]; if (kb && kb[0]) { if (kb[0] == '+') { // button commands add keynum and time as a parm if (cls.key_dest != key_game) //r1: don't run buttons in console return; Com_sprintf (cmd, sizeof(cmd), "%s %i %u\n", kb, key, time); Cbuf_AddText (cmd); buttondown[key] = true; } else { Cbuf_AddText (kb); Cbuf_AddText ("\n"); } } return; } //if (!down) // return; // other systems only care about key down events if (shift_down) key = keyshift[key]; switch (cls.key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: Key_Console (key); break; default: Com_Error (ERR_FATAL, "Bad cls.key_dest"); } }
/* =================== Key_Event Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ void Key_Event (int key, qboolean down) { char *kb; char cmd[1024]; keydown[key] = down; if (!down) key_repeats[key] = 0; key_lastpress = key; key_count++; if (key_count <= 0) return; // just catching keys for Con_NotifyBox // update auto-repeat status if (down) { /* Pause key doesn't generate a scancode when released, * never increment its auto-repeat status. */ if (key != K_PAUSE && key != K_KP_NUMLOCK) key_repeats[key]++; #if 0 if (key != K_BACKSPACE && key != K_PGUP && key != K_PGDN && key_repeats[key] > 1) return; // ignore most autorepeats #endif if (key_repeats[key] > 1) { if (key_dest == key_game && !con_forcedup) return; // ignore autorepeats in game mode } else if (key >= 200 && !keybindings[key]) Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key)); } if (key == K_SHIFT) shift_down = down; // handle escape specialy, so the user can never unbind it if (key == K_ESCAPE) { if (!down) return; switch (key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_menubind: M_Keybind (key); break; case key_game: case key_console: M_ToggleMenu_f (); break; default: Sys_Error ("Bad key_dest"); } return; } // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, // to keep the character from continuing an action started before a console // switch. Button commands include the kenum as a parameter, so multiple // downs can be matched with ups if (!down) { kb = keybindings[key]; if (kb && kb[0] == '+') { sprintf (cmd, "-%s %i\n", kb+1, key); Cbuf_AddText (cmd); } if (keyshift[key] != key) { kb = keybindings[keyshift[key]]; if (kb && kb[0] == '+') { sprintf (cmd, "-%s %i\n", kb+1, key); Cbuf_AddText (cmd); } } return; } // during demo playback, most keys bring up the main menu if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game) { M_ToggleMenu_f (); return; } // if not a consolekey, send to the interpreter no matter what mode is if (((key_dest & key_menu) && menubound[key]) || (key_dest == key_console && !consolekeys[key]) || (key_dest == key_game && (!con_forcedup || !consolekeys[key]))) { kb = keybindings[key]; if (kb) { if (kb[0] == '+') { // button commands add keynum as a parm sprintf (cmd, "%s %i\n", kb, key); Cbuf_AddText (cmd); } else { Cbuf_AddText (kb); Cbuf_AddText ("\n"); } } return; } if (!down) return; // other systems only care about key down events if (shift_down) key = keyshift[key]; switch (key_dest) { case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_menubind: M_Keybind (key); break; case key_game: case key_console: Key_Console (key); break; default: Sys_Error ("Bad key_dest"); } }
/** * \brief Called by the system between frames for both key up and key down events. * \param[in] key Key mapping * \param[in] down Is key being pressed? * \param[in] time * \note Should NOT be called during an interrupt! */ PUBLIC void Key_Event( int key, _boolean down, unsigned time ) { char *kb; char cmd[ 1024 ]; // hack for modal presses if (key_waiting == -1) { if (down) { key_waiting = key; } return; } // update auto-repeat status if (down) { key_repeats[key]++; if (key != K_BACKSPACE && key != K_PAUSE && key != K_PGUP && key != K_KP_PGUP && key != K_PGDN && key != K_KP_PGDN && key_repeats[key] > 1) { return; // ignore most autorepeats } if (key >= 200 && !keybindings[key]) { Com_Printf ( "%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) ); } } else { key_repeats[ key ] = 0; } if( key == K_SHIFT ) { shift_down = down; } // console key is hardcoded, so the user can never unbind it if( key == '`' || key == '~' ) { if( ! down ) { return; } Con_ToggleConsole_f(); return; } // any key during the attract mode will bring up the menu // if (cl.attractloop && ClientStatic.key_dest != key_menu && // !(key >= K_F1 && key <= K_F12)) // key = K_ESCAPE; // menu key is hardcoded, so the user can never unbind it if( key == K_ESCAPE ) { if( ! down ) { return; } // if (cl.frame.playerstate.stats[STAT_LAYOUTS] && ClientStatic.key_dest == key_game) // { // put away help computer / inventory // Cbuf_AddText ("cmd putaway\n"); // return; // } switch( ClientStatic.key_dest ) { case key_message: Key_Message( key ); break; case KEY_AUTOMAP: automap_keydown( key ); break; case key_menu: M_Keydown( key ); break; case key_game: case key_console: M_Menu_Main_f(); break; default: Com_DPrintf( "Bad ClientStatic.key_dest\n" ); } return; } // track if any key is down for BUTTON_ANY keydown[key] = down; if (down) { if (key_repeats[key] == 1) { anykeydown++; } } else { anykeydown--; if (anykeydown < 0) { anykeydown = 0; } } // // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, // to keep the character from continuing an action started before a console // switch. Button commands include the kenum as a parameter, so multiple // downs can be matched with ups // if( ! down ) { kb = keybindings[key]; if (kb && kb[0] == '+') { com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } if (keyshift[key] != key) { kb = keybindings[keyshift[key]]; if (kb && kb[0] == '+') { com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } } return; } // // if not a consolekey, send to the interpreter no matter what mode is // if ( (ClientStatic.key_dest == key_menu && menubound[key]) || (ClientStatic.key_dest == key_console && !consolekeys[key]) || (ClientStatic.key_dest == key_game ) ) { kb = keybindings[key]; if (kb) { if (kb[0] == '+') { // button commands add keynum and time as a parm com_snprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time); Cbuf_AddText (cmd); } else { Cbuf_AddText (kb); Cbuf_AddText ("\n"); } } return; } if( ! down ) { return; // other systems only care about key down events } if (shift_down) { key = keyshift[ key ]; } switch (ClientStatic.key_dest) { case KEY_AUTOMAP: automap_keydown( key ); break; case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: Key_Console (key); break; default: Com_DPrintf( "Bad ClientStatic.key_dest\n" ); } }