cl_keys.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "client.h"
  19. /*
  20. key up events are sent even if in console mode
  21. */
  22. field_t historyEditLines[COMMAND_HISTORY];
  23. int nextHistoryLine; // the last line in the history buffer, not masked
  24. int historyLine; // the line being displayed from history buffer
  25. // will be <= nextHistoryLine
  26. field_t g_consoleField;
  27. field_t chatField;
  28. qboolean chat_team;
  29. int chat_playerNum;
  30. qboolean key_overstrikeMode;
  31. qboolean anykeydown;
  32. qkey_t keys[MAX_KEYS];
  33. typedef struct {
  34. char *name;
  35. int keynum;
  36. } keyname_t;
  37. // names not in this list can either be lowercase ascii, or '0xnn' hex sequences
  38. keyname_t keynames[] =
  39. {
  40. {"TAB", K_TAB},
  41. {"ENTER", K_ENTER},
  42. {"ESCAPE", K_ESCAPE},
  43. {"SPACE", K_SPACE},
  44. {"BACKSPACE", K_BACKSPACE},
  45. {"UPARROW", K_UPARROW},
  46. {"DOWNARROW", K_DOWNARROW},
  47. {"LEFTARROW", K_LEFTARROW},
  48. {"RIGHTARROW", K_RIGHTARROW},
  49. {"ALT", K_ALT},
  50. {"CTRL", K_CTRL},
  51. {"SHIFT", K_SHIFT},
  52. {"COMMAND", K_COMMAND},
  53. {"CAPSLOCK", K_CAPSLOCK},
  54. {"F1", K_F1},
  55. {"F2", K_F2},
  56. {"F3", K_F3},
  57. {"F4", K_F4},
  58. {"F5", K_F5},
  59. {"F6", K_F6},
  60. {"F7", K_F7},
  61. {"F8", K_F8},
  62. {"F9", K_F9},
  63. {"F10", K_F10},
  64. {"F11", K_F11},
  65. {"F12", K_F12},
  66. {"INS", K_INS},
  67. {"DEL", K_DEL},
  68. {"PGDN", K_PGDN},
  69. {"PGUP", K_PGUP},
  70. {"HOME", K_HOME},
  71. {"END", K_END},
  72. {"MOUSE1", K_MOUSE1},
  73. {"MOUSE2", K_MOUSE2},
  74. {"MOUSE3", K_MOUSE3},
  75. {"MOUSE4", K_MOUSE4},
  76. {"MOUSE5", K_MOUSE5},
  77. {"MWHEELUP", K_MWHEELUP },
  78. {"MWHEELDOWN", K_MWHEELDOWN },
  79. {"JOY1", K_JOY1},
  80. {"JOY2", K_JOY2},
  81. {"JOY3", K_JOY3},
  82. {"JOY4", K_JOY4},
  83. {"JOY5", K_JOY5},
  84. {"JOY6", K_JOY6},
  85. {"JOY7", K_JOY7},
  86. {"JOY8", K_JOY8},
  87. {"JOY9", K_JOY9},
  88. {"JOY10", K_JOY10},
  89. {"JOY11", K_JOY11},
  90. {"JOY12", K_JOY12},
  91. {"JOY13", K_JOY13},
  92. {"JOY14", K_JOY14},
  93. {"JOY15", K_JOY15},
  94. {"JOY16", K_JOY16},
  95. {"JOY17", K_JOY17},
  96. {"JOY18", K_JOY18},
  97. {"JOY19", K_JOY19},
  98. {"JOY20", K_JOY20},
  99. {"JOY21", K_JOY21},
  100. {"JOY22", K_JOY22},
  101. {"JOY23", K_JOY23},
  102. {"JOY24", K_JOY24},
  103. {"JOY25", K_JOY25},
  104. {"JOY26", K_JOY26},
  105. {"JOY27", K_JOY27},
  106. {"JOY28", K_JOY28},
  107. {"JOY29", K_JOY29},
  108. {"JOY30", K_JOY30},
  109. {"JOY31", K_JOY31},
  110. {"JOY32", K_JOY32},
  111. {"AUX1", K_AUX1},
  112. {"AUX2", K_AUX2},
  113. {"AUX3", K_AUX3},
  114. {"AUX4", K_AUX4},
  115. {"AUX5", K_AUX5},
  116. {"AUX6", K_AUX6},
  117. {"AUX7", K_AUX7},
  118. {"AUX8", K_AUX8},
  119. {"AUX9", K_AUX9},
  120. {"AUX10", K_AUX10},
  121. {"AUX11", K_AUX11},
  122. {"AUX12", K_AUX12},
  123. {"AUX13", K_AUX13},
  124. {"AUX14", K_AUX14},
  125. {"AUX15", K_AUX15},
  126. {"AUX16", K_AUX16},
  127. {"KP_HOME", K_KP_HOME },
  128. {"KP_UPARROW", K_KP_UPARROW },
  129. {"KP_PGUP", K_KP_PGUP },
  130. {"KP_LEFTARROW", K_KP_LEFTARROW },
  131. {"KP_5", K_KP_5 },
  132. {"KP_RIGHTARROW", K_KP_RIGHTARROW },
  133. {"KP_END", K_KP_END },
  134. {"KP_DOWNARROW", K_KP_DOWNARROW },
  135. {"KP_PGDN", K_KP_PGDN },
  136. {"KP_ENTER", K_KP_ENTER },
  137. {"KP_INS", K_KP_INS },
  138. {"KP_DEL", K_KP_DEL },
  139. {"KP_SLASH", K_KP_SLASH },
  140. {"KP_MINUS", K_KP_MINUS },
  141. {"KP_PLUS", K_KP_PLUS },
  142. {"KP_NUMLOCK", K_KP_NUMLOCK },
  143. {"KP_STAR", K_KP_STAR },
  144. {"KP_EQUALS", K_KP_EQUALS },
  145. {"PAUSE", K_PAUSE},
  146. {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
  147. {NULL,0}
  148. };
  149. /*
  150. =============================================================================
  151. EDIT FIELDS
  152. =============================================================================
  153. */
  154. /*
  155. ===================
  156. Field_Draw
  157. Handles horizontal scrolling and cursor blinking
  158. x, y, amd width are in pixels
  159. ===================
  160. */
  161. void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor ) {
  162. int len;
  163. int drawLen;
  164. int prestep;
  165. int cursorChar;
  166. char str[MAX_STRING_CHARS];
  167. int i;
  168. drawLen = edit->widthInChars;
  169. len = strlen( edit->buffer ) + 1;
  170. // guarantee that cursor will be visible
  171. if ( len <= drawLen ) {
  172. prestep = 0;
  173. } else {
  174. if ( edit->scroll + drawLen > len ) {
  175. edit->scroll = len - drawLen;
  176. if ( edit->scroll < 0 ) {
  177. edit->scroll = 0;
  178. }
  179. }
  180. prestep = edit->scroll;
  181. /*
  182. if ( edit->cursor < len - drawLen ) {
  183. prestep = edit->cursor; // cursor at start
  184. } else {
  185. prestep = len - drawLen;
  186. }
  187. */
  188. }
  189. if ( prestep + drawLen > len ) {
  190. drawLen = len - prestep;
  191. }
  192. // extract <drawLen> characters from the field at <prestep>
  193. if ( drawLen >= MAX_STRING_CHARS ) {
  194. Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
  195. }
  196. Com_Memcpy( str, edit->buffer + prestep, drawLen );
  197. str[ drawLen ] = 0;
  198. // draw it
  199. if ( size == SMALLCHAR_WIDTH ) {
  200. float color[4];
  201. color[0] = color[1] = color[2] = color[3] = 1.0;
  202. SCR_DrawSmallStringExt( x, y, str, color, qfalse );
  203. } else {
  204. // draw big string with drop shadow
  205. SCR_DrawBigString( x, y, str, 1.0 );
  206. }
  207. // draw the cursor
  208. if ( !showCursor ) {
  209. return;
  210. }
  211. if ( (int)( cls.realtime >> 8 ) & 1 ) {
  212. return; // off blink
  213. }
  214. if ( key_overstrikeMode ) {
  215. cursorChar = 11;
  216. } else {
  217. cursorChar = 10;
  218. }
  219. i = drawLen - ( Q_PrintStrlen( str ) + 1 );
  220. if ( size == SMALLCHAR_WIDTH ) {
  221. SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
  222. } else {
  223. str[0] = cursorChar;
  224. str[1] = 0;
  225. SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0 );
  226. }
  227. }
  228. void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor )
  229. {
  230. Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor );
  231. }
  232. void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor )
  233. {
  234. Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor );
  235. }
  236. /*
  237. ================
  238. Field_Paste
  239. ================
  240. */
  241. void Field_Paste( field_t *edit ) {
  242. char *cbd;
  243. int pasteLen, i;
  244. cbd = Sys_GetClipboardData();
  245. if ( !cbd ) {
  246. return;
  247. }
  248. // send as if typed, so insert / overstrike works properly
  249. pasteLen = strlen( cbd );
  250. for ( i = 0 ; i < pasteLen ; i++ ) {
  251. Field_CharEvent( edit, cbd[i] );
  252. }
  253. Z_Free( cbd );
  254. }
  255. /*
  256. =================
  257. Field_KeyDownEvent
  258. Performs the basic line editing functions for the console,
  259. in-game talk, and menu fields
  260. Key events are used for non-printable characters, others are gotten from char events.
  261. =================
  262. */
  263. void Field_KeyDownEvent( field_t *edit, int key ) {
  264. int len;
  265. // shift-insert is paste
  266. if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {
  267. Field_Paste( edit );
  268. return;
  269. }
  270. len = strlen( edit->buffer );
  271. if ( key == K_DEL ) {
  272. if ( edit->cursor < len ) {
  273. memmove( edit->buffer + edit->cursor,
  274. edit->buffer + edit->cursor + 1, len - edit->cursor );
  275. }
  276. return;
  277. }
  278. if ( key == K_RIGHTARROW )
  279. {
  280. if ( edit->cursor < len ) {
  281. edit->cursor++;
  282. }
  283. if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len )
  284. {
  285. edit->scroll++;
  286. }
  287. return;
  288. }
  289. if ( key == K_LEFTARROW )
  290. {
  291. if ( edit->cursor > 0 ) {
  292. edit->cursor--;
  293. }
  294. if ( edit->cursor < edit->scroll )
  295. {
  296. edit->scroll--;
  297. }
  298. return;
  299. }
  300. if ( key == K_HOME || ( tolower(key) == 'a' && keys[K_CTRL].down ) ) {
  301. edit->cursor = 0;
  302. return;
  303. }
  304. if ( key == K_END || ( tolower(key) == 'e' && keys[K_CTRL].down ) ) {
  305. edit->cursor = len;
  306. return;
  307. }
  308. if ( key == K_INS ) {
  309. key_overstrikeMode = !key_overstrikeMode;
  310. return;
  311. }
  312. }
  313. /*
  314. ==================
  315. Field_CharEvent
  316. ==================
  317. */
  318. void Field_CharEvent( field_t *edit, int ch ) {
  319. int len;
  320. if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
  321. Field_Paste( edit );
  322. return;
  323. }
  324. if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
  325. Field_Clear( edit );
  326. return;
  327. }
  328. len = strlen( edit->buffer );
  329. if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
  330. if ( edit->cursor > 0 ) {
  331. memmove( edit->buffer + edit->cursor - 1,
  332. edit->buffer + edit->cursor, len + 1 - edit->cursor );
  333. edit->cursor--;
  334. if ( edit->cursor < edit->scroll )
  335. {
  336. edit->scroll--;
  337. }
  338. }
  339. return;
  340. }
  341. if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
  342. edit->cursor = 0;
  343. edit->scroll = 0;
  344. return;
  345. }
  346. if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
  347. edit->cursor = len;
  348. edit->scroll = edit->cursor - edit->widthInChars;
  349. return;
  350. }
  351. //
  352. // ignore any other non printable chars
  353. //
  354. if ( ch < 32 ) {
  355. return;
  356. }
  357. if ( key_overstrikeMode ) {
  358. if ( edit->cursor == MAX_EDIT_LINE - 1 )
  359. return;
  360. edit->buffer[edit->cursor] = ch;
  361. edit->cursor++;
  362. } else { // insert mode
  363. if ( len == MAX_EDIT_LINE - 1 ) {
  364. return; // all full
  365. }
  366. memmove( edit->buffer + edit->cursor + 1,
  367. edit->buffer + edit->cursor, len + 1 - edit->cursor );
  368. edit->buffer[edit->cursor] = ch;
  369. edit->cursor++;
  370. }
  371. if ( edit->cursor >= edit->widthInChars ) {
  372. edit->scroll++;
  373. }
  374. if ( edit->cursor == len + 1) {
  375. edit->buffer[edit->cursor] = 0;
  376. }
  377. }
  378. /*
  379. =============================================================================
  380. CONSOLE LINE EDITING
  381. ==============================================================================
  382. */
  383. /*
  384. ====================
  385. Console_Key
  386. Handles history and console scrollback
  387. ====================
  388. */
  389. void Console_Key (int key) {
  390. // ctrl-L clears screen
  391. if ( key == 'l' && keys[K_CTRL].down ) {
  392. Cbuf_AddText ("clear\n");
  393. return;
  394. }
  395. // enter finishes the line
  396. if ( key == K_ENTER || key == K_KP_ENTER ) {
  397. // if not in the game explicitly prepent a slash if needed
  398. if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\'
  399. && g_consoleField.buffer[0] != '/' ) {
  400. char temp[MAX_STRING_CHARS];
  401. Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
  402. Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
  403. g_consoleField.cursor++;
  404. }
  405. Com_Printf ( "]%s\n", g_consoleField.buffer );
  406. // leading slash is an explicit command
  407. if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) {
  408. Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
  409. Cbuf_AddText ("\n");
  410. } else {
  411. // other text will be chat messages
  412. if ( !g_consoleField.buffer[0] ) {
  413. return; // empty lines just scroll the console without adding to history
  414. } else {
  415. Cbuf_AddText ("cmd say ");
  416. Cbuf_AddText( g_consoleField.buffer );
  417. Cbuf_AddText ("\n");
  418. }
  419. }
  420. // copy line to history buffer
  421. historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
  422. nextHistoryLine++;
  423. historyLine = nextHistoryLine;
  424. Field_Clear( &g_consoleField );
  425. g_consoleField.widthInChars = g_console_field_width;
  426. if ( cls.state == CA_DISCONNECTED ) {
  427. SCR_UpdateScreen (); // force an update, because the command
  428. } // may take some time
  429. return;
  430. }
  431. // command completion
  432. if (key == K_TAB) {
  433. Field_CompleteCommand(&g_consoleField);
  434. return;
  435. }
  436. // command history (ctrl-p ctrl-n for unix style)
  437. if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
  438. ( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
  439. if ( nextHistoryLine - historyLine < COMMAND_HISTORY
  440. && historyLine > 0 ) {
  441. historyLine--;
  442. }
  443. g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
  444. return;
  445. }
  446. if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
  447. ( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
  448. if (historyLine == nextHistoryLine)
  449. return;
  450. historyLine++;
  451. g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
  452. return;
  453. }
  454. // console scrolling
  455. if ( key == K_PGUP ) {
  456. Con_PageUp();
  457. return;
  458. }
  459. if ( key == K_PGDN) {
  460. Con_PageDown();
  461. return;
  462. }
  463. if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
  464. Con_PageUp();
  465. if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
  466. Con_PageUp();
  467. Con_PageUp();
  468. }
  469. return;
  470. }
  471. if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
  472. Con_PageDown();
  473. if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
  474. Con_PageDown();
  475. Con_PageDown();
  476. }
  477. return;
  478. }
  479. // ctrl-home = top of console
  480. if ( key == K_HOME && keys[K_CTRL].down ) {
  481. Con_Top();
  482. return;
  483. }
  484. // ctrl-end = bottom of console
  485. if ( key == K_END && keys[K_CTRL].down ) {
  486. Con_Bottom();
  487. return;
  488. }
  489. // pass to the normal editline routine
  490. Field_KeyDownEvent( &g_consoleField, key );
  491. }
  492. //============================================================================
  493. /*
  494. ================
  495. Message_Key
  496. In game talk message
  497. ================
  498. */
  499. void Message_Key( int key ) {
  500. char buffer[MAX_STRING_CHARS];
  501. if (key == K_ESCAPE) {
  502. cls.keyCatchers &= ~KEYCATCH_MESSAGE;
  503. Field_Clear( &chatField );
  504. return;
  505. }
  506. if ( key == K_ENTER || key == K_KP_ENTER )
  507. {
  508. if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
  509. if (chat_playerNum != -1 )
  510. Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
  511. else if (chat_team)
  512. Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
  513. else
  514. Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
  515. CL_AddReliableCommand( buffer );
  516. }
  517. cls.keyCatchers &= ~KEYCATCH_MESSAGE;
  518. Field_Clear( &chatField );
  519. return;
  520. }
  521. Field_KeyDownEvent( &chatField, key );
  522. }
  523. //============================================================================
  524. qboolean Key_GetOverstrikeMode( void ) {
  525. return key_overstrikeMode;
  526. }
  527. void Key_SetOverstrikeMode( qboolean state ) {
  528. key_overstrikeMode = state;
  529. }
  530. /*
  531. ===================
  532. Key_IsDown
  533. ===================
  534. */
  535. qboolean Key_IsDown( int keynum ) {
  536. if ( keynum == -1 ) {
  537. return qfalse;
  538. }
  539. return keys[keynum].down;
  540. }
  541. /*
  542. ===================
  543. Key_StringToKeynum
  544. Returns a key number to be used to index keys[] by looking at
  545. the given string. Single ascii characters return themselves, while
  546. the K_* names are matched up.
  547. 0x11 will be interpreted as raw hex, which will allow new controlers
  548. to be configured even if they don't have defined names.
  549. ===================
  550. */
  551. int Key_StringToKeynum( char *str ) {
  552. keyname_t *kn;
  553. if ( !str || !str[0] ) {
  554. return -1;
  555. }
  556. if ( !str[1] ) {
  557. return str[0];
  558. }
  559. // check for hex code
  560. if ( str[0] == '0' && str[1] == 'x' && strlen( str ) == 4) {
  561. int n1, n2;
  562. n1 = str[2];
  563. if ( n1 >= '0' && n1 <= '9' ) {
  564. n1 -= '0';
  565. } else if ( n1 >= 'a' && n1 <= 'f' ) {
  566. n1 = n1 - 'a' + 10;
  567. } else {
  568. n1 = 0;
  569. }
  570. n2 = str[3];
  571. if ( n2 >= '0' && n2 <= '9' ) {
  572. n2 -= '0';
  573. } else if ( n2 >= 'a' && n2 <= 'f' ) {
  574. n2 = n2 - 'a' + 10;
  575. } else {
  576. n2 = 0;
  577. }
  578. return n1 * 16 + n2;
  579. }
  580. // scan for a text match
  581. for ( kn=keynames ; kn->name ; kn++ ) {
  582. if ( !Q_stricmp( str,kn->name ) )
  583. return kn->keynum;
  584. }
  585. return -1;
  586. }
  587. /*
  588. ===================
  589. Key_KeynumToString
  590. Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) for the
  591. given keynum.
  592. ===================
  593. */
  594. char *Key_KeynumToString( int keynum ) {
  595. keyname_t *kn;
  596. static char tinystr[5];
  597. int i, j;
  598. if ( keynum == -1 ) {
  599. return "<KEY NOT FOUND>";
  600. }
  601. if ( keynum < 0 || keynum > 255 ) {
  602. return "<OUT OF RANGE>";
  603. }
  604. // check for printable ascii (don't use quote)
  605. if ( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' ) {
  606. tinystr[0] = keynum;
  607. tinystr[1] = 0;
  608. return tinystr;
  609. }
  610. // check for a key string
  611. for ( kn=keynames ; kn->name ; kn++ ) {
  612. if (keynum == kn->keynum) {
  613. return kn->name;
  614. }
  615. }
  616. // make a hex string
  617. i = keynum >> 4;
  618. j = keynum & 15;
  619. tinystr[0] = '0';
  620. tinystr[1] = 'x';
  621. tinystr[2] = i > 9 ? i - 10 + 'a' : i + '0';
  622. tinystr[3] = j > 9 ? j - 10 + 'a' : j + '0';
  623. tinystr[4] = 0;
  624. return tinystr;
  625. }
  626. /*
  627. ===================
  628. Key_SetBinding
  629. ===================
  630. */
  631. void Key_SetBinding( int keynum, const char *binding ) {
  632. if ( keynum == -1 ) {
  633. return;
  634. }
  635. // free old bindings
  636. if ( keys[ keynum ].binding ) {
  637. Z_Free( keys[ keynum ].binding );
  638. }
  639. // allocate memory for new binding
  640. keys[keynum].binding = CopyString( binding );
  641. // consider this like modifying an archived cvar, so the
  642. // file write will be triggered at the next oportunity
  643. cvar_modifiedFlags |= CVAR_ARCHIVE;
  644. }
  645. /*
  646. ===================
  647. Key_GetBinding
  648. ===================
  649. */
  650. char *Key_GetBinding( int keynum ) {
  651. if ( keynum == -1 ) {
  652. return "";
  653. }
  654. return keys[ keynum ].binding;
  655. }
  656. /*
  657. ===================
  658. Key_GetKey
  659. ===================
  660. */
  661. int Key_GetKey(const char *binding) {
  662. int i;
  663. if (binding) {
  664. for (i=0 ; i<256 ; i++) {
  665. if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
  666. return i;
  667. }
  668. }
  669. }
  670. return -1;
  671. }
  672. /*
  673. ===================
  674. Key_Unbind_f
  675. ===================
  676. */
  677. void Key_Unbind_f (void)
  678. {
  679. int b;
  680. if (Cmd_Argc() != 2)
  681. {
  682. Com_Printf ("unbind <key> : remove commands from a key\n");
  683. return;
  684. }
  685. b = Key_StringToKeynum (Cmd_Argv(1));
  686. if (b==-1)
  687. {
  688. Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  689. return;
  690. }
  691. Key_SetBinding (b, "");
  692. }
  693. /*
  694. ===================
  695. Key_Unbindall_f
  696. ===================
  697. */
  698. void Key_Unbindall_f (void)
  699. {
  700. int i;
  701. for (i=0 ; i<256 ; i++)
  702. if (keys[i].binding)
  703. Key_SetBinding (i, "");
  704. }
  705. /*
  706. ===================
  707. Key_Bind_f
  708. ===================
  709. */
  710. void Key_Bind_f (void)
  711. {
  712. int i, c, b;
  713. char cmd[1024];
  714. c = Cmd_Argc();
  715. if (c < 2)
  716. {
  717. Com_Printf ("bind <key> [command] : attach a command to a key\n");
  718. return;
  719. }
  720. b = Key_StringToKeynum (Cmd_Argv(1));
  721. if (b==-1)
  722. {
  723. Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  724. return;
  725. }
  726. if (c == 2)
  727. {
  728. if (keys[b].binding)
  729. Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding );
  730. else
  731. Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
  732. return;
  733. }
  734. // copy the rest of the command line
  735. cmd[0] = 0; // start out with a null string
  736. for (i=2 ; i< c ; i++)
  737. {
  738. strcat (cmd, Cmd_Argv(i));
  739. if (i != (c-1))
  740. strcat (cmd, " ");
  741. }
  742. Key_SetBinding (b, cmd);
  743. }
  744. /*
  745. ============
  746. Key_WriteBindings
  747. Writes lines containing "bind key value"
  748. ============
  749. */
  750. void Key_WriteBindings( fileHandle_t f ) {
  751. int i;
  752. FS_Printf (f, "unbindall\n" );
  753. for (i=0 ; i<256 ; i++) {
  754. if (keys[i].binding && keys[i].binding[0] ) {
  755. FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
  756. }
  757. }
  758. }
  759. /*
  760. ============
  761. Key_Bindlist_f
  762. ============
  763. */
  764. void Key_Bindlist_f( void ) {
  765. int i;
  766. for ( i = 0 ; i < 256 ; i++ ) {
  767. if ( keys[i].binding && keys[i].binding[0] ) {
  768. Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
  769. }
  770. }
  771. }
  772. /*
  773. ===================
  774. CL_InitKeyCommands
  775. ===================
  776. */
  777. void CL_InitKeyCommands( void ) {
  778. // register our functions
  779. Cmd_AddCommand ("bind",Key_Bind_f);
  780. Cmd_AddCommand ("unbind",Key_Unbind_f);
  781. Cmd_AddCommand ("unbindall",Key_Unbindall_f);
  782. Cmd_AddCommand ("bindlist",Key_Bindlist_f);
  783. }
  784. /*
  785. ===================
  786. CL_AddKeyUpCommands
  787. ===================
  788. */
  789. void CL_AddKeyUpCommands( int key, char *kb ) {
  790. int i;
  791. char button[1024], *buttonPtr;
  792. char cmd[1024];
  793. qboolean keyevent;
  794. if ( !kb ) {
  795. return;
  796. }
  797. keyevent = qfalse;
  798. buttonPtr = button;
  799. for ( i = 0; ; i++ ) {
  800. if ( kb[i] == ';' || !kb[i] ) {
  801. *buttonPtr = '\0';
  802. if ( button[0] == '+') {
  803. // button commands add keynum and time as parms so that multiple
  804. // sources can be discriminated and subframe corrected
  805. Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", button+1, key, time);
  806. Cbuf_AddText (cmd);
  807. keyevent = qtrue;
  808. } else {
  809. if (keyevent) {
  810. // down-only command
  811. Cbuf_AddText (button);
  812. Cbuf_AddText ("\n");
  813. }
  814. }
  815. buttonPtr = button;
  816. while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {
  817. i++;
  818. }
  819. }
  820. *buttonPtr++ = kb[i];
  821. if ( !kb[i] ) {
  822. break;
  823. }
  824. }
  825. }
  826. /*
  827. ===================
  828. CL_KeyEvent
  829. Called by the system for both key up and key down events
  830. ===================
  831. */
  832. void CL_KeyEvent (int key, qboolean down, unsigned time) {
  833. char *kb;
  834. char cmd[1024];
  835. // update auto-repeat status and BUTTON_ANY status
  836. keys[key].down = down;
  837. if (down) {
  838. keys[key].repeats++;
  839. if ( keys[key].repeats == 1) {
  840. anykeydown++;
  841. }
  842. } else {
  843. keys[key].repeats = 0;
  844. anykeydown--;
  845. if (anykeydown < 0) {
  846. anykeydown = 0;
  847. }
  848. }
  849. #ifdef __linux__
  850. if (key == K_ENTER)
  851. {
  852. if (down)
  853. {
  854. if (keys[K_ALT].down)
  855. {
  856. Key_ClearStates();
  857. if (Cvar_VariableValue("r_fullscreen") == 0)
  858. {
  859. Com_Printf("Switching to fullscreen rendering\n");
  860. Cvar_Set("r_fullscreen", "1");
  861. }
  862. else
  863. {
  864. Com_Printf("Switching to windowed rendering\n");
  865. Cvar_Set("r_fullscreen", "0");
  866. }
  867. Cbuf_ExecuteText( EXEC_APPEND, "vid_restart\n");
  868. return;
  869. }
  870. }
  871. }
  872. #endif
  873. // console key is hardcoded, so the user can never unbind it
  874. if (key == '`' || key == '~') {
  875. if (!down) {
  876. return;
  877. }
  878. Con_ToggleConsole_f ();
  879. return;
  880. }
  881. // keys can still be used for bound actions
  882. if ( down && ( key < 128 || key == K_MOUSE1 ) && ( clc.demoplaying || cls.state == CA_CINEMATIC ) && !cls.keyCatchers) {
  883. if (Cvar_VariableValue ("com_cameraMode") == 0) {
  884. Cvar_Set ("nextdemo","");
  885. key = K_ESCAPE;
  886. }
  887. }
  888. // escape is always handled special
  889. if ( key == K_ESCAPE && down ) {
  890. if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
  891. // clear message mode
  892. Message_Key( key );
  893. return;
  894. }
  895. // escape always gets out of CGAME stuff
  896. if (cls.keyCatchers & KEYCATCH_CGAME) {
  897. cls.keyCatchers &= ~KEYCATCH_CGAME;
  898. VM_Call (cgvm, CG_EVENT_HANDLING, CGAME_EVENT_NONE);
  899. return;
  900. }
  901. if ( !( cls.keyCatchers & KEYCATCH_UI ) ) {
  902. if ( cls.state == CA_ACTIVE && !clc.demoplaying ) {
  903. VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_INGAME );
  904. }
  905. else {
  906. CL_Disconnect_f();
  907. S_StopAllSounds();
  908. VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
  909. }
  910. return;
  911. }
  912. VM_Call( uivm, UI_KEY_EVENT, key, down );
  913. return;
  914. }
  915. //
  916. // key up events only perform actions if the game key binding is
  917. // a button command (leading + sign). These will be processed even in
  918. // console mode and menu mode, to keep the character from continuing
  919. // an action started before a mode switch.
  920. //
  921. if (!down) {
  922. kb = keys[key].binding;
  923. CL_AddKeyUpCommands( key, kb );
  924. if ( cls.keyCatchers & KEYCATCH_UI && uivm ) {
  925. VM_Call( uivm, UI_KEY_EVENT, key, down );
  926. } else if ( cls.keyCatchers & KEYCATCH_CGAME && cgvm ) {
  927. VM_Call( cgvm, CG_KEY_EVENT, key, down );
  928. }
  929. return;
  930. }
  931. // distribute the key down event to the apropriate handler
  932. if ( cls.keyCatchers & KEYCATCH_CONSOLE ) {
  933. Console_Key( key );
  934. } else if ( cls.keyCatchers & KEYCATCH_UI ) {
  935. if ( uivm ) {
  936. VM_Call( uivm, UI_KEY_EVENT, key, down );
  937. }
  938. } else if ( cls.keyCatchers & KEYCATCH_CGAME ) {
  939. if ( cgvm ) {
  940. VM_Call( cgvm, CG_KEY_EVENT, key, down );
  941. }
  942. } else if ( cls.keyCatchers & KEYCATCH_MESSAGE ) {
  943. Message_Key( key );
  944. } else if ( cls.state == CA_DISCONNECTED ) {
  945. Console_Key( key );
  946. } else {
  947. // send the bound action
  948. kb = keys[key].binding;
  949. if ( !kb ) {
  950. if (key >= 200) {
  951. Com_Printf ("%s is unbound, use controls menu to set.\n"
  952. , Key_KeynumToString( key ) );
  953. }
  954. } else if (kb[0] == '+') {
  955. int i;
  956. char button[1024], *buttonPtr;
  957. buttonPtr = button;
  958. for ( i = 0; ; i++ ) {
  959. if ( kb[i] == ';' || !kb[i] ) {
  960. *buttonPtr = '\0';
  961. if ( button[0] == '+') {
  962. // button commands add keynum and time as parms so that multiple
  963. // sources can be discriminated and subframe corrected
  964. Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", button, key, time);
  965. Cbuf_AddText (cmd);
  966. } else {
  967. // down-only command
  968. Cbuf_AddText (button);
  969. Cbuf_AddText ("\n");
  970. }
  971. buttonPtr = button;
  972. while ( (kb[i] <= ' ' || kb[i] == ';') && kb[i] != 0 ) {
  973. i++;
  974. }
  975. }
  976. *buttonPtr++ = kb[i];
  977. if ( !kb[i] ) {
  978. break;
  979. }
  980. }
  981. } else {
  982. // down-only command
  983. Cbuf_AddText (kb);
  984. Cbuf_AddText ("\n");
  985. }
  986. }
  987. }
  988. /*
  989. ===================
  990. CL_CharEvent
  991. Normal keyboard characters, already shifted / capslocked / etc
  992. ===================
  993. */
  994. void CL_CharEvent( int key ) {
  995. // the console key should never be used as a char
  996. if ( key == '`' || key == '~' ) {
  997. return;
  998. }
  999. // distribute the key down event to the apropriate handler
  1000. if ( cls.keyCatchers & KEYCATCH_CONSOLE )
  1001. {
  1002. Field_CharEvent( &g_consoleField, key );
  1003. }
  1004. else if ( cls.keyCatchers & KEYCATCH_UI )
  1005. {
  1006. VM_Call( uivm, UI_KEY_EVENT, key | K_CHAR_FLAG, qtrue );
  1007. }
  1008. else if ( cls.keyCatchers & KEYCATCH_MESSAGE )
  1009. {
  1010. Field_CharEvent( &chatField, key );
  1011. }
  1012. else if ( cls.state == CA_DISCONNECTED )
  1013. {
  1014. Field_CharEvent( &g_consoleField, key );
  1015. }
  1016. }
  1017. /*
  1018. ===================
  1019. Key_ClearStates
  1020. ===================
  1021. */
  1022. void Key_ClearStates (void)
  1023. {
  1024. int i;
  1025. anykeydown = qfalse;
  1026. for ( i=0 ; i < MAX_KEYS ; i++ ) {
  1027. if ( keys[i].down ) {
  1028. CL_KeyEvent( i, qfalse, 0 );
  1029. }
  1030. keys[i].down = 0;
  1031. keys[i].repeats = 0;
  1032. }
  1033. }