mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-12-15 23:11:05 +00:00
1107 lines
20 KiB
C
1107 lines
20 KiB
C
/*
|
|
* Copyright (C) 1997-2001 Id Software, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*
|
|
* =======================================================================
|
|
*
|
|
* Upper layer of the keyboard implementation. This file processes all
|
|
* keyboard events which are generated by the low level keyboard layer.
|
|
* Remeber, that the mouse is handled by the refresher and not by the
|
|
* client!
|
|
*
|
|
* =======================================================================
|
|
*/
|
|
|
|
#include "header/client.h"
|
|
|
|
/*
|
|
* key up events are sent even if in console mode
|
|
*/
|
|
|
|
#define MAXCMDLINE 256
|
|
|
|
char key_lines [ 32 ] [ MAXCMDLINE ];
|
|
int key_linepos;
|
|
int shift_down = false;
|
|
int anykeydown;
|
|
|
|
int edit_line = 0;
|
|
int history_line = 0;
|
|
|
|
int key_waiting;
|
|
char *keybindings [ K_LAST ];
|
|
qboolean consolekeys [ K_LAST ]; /* if true, can't be rebound while in console */
|
|
qboolean menubound [ K_LAST ]; /* if true, can't be rebound while in menu */
|
|
int keyshift [ K_LAST ]; /* key to map to if shift held down in console */
|
|
int key_repeats [ K_LAST ]; /* if > 1, it is autorepeating */
|
|
qboolean keydown [ K_LAST ];
|
|
|
|
qboolean Cmd_IsComplete ( char *cmd );
|
|
|
|
typedef struct
|
|
{
|
|
char *name;
|
|
int keynum;
|
|
} keyname_t;
|
|
|
|
keyname_t keynames[] = {
|
|
{ "TAB", K_TAB },
|
|
{ "ENTER", K_ENTER },
|
|
{ "ESCAPE", K_ESCAPE },
|
|
{ "SPACE", K_SPACE },
|
|
{ "BACKSPACE", K_BACKSPACE },
|
|
{ "UPARROW", K_UPARROW },
|
|
{ "DOWNARROW", K_DOWNARROW },
|
|
{ "LEFTARROW", K_LEFTARROW },
|
|
{ "RIGHTARROW", K_RIGHTARROW },
|
|
|
|
{ "ALT", K_ALT },
|
|
{ "CTRL", K_CTRL },
|
|
{ "SHIFT", K_SHIFT },
|
|
|
|
{ "F1", K_F1 },
|
|
{ "F2", K_F2 },
|
|
{ "F3", K_F3 },
|
|
{ "F4", K_F4 },
|
|
{ "F5", K_F5 },
|
|
{ "F6", K_F6 },
|
|
{ "F7", K_F7 },
|
|
{ "F8", K_F8 },
|
|
{ "F9", K_F9 },
|
|
{ "F10", K_F10 },
|
|
{ "F11", K_F11 },
|
|
{ "F12", K_F12 },
|
|
|
|
{ "INS", K_INS },
|
|
{ "DEL", K_DEL },
|
|
{ "PGDN", K_PGDN },
|
|
{ "PGUP", K_PGUP },
|
|
{ "HOME", K_HOME },
|
|
{ "END", K_END },
|
|
|
|
{ "MOUSE1", K_MOUSE1 },
|
|
{ "MOUSE2", K_MOUSE2 },
|
|
{ "MOUSE3", K_MOUSE3 },
|
|
{ "MOUSE4", K_MOUSE4 },
|
|
{ "MOUSE5", K_MOUSE5 },
|
|
|
|
{ "AUX1", K_AUX1 },
|
|
{ "AUX2", K_AUX2 },
|
|
{ "AUX3", K_AUX3 },
|
|
{ "AUX4", K_AUX4 },
|
|
{ "AUX5", K_AUX5 },
|
|
{ "AUX6", K_AUX6 },
|
|
{ "AUX7", K_AUX7 },
|
|
{ "AUX8", K_AUX8 },
|
|
{ "AUX9", K_AUX9 },
|
|
{ "AUX10", K_AUX10 },
|
|
{ "AUX11", K_AUX11 },
|
|
{ "AUX12", K_AUX12 },
|
|
{ "AUX13", K_AUX13 },
|
|
{ "AUX14", K_AUX14 },
|
|
{ "AUX15", K_AUX15 },
|
|
{ "AUX16", K_AUX16 },
|
|
{ "AUX17", K_AUX17 },
|
|
{ "AUX18", K_AUX18 },
|
|
{ "AUX19", K_AUX19 },
|
|
{ "AUX20", K_AUX20 },
|
|
{ "AUX21", K_AUX21 },
|
|
{ "AUX22", K_AUX22 },
|
|
{ "AUX23", K_AUX23 },
|
|
{ "AUX24", K_AUX24 },
|
|
{ "AUX25", K_AUX25 },
|
|
{ "AUX26", K_AUX26 },
|
|
{ "AUX27", K_AUX27 },
|
|
{ "AUX28", K_AUX28 },
|
|
{ "AUX29", K_AUX29 },
|
|
{ "AUX30", K_AUX30 },
|
|
{ "AUX31", K_AUX31 },
|
|
{ "AUX32", K_AUX32 },
|
|
|
|
{ "KP_HOME", K_KP_HOME },
|
|
{ "KP_UPARROW", K_KP_UPARROW },
|
|
{ "KP_PGUP", K_KP_PGUP },
|
|
{ "KP_LEFTARROW", K_KP_LEFTARROW },
|
|
{ "KP_5", K_KP_5 },
|
|
{ "KP_RIGHTARROW", K_KP_RIGHTARROW },
|
|
{ "KP_END", K_KP_END },
|
|
{ "KP_DOWNARROW", K_KP_DOWNARROW },
|
|
{ "KP_PGDN", K_KP_PGDN },
|
|
{ "KP_ENTER", K_KP_ENTER },
|
|
{ "KP_INS", K_KP_INS },
|
|
{ "KP_DEL", K_KP_DEL },
|
|
{ "KP_SLASH", K_KP_SLASH },
|
|
{ "KP_MINUS", K_KP_MINUS },
|
|
{ "KP_PLUS", K_KP_PLUS },
|
|
|
|
{ "MWHEELUP", K_MWHEELUP },
|
|
{ "MWHEELDOWN", K_MWHEELDOWN },
|
|
|
|
{ "PAUSE", K_PAUSE },
|
|
|
|
{ "SEMICOLON", ';' }, /* because a raw semicolon seperates commands */
|
|
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
void
|
|
CompleteCommand ( void )
|
|
{
|
|
char *cmd, *s;
|
|
|
|
s = key_lines [ edit_line ] + 1;
|
|
|
|
if ( ( *s == '\\' ) || ( *s == '/' ) )
|
|
{
|
|
s++;
|
|
}
|
|
|
|
cmd = Cmd_CompleteCommand( s );
|
|
|
|
if ( cmd )
|
|
{
|
|
key_lines [ edit_line ] [ 1 ] = '/';
|
|
strcpy( key_lines [ edit_line ] + 2, cmd );
|
|
key_linepos = strlen( cmd ) + 2;
|
|
|
|
if ( Cmd_IsComplete( cmd ) )
|
|
{
|
|
key_lines [ edit_line ] [ key_linepos ] = ' ';
|
|
key_linepos++;
|
|
key_lines [ edit_line ] [ key_linepos ] = 0;
|
|
}
|
|
else
|
|
{
|
|
key_lines [ edit_line ] [ key_linepos ] = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Interactive line editing and console scrollback
|
|
*/
|
|
void
|
|
Key_Console ( int key )
|
|
{
|
|
switch ( key )
|
|
{
|
|
case K_KP_SLASH:
|
|
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;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( key == 'l' )
|
|
{
|
|
if ( keydown [ K_CTRL ] )
|
|
{
|
|
Cbuf_AddText( "clear\n" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( ( key == K_ENTER ) || ( key == K_KP_ENTER ) )
|
|
{
|
|
/* slash text are commands, else chat */
|
|
if ( ( key_lines [ edit_line ] [ 1 ] == '\\' ) || ( key_lines [ edit_line ] [ 1 ] == '/' ) )
|
|
{
|
|
Cbuf_AddText( key_lines [ edit_line ] + 2 ); /* skip the > */
|
|
}
|
|
else
|
|
{
|
|
Cbuf_AddText( key_lines [ edit_line ] + 1 ); /* valid command */
|
|
}
|
|
|
|
Cbuf_AddText( "\n" );
|
|
Com_Printf( "%s\n", key_lines [ edit_line ] );
|
|
edit_line = ( edit_line + 1 ) & 31;
|
|
history_line = edit_line;
|
|
key_lines [ edit_line ] [ 0 ] = ']';
|
|
key_linepos = 1;
|
|
|
|
if ( cls.state == ca_disconnected )
|
|
{
|
|
SCR_UpdateScreen(); /* force an update, because the command may take some time */
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( key == K_TAB )
|
|
{
|
|
/* command completion */
|
|
CompleteCommand();
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) ||
|
|
( ( key == 'h' ) && ( keydown [ K_CTRL ] ) ) )
|
|
{
|
|
if ( key_linepos > 1 )
|
|
{
|
|
key_linepos--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( key == K_DEL )
|
|
{
|
|
memmove( key_lines [ edit_line ] + key_linepos, key_lines [ edit_line ] + key_linepos + 1,
|
|
sizeof ( key_lines [ edit_line ] ) - key_linepos - 1 );
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
|
|
( ( key == 'p' ) && keydown [ K_CTRL ] ) )
|
|
{
|
|
do
|
|
{
|
|
history_line = ( history_line - 1 ) & 31;
|
|
}
|
|
while ( history_line != edit_line &&
|
|
!key_lines [ history_line ] [ 1 ] );
|
|
|
|
if ( history_line == edit_line )
|
|
{
|
|
history_line = ( edit_line + 1 ) & 31;
|
|
}
|
|
|
|
strcpy( key_lines [ edit_line ], key_lines [ history_line ] );
|
|
key_linepos = (int) strlen( key_lines [ edit_line ] );
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
|
|
( ( key == 'n' ) && keydown [ K_CTRL ] ) )
|
|
{
|
|
if ( history_line == edit_line )
|
|
{
|
|
return;
|
|
}
|
|
|
|
do
|
|
{
|
|
history_line = ( history_line + 1 ) & 31;
|
|
}
|
|
while ( history_line != edit_line &&
|
|
!key_lines [ history_line ] [ 1 ] );
|
|
|
|
if ( history_line == edit_line )
|
|
{
|
|
key_lines [ edit_line ] [ 0 ] = ']';
|
|
key_linepos = 1;
|
|
}
|
|
else
|
|
{
|
|
strcpy( key_lines [ edit_line ], key_lines [ history_line ] );
|
|
key_linepos = (int) strlen( key_lines [ edit_line ] );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_PGUP ) || ( key == K_KP_PGUP ) || ( key == K_MWHEELUP ) || ( key == K_MOUSE4 ) )
|
|
{
|
|
con.display -= 2;
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_PGDN ) || ( key == K_KP_PGDN ) || ( key == K_MWHEELDOWN ) || ( key == K_MOUSE5 ) )
|
|
{
|
|
con.display += 2;
|
|
|
|
if ( con.display > con.current )
|
|
{
|
|
con.display = con.current;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_HOME ) || ( key == K_KP_HOME ) )
|
|
{
|
|
if ( keydown [ K_CTRL ] )
|
|
{
|
|
con.display = con.current - con.totallines + 10;
|
|
}
|
|
|
|
else
|
|
{
|
|
key_linepos = 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( key == K_END ) || ( key == K_KP_END ) )
|
|
{
|
|
if ( keydown [ K_CTRL ] )
|
|
{
|
|
con.display = con.current;
|
|
}
|
|
|
|
else
|
|
{
|
|
key_linepos = (int) strlen( key_lines [ edit_line ] );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( key < 32 ) || ( key > 127 ) )
|
|
{
|
|
return; /* non printable character */
|
|
}
|
|
|
|
if ( key_linepos < MAXCMDLINE - 1 )
|
|
{
|
|
int last;
|
|
int length;
|
|
|
|
length = strlen( key_lines [ edit_line ] );
|
|
|
|
if ( length >= MAXCMDLINE - 1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
last = key_lines [ edit_line ] [ key_linepos ];
|
|
|
|
memmove( key_lines [ edit_line ] + key_linepos + 1, key_lines [ edit_line ] + key_linepos, length - key_linepos );
|
|
|
|
key_lines [ edit_line ] [ key_linepos ] = key;
|
|
key_linepos++;
|
|
|
|
if ( !last )
|
|
{
|
|
key_lines [ edit_line ] [ key_linepos ] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
qboolean chat_team;
|
|
char chat_buffer [ MAXCMDLINE ];
|
|
int chat_bufferlen = 0;
|
|
int chat_cursorpos = 0;
|
|
|
|
void
|
|
Key_Message ( int key )
|
|
{
|
|
char last;
|
|
|
|
if ( ( key == K_ENTER ) || ( key == K_KP_ENTER ) )
|
|
{
|
|
if ( chat_team )
|
|
{
|
|
Cbuf_AddText( "say_team \"" );
|
|
}
|
|
|
|
else
|
|
{
|
|
Cbuf_AddText( "say \"" );
|
|
}
|
|
|
|
Cbuf_AddText( chat_buffer );
|
|
Cbuf_AddText( "\"\n" );
|
|
|
|
cls.key_dest = key_game;
|
|
chat_bufferlen = 0;
|
|
chat_buffer [ 0 ] = 0;
|
|
chat_cursorpos = 0;
|
|
return;
|
|
}
|
|
|
|
if ( key == K_ESCAPE )
|
|
{
|
|
cls.key_dest = key_game;
|
|
chat_cursorpos = 0;
|
|
chat_bufferlen = 0;
|
|
chat_buffer [ 0 ] = 0;
|
|
return;
|
|
}
|
|
|
|
if ( key == K_BACKSPACE )
|
|
{
|
|
if ( chat_cursorpos )
|
|
{
|
|
memmove( chat_buffer + chat_cursorpos - 1, chat_buffer + chat_cursorpos, chat_bufferlen - chat_cursorpos + 1 );
|
|
chat_cursorpos--;
|
|
chat_bufferlen--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( key == K_DEL )
|
|
{
|
|
if ( chat_bufferlen && ( chat_cursorpos != chat_bufferlen ) )
|
|
{
|
|
memmove( chat_buffer + chat_cursorpos, chat_buffer + chat_cursorpos + 1, chat_bufferlen - chat_cursorpos + 1 );
|
|
chat_bufferlen--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( key == K_LEFTARROW )
|
|
{
|
|
if ( chat_cursorpos > 0 )
|
|
{
|
|
chat_cursorpos--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( key == K_HOME )
|
|
{
|
|
chat_cursorpos = 0;
|
|
return;
|
|
}
|
|
|
|
if ( key == K_END )
|
|
{
|
|
chat_cursorpos = chat_bufferlen;
|
|
return;
|
|
}
|
|
|
|
if ( key == K_RIGHTARROW )
|
|
{
|
|
if ( chat_buffer [ chat_cursorpos ] )
|
|
{
|
|
chat_cursorpos++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( key < 32 ) || ( key > 127 ) )
|
|
{
|
|
return; /* non printable charcter */
|
|
}
|
|
|
|
if ( chat_bufferlen == sizeof ( chat_buffer ) - 1 )
|
|
{
|
|
return; /* all full, this should never happen on modern systems */
|
|
}
|
|
|
|
memmove( chat_buffer + chat_cursorpos + 1, chat_buffer + chat_cursorpos, chat_bufferlen - chat_cursorpos + 1 );
|
|
|
|
last = chat_buffer [ chat_cursorpos ];
|
|
|
|
chat_buffer [ chat_cursorpos ] = key;
|
|
|
|
chat_bufferlen++;
|
|
chat_cursorpos++;
|
|
|
|
if ( !last )
|
|
{
|
|
chat_buffer [ chat_cursorpos ] = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns a key number to be used to index keybindings[] by looking at
|
|
* the given string. Single ascii characters return themselves, while
|
|
* the K_* names are matched up.
|
|
*/
|
|
int
|
|
Key_StringToKeynum ( char *str )
|
|
{
|
|
keyname_t *kn;
|
|
|
|
if ( !str || !str [ 0 ] )
|
|
{
|
|
return ( -1 );
|
|
}
|
|
|
|
if ( !str [ 1 ] )
|
|
{
|
|
return ( str [ 0 ] );
|
|
}
|
|
|
|
for ( kn = keynames; kn->name; kn++ )
|
|
{
|
|
if ( !Q_stricmp( str, kn->name ) )
|
|
{
|
|
return ( kn->keynum );
|
|
}
|
|
}
|
|
|
|
return ( -1 );
|
|
}
|
|
|
|
/*
|
|
* Returns a string (either a single ascii char, or a K_* name) for the
|
|
* given keynum.
|
|
*/
|
|
char *
|
|
Key_KeynumToString ( int keynum )
|
|
{
|
|
keyname_t *kn;
|
|
static char tinystr [ 2 ] = { 0 };
|
|
|
|
if ( keynum == -1 )
|
|
{
|
|
return ( "<KEY NOT FOUND>" );
|
|
}
|
|
|
|
if ( ( keynum > 32 ) && ( keynum < 127 ) )
|
|
{
|
|
/* printable ascii */
|
|
tinystr [ 0 ] = keynum;
|
|
return ( tinystr );
|
|
}
|
|
|
|
for ( kn = keynames; kn->name; kn++ )
|
|
{
|
|
if ( keynum == kn->keynum )
|
|
{
|
|
return ( kn->name );
|
|
}
|
|
}
|
|
|
|
return ( "<UNKNOWN KEYNUM>" );
|
|
}
|
|
|
|
void
|
|
Key_SetBinding ( int keynum, char *binding )
|
|
{
|
|
char *new;
|
|
int l;
|
|
|
|
if ( keynum == -1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* free old bindings */
|
|
if ( keybindings [ keynum ] )
|
|
{
|
|
Z_Free( keybindings [ keynum ] );
|
|
keybindings [ keynum ] = NULL;
|
|
}
|
|
|
|
/* allocate memory for new binding */
|
|
l = strlen( binding );
|
|
new = Z_Malloc( l + 1 );
|
|
strcpy( new, binding );
|
|
new [ l ] = 0;
|
|
keybindings [ keynum ] = new;
|
|
}
|
|
|
|
void
|
|
Key_Unbind_f ( void )
|
|
{
|
|
int b;
|
|
|
|
if ( Cmd_Argc() != 2 )
|
|
{
|
|
Com_Printf( "unbind <key> : remove commands from a key\n" );
|
|
return;
|
|
}
|
|
|
|
b = Key_StringToKeynum( Cmd_Argv( 1 ) );
|
|
|
|
if ( b == -1 )
|
|
{
|
|
Com_Printf( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ) );
|
|
return;
|
|
}
|
|
|
|
Key_SetBinding( b, "" );
|
|
}
|
|
|
|
void
|
|
Key_Unbindall_f ( void )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < K_LAST; i++ )
|
|
{
|
|
if ( keybindings [ i ] )
|
|
{
|
|
Key_SetBinding( i, "" );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Key_Bind_f ( void )
|
|
{
|
|
int i, c, b;
|
|
char cmd [ 1024 ];
|
|
|
|
c = Cmd_Argc();
|
|
|
|
if ( c < 2 )
|
|
{
|
|
Com_Printf( "bind <key> [command] : attach a command to a key\n" );
|
|
return;
|
|
}
|
|
|
|
b = Key_StringToKeynum( Cmd_Argv( 1 ) );
|
|
|
|
if ( b == -1 )
|
|
{
|
|
Com_Printf( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ) );
|
|
return;
|
|
}
|
|
|
|
if ( c == 2 )
|
|
{
|
|
if ( keybindings [ b ] )
|
|
{
|
|
Com_Printf( "\"%s\" = \"%s\"\n", Cmd_Argv( 1 ), keybindings [ b ] );
|
|
}
|
|
|
|
else
|
|
{
|
|
Com_Printf( "\"%s\" is not bound\n", Cmd_Argv( 1 ) );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* copy the rest of the command line */
|
|
cmd [ 0 ] = 0; /* start out with a null string */
|
|
|
|
for ( i = 2; i < c; i++ )
|
|
{
|
|
strcat( cmd, Cmd_Argv( i ) );
|
|
|
|
if ( i != ( c - 1 ) )
|
|
{
|
|
strcat( cmd, " " );
|
|
}
|
|
}
|
|
|
|
Key_SetBinding( b, cmd );
|
|
}
|
|
|
|
/*
|
|
* Writes lines containing "bind key value"
|
|
*/
|
|
void
|
|
Key_WriteBindings ( FILE *f )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < K_LAST; i++ )
|
|
{
|
|
if ( keybindings [ i ] && keybindings [ i ] [ 0 ] )
|
|
{
|
|
fprintf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ), keybindings [ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Key_Bindlist_f ( void )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < K_LAST; i++ )
|
|
{
|
|
if ( keybindings [ i ] && keybindings [ i ] [ 0 ] )
|
|
{
|
|
Com_Printf( "%s \"%s\"\n", Key_KeynumToString( i ), keybindings [ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Key_Init ( void )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < 32; i++ )
|
|
{
|
|
key_lines [ i ] [ 0 ] = ']';
|
|
key_lines [ i ] [ 1 ] = 0;
|
|
}
|
|
|
|
key_linepos = 1;
|
|
|
|
/* init 128 bit ascii characters in console mode */
|
|
for ( i = 32; i < 128; i++ )
|
|
{
|
|
consolekeys [ i ] = true;
|
|
}
|
|
|
|
consolekeys [ K_ENTER ] = true;
|
|
consolekeys [ K_KP_ENTER ] = true;
|
|
consolekeys [ K_TAB ] = true;
|
|
consolekeys [ K_LEFTARROW ] = true;
|
|
consolekeys [ K_KP_LEFTARROW ] = true;
|
|
consolekeys [ K_RIGHTARROW ] = true;
|
|
consolekeys [ K_KP_RIGHTARROW ] = true;
|
|
consolekeys [ K_UPARROW ] = true;
|
|
consolekeys [ K_KP_UPARROW ] = true;
|
|
consolekeys [ K_DOWNARROW ] = true;
|
|
consolekeys [ K_KP_DOWNARROW ] = true;
|
|
consolekeys [ K_BACKSPACE ] = true;
|
|
consolekeys [ K_HOME ] = true;
|
|
consolekeys [ K_KP_HOME ] = true;
|
|
consolekeys [ K_END ] = true;
|
|
consolekeys [ K_KP_END ] = true;
|
|
consolekeys [ K_PGUP ] = true;
|
|
consolekeys [ K_KP_PGUP ] = true;
|
|
consolekeys [ K_PGDN ] = true;
|
|
consolekeys [ K_KP_PGDN ] = true;
|
|
consolekeys [ K_SHIFT ] = true;
|
|
consolekeys [ K_INS ] = true;
|
|
consolekeys [ K_KP_INS ] = true;
|
|
consolekeys [ K_KP_DEL ] = true;
|
|
consolekeys [ K_KP_SLASH ] = true;
|
|
consolekeys [ K_KP_PLUS ] = true;
|
|
consolekeys [ K_KP_MINUS ] = true;
|
|
consolekeys [ K_KP_5 ] = true;
|
|
|
|
consolekeys [ '`' ] = false;
|
|
consolekeys [ '~' ] = false;
|
|
consolekeys [ '^' ] = false;
|
|
|
|
for ( i = 0; i < K_LAST; i++ )
|
|
{
|
|
keyshift [ i ] = i;
|
|
}
|
|
|
|
for ( i = 'a'; i <= 'z'; i++ )
|
|
{
|
|
keyshift [ i ] = i - 'a' + 'A';
|
|
}
|
|
|
|
keyshift [ '1' ] = '!';
|
|
keyshift [ '2' ] = '@';
|
|
keyshift [ '3' ] = '#';
|
|
keyshift [ '4' ] = '$';
|
|
keyshift [ '5' ] = '%';
|
|
keyshift [ '6' ] = '^';
|
|
keyshift [ '7' ] = '&';
|
|
keyshift [ '8' ] = '*';
|
|
keyshift [ '9' ] = '(';
|
|
keyshift [ '0' ] = ')';
|
|
keyshift [ '-' ] = '_';
|
|
keyshift [ '=' ] = '+';
|
|
keyshift [ ',' ] = '<';
|
|
keyshift [ '.' ] = '>';
|
|
keyshift [ '/' ] = '?';
|
|
keyshift [ ';' ] = ':';
|
|
keyshift [ '\'' ] = '"';
|
|
keyshift [ '[' ] = '{';
|
|
keyshift [ ']' ] = '}';
|
|
keyshift [ '`' ] = '~';
|
|
keyshift [ '\\' ] = '|';
|
|
|
|
menubound [ K_ESCAPE ] = true;
|
|
|
|
for ( i = 0; i < 12; i++ )
|
|
{
|
|
menubound [ K_F1 + i ] = true;
|
|
}
|
|
|
|
/* register our functions */
|
|
Cmd_AddCommand( "bind", Key_Bind_f );
|
|
Cmd_AddCommand( "unbind", Key_Unbind_f );
|
|
Cmd_AddCommand( "unbindall", Key_Unbindall_f );
|
|
Cmd_AddCommand( "bindlist", Key_Bindlist_f );
|
|
}
|
|
|
|
/*
|
|
* 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, 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 ] && ( cls.key_dest != key_console ) )
|
|
{
|
|
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 == '~' ) || ( key == '`' ) )
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* 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_sprintf( 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_sprintf( 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 ( ( ( 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 )
|
|
{
|
|
if ( kb [ 0 ] == '+' )
|
|
{
|
|
/* button commands add keynum and time as a parm */
|
|
Com_sprintf( 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 ( 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" );
|
|
}
|
|
}
|
|
|
|
void
|
|
Key_ClearStates ( void )
|
|
{
|
|
int i;
|
|
|
|
anykeydown = false;
|
|
|
|
for ( i = 0; i < K_LAST; i++ )
|
|
{
|
|
if ( keydown [ i ] || key_repeats [ i ] )
|
|
{
|
|
Key_Event( i, false, 0 );
|
|
}
|
|
|
|
keydown [ i ] = 0;
|
|
key_repeats [ i ] = 0;
|
|
}
|
|
}
|
|
|
|
int
|
|
Key_GetKey ( void )
|
|
{
|
|
key_waiting = -1;
|
|
|
|
while ( key_waiting == -1 )
|
|
{
|
|
Sys_SendKeyEvents();
|
|
}
|
|
|
|
return ( key_waiting );
|
|
}
|
|
|