File: client\keys.c

    1 /*
    2 Copyright (C) 1997-2001 Id Software, Inc.
    3 
    4 This program is free software; you can redistribute it and/or
    5 modify it under the terms of the GNU General Public License
    6 as published by the Free Software Foundation; either version 2
    7 of the License, or (at your option) any later version.
    8 
    9 This program is distributed in the hope that it will be useful,
   10 but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
   12 
   13 See the GNU General Public License for more details.
   14 
   15 You should have received a copy of the GNU General Public License
   16 along with this program; if not, write to the Free Software
   17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   18 
   19 */
   20 #include "client.h"
   21 
   22 /*
   23 
   24 key up events are sent even if in console mode
   25 
   26 */
   27 
   28 
   29 #define         MAXCMDLINE      256
   30 char    key_lines[32][MAXCMDLINE];
   31 int             key_linepos;
   32 int             shift_down=false;
   33 int     anykeydown;
   34 
   35 int             edit_line=0;
   36 int             history_line=0;
   37 
   38 int             key_waiting;
   39 char    *keybindings[256];
   40 qboolean        consolekeys[256];       // if true, can't be rebound while in console
   41 qboolean        menubound[256]; // if true, can't be rebound while in menu
   42 int             keyshift[256];          // key to map to if shift held down in console
   43 int             key_repeats[256];       // if > 1, it is autorepeating
   44 qboolean        keydown[256];
   45 
   46 typedef struct
   47 {
   48         char    *name;
   49         int             keynum;
   50 } keyname_t;
   51 
   52 keyname_t keynames[] =
   53 {
   54         {"TAB", K_TAB},
   55         {"ENTER", K_ENTER},
   56         {"ESCAPE", K_ESCAPE},
   57         {"SPACE", K_SPACE},
   58         {"BACKSPACE", K_BACKSPACE},
   59         {"UPARROW", K_UPARROW},
   60         {"DOWNARROW", K_DOWNARROW},
   61         {"LEFTARROW", K_LEFTARROW},
   62         {"RIGHTARROW", K_RIGHTARROW},
   63 
   64         {"ALT", K_ALT},
   65         {"CTRL", K_CTRL},
   66         {"SHIFT", K_SHIFT},
   67         
   68         {"F1", K_F1},
   69         {"F2", K_F2},
   70         {"F3", K_F3},
   71         {"F4", K_F4},
   72         {"F5", K_F5},
   73         {"F6", K_F6},
   74         {"F7", K_F7},
   75         {"F8", K_F8},
   76         {"F9", K_F9},
   77         {"F10", K_F10},
   78         {"F11", K_F11},
   79         {"F12", K_F12},
   80 
   81         {"INS", K_INS},
   82         {"DEL", K_DEL},
   83         {"PGDN", K_PGDN},
   84         {"PGUP", K_PGUP},
   85         {"HOME", K_HOME},
   86         {"END", K_END},
   87 
   88         {"MOUSE1", K_MOUSE1},
   89         {"MOUSE2", K_MOUSE2},
   90         {"MOUSE3", K_MOUSE3},
   91 
   92         {"JOY1", K_JOY1},
   93         {"JOY2", K_JOY2},
   94         {"JOY3", K_JOY3},
   95         {"JOY4", K_JOY4},
   96 
   97         {"AUX1", K_AUX1},
   98         {"AUX2", K_AUX2},
   99         {"AUX3", K_AUX3},
  100         {"AUX4", K_AUX4},
  101         {"AUX5", K_AUX5},
  102         {"AUX6", K_AUX6},
  103         {"AUX7", K_AUX7},
  104         {"AUX8", K_AUX8},
  105         {"AUX9", K_AUX9},
  106         {"AUX10", K_AUX10},
  107         {"AUX11", K_AUX11},
  108         {"AUX12", K_AUX12},
  109         {"AUX13", K_AUX13},
  110         {"AUX14", K_AUX14},
  111         {"AUX15", K_AUX15},
  112         {"AUX16", K_AUX16},
  113         {"AUX17", K_AUX17},
  114         {"AUX18", K_AUX18},
  115         {"AUX19", K_AUX19},
  116         {"AUX20", K_AUX20},
  117         {"AUX21", K_AUX21},
  118         {"AUX22", K_AUX22},
  119         {"AUX23", K_AUX23},
  120         {"AUX24", K_AUX24},
  121         {"AUX25", K_AUX25},
  122         {"AUX26", K_AUX26},
  123         {"AUX27", K_AUX27},
  124         {"AUX28", K_AUX28},
  125         {"AUX29", K_AUX29},
  126         {"AUX30", K_AUX30},
  127         {"AUX31", K_AUX31},
  128         {"AUX32", K_AUX32},
  129 
  130         {"KP_HOME",                     K_KP_HOME },
  131         {"KP_UPARROW",          K_KP_UPARROW },
  132         {"KP_PGUP",                     K_KP_PGUP },
  133         {"KP_LEFTARROW",        K_KP_LEFTARROW },
  134         {"KP_5",                        K_KP_5 },
  135         {"KP_RIGHTARROW",       K_KP_RIGHTARROW },
  136         {"KP_END",                      K_KP_END },
  137         {"KP_DOWNARROW",        K_KP_DOWNARROW },
  138         {"KP_PGDN",                     K_KP_PGDN },
  139         {"KP_ENTER",            K_KP_ENTER },
  140         {"KP_INS",                      K_KP_INS },
  141         {"KP_DEL",                      K_KP_DEL },
  142         {"KP_SLASH",            K_KP_SLASH },
  143         {"KP_MINUS",            K_KP_MINUS },
  144         {"KP_PLUS",                     K_KP_PLUS },
  145 
  146         {"MWHEELUP", K_MWHEELUP },
  147         {"MWHEELDOWN", K_MWHEELDOWN },
  148 
  149         {"PAUSE", K_PAUSE},
  150 
  151         {"SEMICOLON", ';'},     // because a raw semicolon seperates commands
  152 
  153         {NULL,0}
  154 };
  155 
  156 /*
  157 ==============================================================================
  158 
  159                         LINE TYPING INTO THE CONSOLE
  160 
  161 ==============================================================================
  162 */
  163 
  164 void CompleteCommand (void)
  165 {
  166         char    *cmd, *s;
  167 
  168         s = key_lines[edit_line]+1;
  169         if (*s == '\\' || *s == '/')
  170                 s++;
  171 
  172         cmd = Cmd_CompleteCommand (s);
  173         if (!cmd)
  174                 cmd = Cvar_CompleteVariable (s);
  175         if (cmd)
  176         {
  177                 key_lines[edit_line][1] = '/';
  178                 strcpy (key_lines[edit_line]+2, cmd);
  179                 key_linepos = strlen(cmd)+2;
  180                 key_lines[edit_line][key_linepos] = ' ';
  181                 key_linepos++;
  182                 key_lines[edit_line][key_linepos] = 0;
  183                 return;
  184         }
  185 }
  186 
  187 /*
  188 ====================
  189 Key_Console
  190 
  191 Interactive line editing and console scrollback
  192 ====================
  193 */
  194 void Key_Console (int key)
  195 {
  196 
  197         switch ( key )
  198         {
  199         case K_KP_SLASH:
  200                 key = '/';
  201                 break;
  202         case K_KP_MINUS:
  203                 key = '-';
  204                 break;
  205         case K_KP_PLUS:
  206                 key = '+';
  207                 break;
  208         case K_KP_HOME:
  209                 key = '7';
  210                 break;
  211         case K_KP_UPARROW:
  212                 key = '8';
  213                 break;
  214         case K_KP_PGUP:
  215                 key = '9';
  216                 break;
  217         case K_KP_LEFTARROW:
  218                 key = '4';
  219                 break;
  220         case K_KP_5:
  221                 key = '5';
  222                 break;
  223         case K_KP_RIGHTARROW:
  224                 key = '6';
  225                 break;
  226         case K_KP_END:
  227                 key = '1';
  228                 break;
  229         case K_KP_DOWNARROW:
  230                 key = '2';
  231                 break;
  232         case K_KP_PGDN:
  233                 key = '3';
  234                 break;
  235         case K_KP_INS:
  236                 key = '0';
  237                 break;
  238         case K_KP_DEL:
  239                 key = '.';
  240                 break;
  241         }
  242 
  243         if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
  244                  ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
  245         {
  246                 char *cbd;
  247                 
  248                 if ( ( cbd = Sys_GetClipboardData() ) != 0 )
  249                 {
  250                         int i;
  251 
  252                         strtok( cbd, "\n\r\b" );
  253 
  254                         i = strlen( cbd );
  255                         if ( i + key_linepos >= MAXCMDLINE)
  256                                 i= MAXCMDLINE - key_linepos;
  257 
  258                         if ( i > 0 )
  259                         {
  260                                 cbd[i]=0;
  261                                 strcat( key_lines[edit_line], cbd );
  262                                 key_linepos += i;
  263                         }
  264                         free( cbd );
  265                 }
  266 
  267                 return;
  268         }
  269 
  270         if ( key == 'l' ) 
  271         {
  272                 if ( keydown[K_CTRL] )
  273                 {
  274                         Cbuf_AddText ("clear\n");
  275                         return;
  276                 }
  277         }
  278 
  279         if ( key == K_ENTER || key == K_KP_ENTER )
  280         {       // backslash text are commands, else chat
  281                 if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
  282                         Cbuf_AddText (key_lines[edit_line]+2);  // skip the >
  283                 else
  284                         Cbuf_AddText (key_lines[edit_line]+1);  // valid command
  285 
  286                 Cbuf_AddText ("\n");
  287                 Com_Printf ("%s\n",key_lines[edit_line]);
  288                 edit_line = (edit_line + 1) & 31;
  289                 history_line = edit_line;
  290                 key_lines[edit_line][0] = ']';
  291                 key_linepos = 1;
  292                 if (cls.state == ca_disconnected)
  293                         SCR_UpdateScreen ();    // force an update, because the command
  294                                                                         // may take some time
  295                 return;
  296         }
  297 
  298         if (key == K_TAB)
  299         {       // command completion
  300                 CompleteCommand ();
  301                 return;
  302         }
  303         
  304         if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
  305         {
  306                 if (key_linepos > 1)
  307                         key_linepos--;
  308                 return;
  309         }
  310 
  311         if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
  312                  ( ( key == 'p' ) && keydown[K_CTRL] ) )
  313         {
  314                 do
  315                 {
  316                         history_line = (history_line - 1) & 31;
  317                 } while (history_line != edit_line
  318                                 && !key_lines[history_line][1]);
  319                 if (history_line == edit_line)
  320                         history_line = (edit_line+1)&31;
  321                 strcpy(key_lines[edit_line], key_lines[history_line]);
  322                 key_linepos = strlen(key_lines[edit_line]);
  323                 return;
  324         }
  325 
  326         if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
  327                  ( ( key == 'n' ) && keydown[K_CTRL] ) )
  328         {
  329                 if (history_line == edit_line) return;
  330                 do
  331                 {
  332                         history_line = (history_line + 1) & 31;
  333                 }
  334                 while (history_line != edit_line
  335                         && !key_lines[history_line][1]);
  336                 if (history_line == edit_line)
  337                 {
  338                         key_lines[edit_line][0] = ']';
  339                         key_linepos = 1;
  340                 }
  341                 else
  342                 {
  343                         strcpy(key_lines[edit_line], key_lines[history_line]);
  344                         key_linepos = strlen(key_lines[edit_line]);
  345                 }
  346                 return;
  347         }
  348 
  349         if (key == K_PGUP || key == K_KP_PGUP )
  350         {
  351                 con.display -= 2;
  352                 return;
  353         }
  354 
  355         if (key == K_PGDN || key == K_KP_PGDN ) 
  356         {
  357                 con.display += 2;
  358                 if (con.display > con.current)
  359                         con.display = con.current;
  360                 return;
  361         }
  362 
  363         if (key == K_HOME || key == K_KP_HOME )
  364         {
  365                 con.display = con.current - con.totallines + 10;
  366                 return;
  367         }
  368 
  369         if (key == K_END || key == K_KP_END )
  370         {
  371                 con.display = con.current;
  372                 return;
  373         }
  374         
  375         if (key < 32 || key > 127)
  376                 return; // non printable
  377                 
  378         if (key_linepos < MAXCMDLINE-1)
  379         {
  380                 key_lines[edit_line][key_linepos] = key;
  381                 key_linepos++;
  382                 key_lines[edit_line][key_linepos] = 0;
  383         }
  384 
  385 }
  386 
  387 //============================================================================
  388 
  389 qboolean        chat_team;
  390 char            chat_buffer[MAXCMDLINE];
  391 int                     chat_bufferlen = 0;
  392 
  393 void Key_Message (int key)
  394 {
  395 
  396         if ( key == K_ENTER || key == K_KP_ENTER )
  397         {
  398                 if (chat_team)
  399                         Cbuf_AddText ("say_team \"");
  400                 else
  401                         Cbuf_AddText ("say \"");
  402                 Cbuf_AddText(chat_buffer);
  403                 Cbuf_AddText("\"\n");
  404 
  405                 cls.key_dest = key_game;
  406                 chat_bufferlen = 0;
  407                 chat_buffer[0] = 0;
  408                 return;
  409         }
  410 
  411         if (key == K_ESCAPE)
  412         {
  413                 cls.key_dest = key_game;
  414                 chat_bufferlen = 0;
  415                 chat_buffer[0] = 0;
  416                 return;
  417         }
  418 
  419         if (key < 32 || key > 127)
  420                 return; // non printable
  421 
  422         if (key == K_BACKSPACE)
  423         {
  424                 if (chat_bufferlen)
  425                 {
  426                         chat_bufferlen--;
  427                         chat_buffer[chat_bufferlen] = 0;
  428                 }
  429                 return;
  430         }
  431 
  432         if (chat_bufferlen == sizeof(chat_buffer)-1)
  433                 return; // all full
  434 
  435         chat_buffer[chat_bufferlen++] = key;
  436         chat_buffer[chat_bufferlen] = 0;
  437 }
  438 
  439 //============================================================================
  440 
  441 
  442 /*
  443 ===================
  444 Key_StringToKeynum
  445 
  446 Returns a key number to be used to index keybindings[] by looking at
  447 the given string.  Single ascii characters return themselves, while
  448 the K_* names are matched up.
  449 ===================
  450 */
  451 int Key_StringToKeynum (char *str)
  452 {
  453         keyname_t       *kn;
  454         
  455         if (!str || !str[0])
  456                 return -1;
  457         if (!str[1])
  458                 return str[0];
  459 
  460         for (kn=keynames ; kn->name ; kn++)
  461         {
  462                 if (!Q_strcasecmp(str,kn->name))
  463                         return kn->keynum;
  464         }
  465         return -1;
  466 }
  467 
  468 /*
  469 ===================
  470 Key_KeynumToString
  471 
  472 Returns a string (either a single ascii char, or a K_* name) for the
  473 given keynum.
  474 FIXME: handle quote special (general escape sequence?)
  475 ===================
  476 */
  477 char *Key_KeynumToString (int keynum)
  478 {
  479         keyname_t       *kn;    
  480         static  char    tinystr[2];
  481         
  482         if (keynum == -1)
  483                 return "<KEY NOT FOUND>";
  484         if (keynum > 32 && keynum < 127)
  485         {       // printable ascii
  486                 tinystr[0] = keynum;
  487                 tinystr[1] = 0;
  488                 return tinystr;
  489         }
  490         
  491         for (kn=keynames ; kn->name ; kn++)
  492                 if (keynum == kn->keynum)
  493                         return kn->name;
  494 
  495         return "<UNKNOWN KEYNUM>";
  496 }
  497 
  498 
  499 /*
  500 ===================
  501 Key_SetBinding
  502 ===================
  503 */
  504 void Key_SetBinding (int keynum, char *binding)
  505 {
  506         char    *new;
  507         int             l;
  508                         
  509         if (keynum == -1)
  510                 return;
  511 
  512 // free old bindings
  513         if (keybindings[keynum])
  514         {
  515                 Z_Free (keybindings[keynum]);
  516                 keybindings[keynum] = NULL;
  517         }
  518                         
  519 // allocate memory for new binding
  520         l = strlen (binding);   
  521         new = Z_Malloc (l+1);
  522         strcpy (new, binding);
  523         new[l] = 0;
  524         keybindings[keynum] = new;      
  525 }
  526 
  527 /*
  528 ===================
  529 Key_Unbind_f
  530 ===================
  531 */
  532 void Key_Unbind_f (void)
  533 {
  534         int             b;
  535 
  536         if (Cmd_Argc() != 2)
  537         {
  538                 Com_Printf ("unbind <key> : remove commands from a key\n");
  539                 return;
  540         }
  541         
  542         b = Key_StringToKeynum (Cmd_Argv(1));
  543         if (b==-1)
  544         {
  545                 Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  546                 return;
  547         }
  548 
  549         Key_SetBinding (b, "");
  550 }
  551 
  552 void Key_Unbindall_f (void)
  553 {
  554         int             i;
  555         
  556         for (i=0 ; i<256 ; i++)
  557                 if (keybindings[i])
  558                         Key_SetBinding (i, "");
  559 }
  560 
  561 
  562 /*
  563 ===================
  564 Key_Bind_f
  565 ===================
  566 */
  567 void Key_Bind_f (void)
  568 {
  569         int                     i, c, b;
  570         char            cmd[1024];
  571         
  572         c = Cmd_Argc();
  573 
  574         if (c < 2)
  575         {
  576                 Com_Printf ("bind <key> [command] : attach a command to a key\n");
  577                 return;
  578         }
  579         b = Key_StringToKeynum (Cmd_Argv(1));
  580         if (b==-1)
  581         {
  582                 Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  583                 return;
  584         }
  585 
  586         if (c == 2)
  587         {
  588                 if (keybindings[b])
  589                         Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
  590                 else
  591                         Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
  592                 return;
  593         }
  594         
  595 // copy the rest of the command line
  596         cmd[0] = 0;             // start out with a null string
  597         for (i=2 ; i< c ; i++)
  598         {
  599                 strcat (cmd, Cmd_Argv(i));
  600                 if (i != (c-1))
  601                         strcat (cmd, " ");
  602         }
  603 
  604         Key_SetBinding (b, cmd);
  605 }
  606 
  607 /*
  608 ============
  609 Key_WriteBindings
  610 
  611 Writes lines containing "bind key value"
  612 ============
  613 */
  614 void Key_WriteBindings (FILE *f)
  615 {
  616         int             i;
  617 
  618         for (i=0 ; i<256 ; i++)
  619                 if (keybindings[i] && keybindings[i][0])
  620                         fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
  621 }
  622 
  623 
  624 /*
  625 ============
  626 Key_Bindlist_f
  627 
  628 ============
  629 */
  630 void Key_Bindlist_f (void)
  631 {
  632         int             i;
  633 
  634         for (i=0 ; i<256 ; i++)
  635                 if (keybindings[i] && keybindings[i][0])
  636                         Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
  637 }
  638 
  639 
  640 /*
  641 ===================
  642 Key_Init
  643 ===================
  644 */
  645 void Key_Init (void)
  646 {
  647         int             i;
  648 
  649         for (i=0 ; i<32 ; i++)
  650         {
  651                 key_lines[i][0] = ']';
  652                 key_lines[i][1] = 0;
  653         }
  654         key_linepos = 1;
  655         
  656 //
  657 // init ascii characters in console mode
  658 //
  659         for (i=32 ; i<128 ; i++)
  660                 consolekeys[i] = true;
  661         consolekeys[K_ENTER] = true;
  662         consolekeys[K_KP_ENTER] = true;
  663         consolekeys[K_TAB] = true;
  664         consolekeys[K_LEFTARROW] = true;
  665         consolekeys[K_KP_LEFTARROW] = true;
  666         consolekeys[K_RIGHTARROW] = true;
  667         consolekeys[K_KP_RIGHTARROW] = true;
  668         consolekeys[K_UPARROW] = true;
  669         consolekeys[K_KP_UPARROW] = true;
  670         consolekeys[K_DOWNARROW] = true;
  671         consolekeys[K_KP_DOWNARROW] = true;
  672         consolekeys[K_BACKSPACE] = true;
  673         consolekeys[K_HOME] = true;
  674         consolekeys[K_KP_HOME] = true;
  675         consolekeys[K_END] = true;
  676         consolekeys[K_KP_END] = true;
  677         consolekeys[K_PGUP] = true;
  678         consolekeys[K_KP_PGUP] = true;
  679         consolekeys[K_PGDN] = true;
  680         consolekeys[K_KP_PGDN] = true;
  681         consolekeys[K_SHIFT] = true;
  682         consolekeys[K_INS] = true;
  683         consolekeys[K_KP_INS] = true;
  684         consolekeys[K_KP_DEL] = true;
  685         consolekeys[K_KP_SLASH] = true;
  686         consolekeys[K_KP_PLUS] = true;
  687         consolekeys[K_KP_MINUS] = true;
  688         consolekeys[K_KP_5] = true;
  689 
  690         consolekeys['`'] = false;
  691         consolekeys['~'] = false;
  692 
  693         for (i=0 ; i<256 ; i++)
  694                 keyshift[i] = i;
  695         for (i='a' ; i<='z' ; i++)
  696                 keyshift[i] = i - 'a' + 'A';
  697         keyshift['1'] = '!';
  698         keyshift['2'] = '@';
  699         keyshift['3'] = '#';
  700         keyshift['4'] = '$';
  701         keyshift['5'] = '%';
  702         keyshift['6'] = '^';
  703         keyshift['7'] = '&';
  704         keyshift['8'] = '*';
  705         keyshift['9'] = '(';
  706         keyshift['0'] = ')';
  707         keyshift['-'] = '_';
  708         keyshift['='] = '+';
  709         keyshift[','] = '<';
  710         keyshift['.'] = '>';
  711         keyshift['/'] = '?';
  712         keyshift[';'] = ':';
  713         keyshift['\''] = '"';
  714         keyshift['['] = '{';
  715         keyshift[']'] = '}';
  716         keyshift['`'] = '~';
  717         keyshift['\\'] = '|';
  718 
  719         menubound[K_ESCAPE] = true;
  720         for (i=0 ; i<12 ; i++)
  721                 menubound[K_F1+i] = true;
  722 
  723 //
  724 // register our functions
  725 //
  726         Cmd_AddCommand ("bind",Key_Bind_f);
  727         Cmd_AddCommand ("unbind",Key_Unbind_f);
  728         Cmd_AddCommand ("unbindall",Key_Unbindall_f);
  729         Cmd_AddCommand ("bindlist",Key_Bindlist_f);
  730 }
  731 
  732 /*
  733 ===================
  734 Key_Event
  735 
  736 Called by the system between frames for both key up and key down events
  737 Should NOT be called during an interrupt!
  738 ===================
  739 */
  740 void Key_Event (int key, qboolean down, unsigned time)
  741 {
  742         char    *kb;
  743         char    cmd[1024];
  744 
  745         // hack for modal presses
  746         if (key_waiting == -1)
  747         {
  748                 if (down)
  749                         key_waiting = key;
  750                 return;
  751         }
  752 
  753         // update auto-repeat status
  754         if (down)
  755         {
  756                 key_repeats[key]++;
  757                 if (key != K_BACKSPACE 
  758                         && key != K_PAUSE 
  759                         && key != K_PGUP 
  760                         && key != K_KP_PGUP 
  761                         && key != K_PGDN
  762                         && key != K_KP_PGDN
  763                         && key_repeats[key] > 1)
  764                         return; // ignore most autorepeats
  765                         
  766                 if (key >= 200 && !keybindings[key])
  767                         Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
  768         }
  769         else
  770         {
  771                 key_repeats[key] = 0;
  772         }
  773 
  774         if (key == K_SHIFT)
  775                 shift_down = down;
  776 
  777         // console key is hardcoded, so the user can never unbind it
  778         if (key == '`' || key == '~')
  779         {
  780                 if (!down)
  781                         return;
  782                 Con_ToggleConsole_f ();
  783                 return;
  784         }
  785 
  786         // any key during the attract mode will bring up the menu
  787         if (cl.attractloop && cls.key_dest != key_menu &&
  788                 !(key >= K_F1 && key <= K_F12))
  789                 key = K_ESCAPE;
  790 
  791         // menu key is hardcoded, so the user can never unbind it
  792         if (key == K_ESCAPE)
  793         {
  794                 if (!down)
  795                         return;
  796 
  797                 if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
  798                 {       // put away help computer / inventory
  799                         Cbuf_AddText ("cmd putaway\n");
  800                         return;
  801                 }
  802                 switch (cls.key_dest)
  803                 {
  804                 case key_message:
  805                         Key_Message (key);
  806                         break;
  807                 case key_menu:
  808                         M_Keydown (key);
  809                         break;
  810                 case key_game:
  811                 case key_console:
  812                         M_Menu_Main_f ();
  813                         break;
  814                 default:
  815                         Com_Error (ERR_FATAL, "Bad cls.key_dest");
  816                 }
  817                 return;
  818         }
  819 
  820         // track if any key is down for BUTTON_ANY
  821         keydown[key] = down;
  822         if (down)
  823         {
  824                 if (key_repeats[key] == 1)
  825                         anykeydown++;
  826         }
  827         else
  828         {
  829                 anykeydown--;
  830                 if (anykeydown < 0)
  831                         anykeydown = 0;
  832         }
  833 
  834 //
  835 // key up events only generate commands if the game key binding is
  836 // a button command (leading + sign).  These will occur even in console mode,
  837 // to keep the character from continuing an action started before a console
  838 // switch.  Button commands include the kenum as a parameter, so multiple
  839 // downs can be matched with ups
  840 //
  841         if (!down)
  842         {
  843                 kb = keybindings[key];
  844                 if (kb && kb[0] == '+')
  845                 {
  846                         Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
  847                         Cbuf_AddText (cmd);
  848                 }
  849                 if (keyshift[key] != key)
  850                 {
  851                         kb = keybindings[keyshift[key]];
  852                         if (kb && kb[0] == '+')
  853                         {
  854                                 Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
  855                                 Cbuf_AddText (cmd);
  856                         }
  857                 }
  858                 return;
  859         }
  860 
  861 //
  862 // if not a consolekey, send to the interpreter no matter what mode is
  863 //
  864         if ( (cls.key_dest == key_menu && menubound[key])
  865         || (cls.key_dest == key_console && !consolekeys[key])
  866         || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
  867         {
  868                 kb = keybindings[key];
  869                 if (kb)
  870                 {
  871                         if (kb[0] == '+')
  872                         {       // button commands add keynum and time as a parm
  873                                 Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
  874                                 Cbuf_AddText (cmd);
  875                         }
  876                         else
  877                         {
  878                                 Cbuf_AddText (kb);
  879                                 Cbuf_AddText ("\n");
  880                         }
  881                 }
  882                 return;
  883         }
  884 
  885         if (!down)
  886                 return;         // other systems only care about key down events
  887 
  888         if (shift_down)
  889                 key = keyshift[key];
  890 
  891         switch (cls.key_dest)
  892         {
  893         case key_message:
  894                 Key_Message (key);
  895                 break;
  896         case key_menu:
  897                 M_Keydown (key);
  898                 break;
  899 
  900         case key_game:
  901         case key_console:
  902                 Key_Console (key);
  903                 break;
  904         default:
  905                 Com_Error (ERR_FATAL, "Bad cls.key_dest");
  906         }
  907 }
  908 
  909 /*
  910 ===================
  911 Key_ClearStates
  912 ===================
  913 */
  914 void Key_ClearStates (void)
  915 {
  916         int             i;
  917 
  918         anykeydown = false;
  919 
  920         for (i=0 ; i<256 ; i++)
  921         {
  922                 if ( keydown[i] || key_repeats[i] )
  923                         Key_Event( i, false, 0 );
  924                 keydown[i] = 0;
  925                 key_repeats[i] = 0;
  926         }
  927 }
  928 
  929 
  930 /*
  931 ===================
  932 Key_GetKey
  933 ===================
  934 */
  935 int Key_GetKey (void)
  936 {
  937         key_waiting = -1;
  938 
  939         while (key_waiting == -1)
  940                 Sys_SendKeyEvents ();
  941 
  942         return key_waiting;
  943 }
  944 
  945