home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / keys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  16.3 KB  |  840 lines

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