12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code 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.
- Quake III Arena source code 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 Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "client.h"
- /*
- key up events are sent even if in console mode
- */
- field_t historyEditLines[COMMAND_HISTORY];
- int nextHistoryLine; // the last line in the history buffer, not masked
- int historyLine; // the line being displayed from history buffer
- // will be <= nextHistoryLine
- field_t g_consoleField;
- field_t chatField;
- qboolean chat_team;
- int chat_playerNum;
- qboolean key_overstrikeMode;
- qboolean anykeydown;
- qkey_t keys[MAX_KEYS];
- typedef struct {
- char *name;
- int keynum;
- } keyname_t;
- // names not in this list can either be lowercase ascii, or '0xnn' hex sequences
- 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},
- {"COMMAND", K_COMMAND},
- {"CAPSLOCK", K_CAPSLOCK},
-
- {"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},
- {"MWHEELUP", K_MWHEELUP },
- {"MWHEELDOWN", K_MWHEELDOWN },
- {"JOY1", K_JOY1},
- {"JOY2", K_JOY2},
- {"JOY3", K_JOY3},
- {"JOY4", K_JOY4},
- {"JOY5", K_JOY5},
- {"JOY6", K_JOY6},
- {"JOY7", K_JOY7},
- {"JOY8", K_JOY8},
- {"JOY9", K_JOY9},
- {"JOY10", K_JOY10},
- {"JOY11", K_JOY11},
- {"JOY12", K_JOY12},
- {"JOY13", K_JOY13},
- {"JOY14", K_JOY14},
- {"JOY15", K_JOY15},
- {"JOY16", K_JOY16},
- {"JOY17", K_JOY17},
- {"JOY18", K_JOY18},
- {"JOY19", K_JOY19},
- {"JOY20", K_JOY20},
- {"JOY21", K_JOY21},
- {"JOY22", K_JOY22},
- {"JOY23", K_JOY23},
- {"JOY24", K_JOY24},
- {"JOY25", K_JOY25},
- {"JOY26", K_JOY26},
- {"JOY27", K_JOY27},
- {"JOY28", K_JOY28},
- {"JOY29", K_JOY29},
- {"JOY30", K_JOY30},
- {"JOY31", K_JOY31},
- {"JOY32", K_JOY32},
- {"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},
- {"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 },
- {"KP_NUMLOCK", K_KP_NUMLOCK },
- {"KP_STAR", K_KP_STAR },
- {"KP_EQUALS", K_KP_EQUALS },
- {"PAUSE", K_PAUSE},
-
- {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
- {NULL,0}
- };
- /*
- =============================================================================
- EDIT FIELDS
- =============================================================================
- */
- /*
- ===================
- Field_Draw
- Handles horizontal scrolling and cursor blinking
- x, y, amd width are in pixels
- ===================
- */
- void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor ) {
- int len;
- int drawLen;
- int prestep;
- int cursorChar;
- char str[MAX_STRING_CHARS];
- int i;
- drawLen = edit->widthInChars;
- len = strlen( edit->buffer ) + 1;
- // guarantee that cursor will be visible
- if ( len <= drawLen ) {
- prestep = 0;
- } else {
- if ( edit->scroll + drawLen > len ) {
- edit->scroll = len - drawLen;
- if ( edit->scroll < 0 ) {
- edit->scroll = 0;
- }
- }
- prestep = edit->scroll;
- /*
- if ( edit->cursor < len - drawLen ) {
- prestep = edit->cursor; // cursor at start
- } else {
- prestep = len - drawLen;
- }
- */
- }
- if ( prestep + drawLen > len ) {
- drawLen = len - prestep;
- }
- // extract <drawLen> characters from the field at <prestep>
- if ( drawLen >= MAX_STRING_CHARS ) {
- Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
- }
- Com_Memcpy( str, edit->buffer + prestep, drawLen );
- str[ drawLen ] = 0;
- // draw it
- if ( size == SMALLCHAR_WIDTH ) {
- float color[4];
- color[0] = color[1] = color[2] = color[3] = 1.0;
- SCR_DrawSmallStringExt( x, y, str, color, qfalse );
- } else {
- // draw big string with drop shadow
- SCR_DrawBigString( x, y, str, 1.0 );
- }
- // draw the cursor
- if ( !showCursor ) {
- return;
- }
- if ( (int)( cls.realtime >> 8 ) & 1 ) {
- return; // off blink
- }
- if ( key_overstrikeMode ) {
- cursorChar = 11;
- } else {
- cursorChar = 10;
- }
- i = drawLen - ( Q_PrintStrlen( str ) + 1 );
- if ( size == SMALLCHAR_WIDTH ) {
- SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
- } else {
- str[0] = cursorChar;
- str[1] = 0;
- SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0 );
- }
- }
- void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor )
- {
- Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor );
- }
- void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor )
- {
- Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor );
- }
- /*
- ================
- Field_Paste
- ================
- */
- void Field_Paste( field_t *edit ) {
- char *cbd;
- int pasteLen, i;
- cbd = Sys_GetClipboardData();
- if ( !cbd ) {
- return;
- }
- // send as if typed, so insert / overstrike works properly
- pasteLen = strlen( cbd );
- for ( i = 0 ; i < pasteLen ; i++ ) {
- Field_CharEvent( edit, cbd[i] );
- }
- Z_Free( cbd );
- }
- /*
- =================
- Field_KeyDownEvent
- Performs the basic line editing functions for the console,
- in-game talk, and menu fields
- Key events are used for non-printable characters, others are gotten from char events.
- =================
- */
- void Field_KeyDownEvent( field_t *edit, int key ) {
- int len;
- // shift-insert is paste
- if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {
- Field_Paste( edit );
- return;
- }
- len = strlen( edit->buffer );
- if ( key == K_DEL ) {
- if ( edit->cursor < len ) {
- memmove( edit->buffer + edit->cursor,
- edit->buffer + edit->cursor + 1, len - edit->cursor );
- }
- return;
- }
- if ( key == K_RIGHTARROW )
- {
- if ( edit->cursor < len ) {
- edit->cursor++;
- }
- if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
- {
- edit->scroll++;
- }
- return;
- }
- if ( key == K_LEFTARROW )
- {
- if ( edit->cursor > 0 ) {
- edit->cursor--;
- }
- if ( edit->cursor < edit->scroll )
- {
- edit->scroll--;
- }
- return;
- }
- if ( key == K_HOME || ( tolower(key) == 'a' && keys[K_CTRL].down ) ) {
- edit->cursor = 0;
- return;
- }
- if ( key == K_END || ( tolower(key) == 'e' && keys[K_CTRL].down ) ) {
- edit->cursor = len;
- return;
- }
- if ( key == K_INS ) {
- key_overstrikeMode = !key_overstrikeMode;
- return;
- }
- }
- /*
- ==================
- Field_CharEvent
- ==================
- */
- void Field_CharEvent( field_t *edit, int ch ) {
- int len;
- if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
- Field_Paste( edit );
- return;
- }
- if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
- Field_Clear( edit );
- return;
- }
- len = strlen( edit->buffer );
- if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
- if ( edit->cursor > 0 ) {
- memmove( edit->buffer + edit->cursor - 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->cursor--;
- if ( edit->cursor < edit->scroll )
- {
- edit->scroll--;
- }
- }
- return;
- }
- if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
- edit->cursor = 0;
- edit->scroll = 0;
- return;
- }
- if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
- edit->cursor = len;
- edit->scroll = edit->cursor - edit->widthInChars;
- return;
- }
- //
- // ignore any other non printable chars
- //
- if ( ch < 32 ) {
- return;
- }
- if ( key_overstrikeMode ) {
- if ( edit->cursor == MAX_EDIT_LINE - 1 )
- return;
- edit->buffer[edit->cursor] = ch;
- edit->cursor++;
- } else { // insert mode
- if ( len == MAX_EDIT_LINE - 1 ) {
- return; // all full
- }
- memmove( edit->buffer + edit->cursor + 1,
- edit->buffer + edit->cursor, len + 1 - edit->cursor );
- edit->buffer[edit->cursor] = ch;
- edit->cursor++;
- }
- if ( edit->cursor >= edit->widthInChars ) {
- edit->scroll++;
- }
- if ( edit->cursor == len + 1) {
- edit->buffer[edit->cursor] = 0;
- }
- }
- /*
- =============================================================================
- CONSOLE LINE EDITING
- ==============================================================================
- */
- /*
- ====================
- Console_Key
- Handles history and console scrollback
- ====================
- */
- void Console_Key (int key) {
- // ctrl-L clears screen
- if ( key == 'l' && keys[K_CTRL].down ) {
- Cbuf_AddText ("clear\n");
- return;
- }
- // enter finishes the line
- if ( key == K_ENTER || key == K_KP_ENTER ) {
- // if not in the game explicitly prepent a slash if needed
- if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\'
- && g_consoleField.buffer[0] != '/' ) {
- char temp[MAX_STRING_CHARS];
- Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
- Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
- g_consoleField.cursor++;
- }
- Com_Printf ( "]%s\n", g_consoleField.buffer );
- // leading slash is an explicit command
- if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) {
- Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
- Cbuf_AddText ("\n");
- } else {
- // other text will be chat messages
- if ( !g_consoleField.buffer[0] ) {
- return; // empty lines just scroll the console without adding to history
- } else {
- Cbuf_AddText ("cmd say ");
- Cbuf_AddText( g_consoleField.buffer );
- Cbuf_AddText ("\n");
- }
- }
- // copy line to history buffer
- historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
- nextHistoryLine++;
- historyLine = nextHistoryLine;
- Field_Clear( &g_consoleField );
- g_consoleField.widthInChars = g_console_field_width;
- if ( cls.state == CA_DISCONNECTED ) {
- SCR_UpdateScreen (); // force an update, because the command
- } // may take some time
- return;
- }
- // command completion
- if (key == K_TAB) {
- Field_CompleteCommand(&g_consoleField);
- return;
- }
- // command history (ctrl-p ctrl-n for unix style)
- if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
- ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
- if ( nextHistoryLine - historyLine < COMMAND_HISTORY
- && historyLine > 0 ) {
- historyLine--;
- }
- g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
- return;
- }
- if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
- ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
- if (historyLine == nextHistoryLine)
- return;
- historyLine++;
- g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
- return;
- }
- // console scrolling
- if ( key == K_PGUP ) {
- Con_PageUp();
- return;
- }
- if ( key == K_PGDN) {
- Con_PageDown();
- return;
- }
- if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
- Con_PageUp();
- if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
- Con_PageUp();
- Con_PageUp();
- }
- return;
- }
- if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
- Con_PageDown();
- if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
- Con_PageDown();
- Con_PageDown();
- }
- return;
- }
- // ctrl-home = top of console
- if ( key == K_HOME && keys[K_CTRL].down ) {
- Con_Top();
- return;
- }
- // ctrl-end = bottom of console
- if ( key == K_END && keys[K_CTRL].down ) {
- Con_Bottom();
- return;
- }
- // pass to the normal editline routine
- Field_KeyDownEvent( &g_consoleField, key );
- }
- //============================================================================
- /*
- ================
- Message_Key
- In game talk message
- ================
- */
- void Message_Key( int key ) {
- char buffer[MAX_STRING_CHARS];
- if (key == K_ESCAPE) {
- cls.keyCatchers &= ~KEYCATCH_MESSAGE;
- Field_Clear( &chatField );
- return;
- }
- if ( key == K_ENTER || key == K_KP_ENTER )
- {
- if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
- if (chat_playerNum != -1 )
- Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
- else if (chat_team)
- Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
- else
- Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
- CL_AddReliableCommand( buffer );
- }
- cls.keyCatchers &= ~KEYCATCH_MESSAGE;
- Field_Clear( &chatField );
- return;
- }
- Field_KeyDownEvent( &chatField, key );
- }
- //============================================================================
- qboolean Key_GetOverstrikeMode( void ) {
- return key_overstrikeMode;
- }
- void Key_SetOverstrikeMode( qboolean state ) {
- key_overstrikeMode = state;
- }
- /*
- ===================
- Key_IsDown
- ===================
- */
- qboolean Key_IsDown( int keynum ) {
- if ( keynum == -1 ) {
- return qfalse;
- }
- return keys[keynum].down;
- }
- /*
- ===================
- Key_StringToKeynum
- Returns a key number to be used to index keys[] by looking at
- the given string. Single ascii characters return themselves, while
- the K_* names are matched up.
- 0x11 will be interpreted as raw hex, which will allow new controlers
- to be configured even if they don't have defined names.
- ===================
- */
- int Key_StringToKeynum( char *str ) {
- keyname_t *kn;
-
- if ( !str || !str[0] ) {
- return -1;
- }
- if ( !str[1] ) {
- return str[0];
- }
- // check for hex code
- if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) {
- int n1, n2;
-
- n1 = str[2];
- if ( n1 >= '0' && n1 <= '9' ) {
- n1 -= '0';
- } else if ( n1 >= 'a' && n1 <= 'f' ) {
- n1 = n1 - 'a' + 10;
- } else {
- n1 = 0;
- }
- n2 = str[3];
- if ( n2 >= '0' && n2 <= '9' ) {
- n2 -= '0';
- } else if ( n2 >= 'a' && n2 <= 'f' ) {
- n2 = n2 - 'a' + 10;
- } else {
- n2 = 0;
- }
- return n1 * 16 + n2;
- }
- // scan for a text match
- for ( kn=keynames ; kn->name ; kn++ ) {
- if ( !Q_stricmp( str,kn->name ) )
- return kn->keynum;
- }
- return -1;
- }
- /*
- ===================
- Key_KeynumToString
- Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the
- given keynum.
- ===================
- */
- char *Key_KeynumToString( int keynum ) {
- keyname_t *kn;
- static char tinystr[5];
- int i, j;
- if ( keynum == -1 ) {
- return "<KEY NOT FOUND>";
- }
- if ( keynum < 0 || keynum > 255 ) {
- return "<OUT OF RANGE>";
- }
- // check for printable ascii (don't use quote)
- if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' ) {
- tinystr[0] = keynum;
- tinystr[1] = 0;
- return tinystr;
- }
- // check for a key string
- for ( kn=keynames ; kn->name ; kn++ ) {
- if (keynum == kn->keynum) {
- return kn->name;
- }
- }
- // make a hex string
- i = keynum >> 4;
- j = keynum & 15;
- tinystr[0] = '0';
- tinystr[1] = 'x';
- tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';
- tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';
- tinystr[4] = 0;
- return tinystr;
- }
- /*
- ===================
- Key_SetBinding
- ===================
- */
- void Key_SetBinding( int keynum, const char *binding ) {
- if ( keynum == -1 ) {
- return;
- }
- // free old bindings
- if ( keys[ keynum ].binding ) {
- Z_Free( keys[ keynum ].binding );
- }
-
- // allocate memory for new binding
- keys[keynum].binding = CopyString( binding );
- // consider this like modifying an archived cvar, so the
- // file write will be triggered at the next oportunity
- cvar_modifiedFlags |= CVAR_ARCHIVE;
- }
- /*
- ===================
- Key_GetBinding
- ===================
- */
- char *Key_GetBinding( int keynum ) {
- if ( keynum == -1 ) {
- return "";
- }
- return keys[ keynum ].binding;
- }
- /*
- ===================
- Key_GetKey
- ===================
- */
- int Key_GetKey(const char *binding) {
- int i;
- if (binding) {
- for (i=0 ; i<256 ; i++) {
- if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
- return i;
- }
- }
- }
- return -1;
- }
- /*
- ===================
- Key_Unbind_f
- ===================
- */
- 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, "");
- }
- /*
- ===================
- Key_Unbindall_f
- ===================
- */
- void Key_Unbindall_f (void)
- {
- int i;
-
- for (i=0 ; i<256 ; i++)
- if (keys[i].binding)
- Key_SetBinding (i, "");
- }
- /*
- ===================
- Key_Bind_f
- ===================
- */
- 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 (keys[b].binding)
- Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding );
- 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);
- }
- /*
- ============
- Key_WriteBindings
- Writes lines containing "bind key value"
- ============
- */
- void Key_WriteBindings( fileHandle_t f ) {
- int i;
- FS_Printf (f, "unbindall\n" );
- for (i=0 ; i<256 ; i++) {
- if (keys[i].binding && keys[i].binding[0] ) {
- FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
- }
- }
- }
- /*
- ============
- Key_Bindlist_f
- ============
- */
- void Key_Bindlist_f( void ) {
- int i;
- for ( i = 0 ; i < 256 ; i++ ) {
- if ( keys[i].binding && keys[i].binding[0] ) {
- Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
- }
- }
- }
- /*
- ===================
- CL_InitKeyCommands
- ===================
- */
- void CL_InitKeyCommands( void ) {
- // 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);
- }
- /*
- ===================
- CL_AddKeyUpCommands
- ===================
- */
- void CL_AddKeyUpCommands( int key, char *kb ) {
- int i;
- char button[1024], *buttonPtr;
- char cmd[1024];
- qboolean keyevent;
- if ( !kb ) {
- return;
- }
- keyevent = qfalse;
- buttonPtr = button;
- for ( i = 0; ; i++ ) {
- if ( kb[i] == ';' || !kb[i] ) {
- *buttonPtr = '\0';
- if ( button[0] == '+') {
- // button commands add keynum and time as parms so that multiple
- // sources can be discriminated and subframe corrected
- Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", button+1, key, time);
- Cbuf_AddText (cmd);
- keyevent = qtrue;
- } else {
- if (keyevent) {
- // down-only command
- Cbuf_AddText (button);
- Cbuf_AddText ("\n");
- }
- }
- buttonPtr = button;
- while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {
- i++;
- }
- }
- *buttonPtr++ = kb[i];
- if ( !kb[i] ) {
- break;
- }
- }
- }
- /*
- ===================
- CL_KeyEvent
- Called by the system for both key up and key down events
- ===================
- */
- void CL_KeyEvent (int key, qboolean down, unsigned time) {
- char *kb;
- char cmd[1024];
- // update auto-repeat status and BUTTON_ANY status
- keys[key].down = down;
- if (down) {
- keys[key].repeats++;
- if ( keys[key].repeats == 1) {
- anykeydown++;
- }
- } else {
- keys[key].repeats = 0;
- anykeydown--;
- if (anykeydown < 0) {
- anykeydown = 0;
- }
- }
- #ifdef __linux__
- if (key == K_ENTER)
- {
- if (down)
- {
- if (keys[K_ALT].down)
- {
- Key_ClearStates();
- if (Cvar_VariableValue("r_fullscreen") == 0)
- {
- Com_Printf("Switching to fullscreen rendering\n");
- Cvar_Set("r_fullscreen", "1");
- }
- else
- {
- Com_Printf("Switching to windowed rendering\n");
- Cvar_Set("r_fullscreen", "0");
- }
- Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n");
- return;
- }
- }
- }
- #endif
- // console key is hardcoded, so the user can never unbind it
- if (key == '`' || key == '~') {
- if (!down) {
- return;
- }
- Con_ToggleConsole_f ();
- return;
- }
- // keys can still be used for bound actions
- if ( down && ( key < 128 || key == K_MOUSE1 ) && ( clc.demoplaying || cls.state == CA_CINEMATIC ) && !cls.keyCatchers) {
- if (Cvar_VariableValue ("com_cameraMode") == 0) {
- Cvar_Set ("nextdemo","");
- key = K_ESCAPE;
- }
- }
- // escape is always handled special
- if ( key == K_ESCAPE && down ) {
- if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
- // clear message mode
- Message_Key( key );
- return;
- }
- // escape always gets out of CGAME stuff
- if (cls.keyCatchers & KEYCATCH_CGAME) {
- cls.keyCatchers &= ~KEYCATCH_CGAME;
- VM_Call (cgvm, CG_EVENT_HANDLING, CGAME_EVENT_NONE);
- return;
- }
- if ( !( cls.keyCatchers & KEYCATCH_UI ) ) {
- if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
- }
- else {
- CL_Disconnect_f();
- S_StopAllSounds();
- VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
- }
- return;
- }
- VM_Call( uivm, UI_KEY_EVENT, key, down );
- return;
- }
- //
- // key up events only perform actions if the game key binding is
- // a button command (leading + sign). These will be processed even in
- // console mode and menu mode, to keep the character from continuing
- // an action started before a mode switch.
- //
- if (!down) {
- kb = keys[key].binding;
- CL_AddKeyUpCommands( key, kb );
- if ( cls.keyCatchers & KEYCATCH_UI && uivm ) {
- VM_Call( uivm, UI_KEY_EVENT, key, down );
- } else if ( cls.keyCatchers & KEYCATCH_CGAME && cgvm ) {
- VM_Call( cgvm, CG_KEY_EVENT, key, down );
- }
- return;
- }
- // distribute the key down event to the apropriate handler
- if ( cls.keyCatchers & KEYCATCH_CONSOLE ) {
- Console_Key( key );
- } else if ( cls.keyCatchers & KEYCATCH_UI ) {
- if ( uivm ) {
- VM_Call( uivm, UI_KEY_EVENT, key, down );
- }
- } else if ( cls.keyCatchers & KEYCATCH_CGAME ) {
- if ( cgvm ) {
- VM_Call( cgvm, CG_KEY_EVENT, key, down );
- }
- } else if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
- Message_Key( key );
- } else if ( cls.state == CA_DISCONNECTED ) {
- Console_Key( key );
- } else {
- // send the bound action
- kb = keys[key].binding;
- if ( !kb ) {
- if (key >= 200) {
- Com_Printf ("%s is unbound, use controls menu to set.\n"
- , Key_KeynumToString( key ) );
- }
- } else if (kb[0] == '+') {
- int i;
- char button[1024], *buttonPtr;
- buttonPtr = button;
- for ( i = 0; ; i++ ) {
- if ( kb[i] == ';' || !kb[i] ) {
- *buttonPtr = '\0';
- if ( button[0] == '+') {
- // button commands add keynum and time as parms so that multiple
- // sources can be discriminated and subframe corrected
- Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", button, key, time);
- Cbuf_AddText (cmd);
- } else {
- // down-only command
- Cbuf_AddText (button);
- Cbuf_AddText ("\n");
- }
- buttonPtr = button;
- while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {
- i++;
- }
- }
- *buttonPtr++ = kb[i];
- if ( !kb[i] ) {
- break;
- }
- }
- } else {
- // down-only command
- Cbuf_AddText (kb);
- Cbuf_AddText ("\n");
- }
- }
- }
- /*
- ===================
- CL_CharEvent
- Normal keyboard characters, already shifted / capslocked / etc
- ===================
- */
- void CL_CharEvent( int key ) {
- // the console key should never be used as a char
- if ( key == '`' || key == '~' ) {
- return;
- }
- // distribute the key down event to the apropriate handler
- if ( cls.keyCatchers & KEYCATCH_CONSOLE )
- {
- Field_CharEvent( &g_consoleField, key );
- }
- else if ( cls.keyCatchers & KEYCATCH_UI )
- {
- VM_Call( uivm, UI_KEY_EVENT, key | K_CHAR_FLAG, qtrue );
- }
- else if ( cls.keyCatchers & KEYCATCH_MESSAGE )
- {
- Field_CharEvent( &chatField, key );
- }
- else if ( cls.state == CA_DISCONNECTED )
- {
- Field_CharEvent( &g_consoleField, key );
- }
- }
- /*
- ===================
- Key_ClearStates
- ===================
- */
- void Key_ClearStates (void)
- {
- int i;
- anykeydown = qfalse;
- for ( i=0 ; i < MAX_KEYS ; i++ ) {
- if ( keys[i].down ) {
- CL_KeyEvent( i, qfalse, 0 );
- }
- keys[i].down = 0;
- keys[i].repeats = 0;
- }
- }
|