Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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