1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: g_input.c 1566 2020-12-19 06:22:58Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: g_input.c,v $
20 // Revision 1.12 2002/08/24 22:42:02 hurdler
21 // Apply Robert Hogberg patches
22 //
23 // Revision 1.11 2002/07/01 19:59:58 metzgermeister
24 // *** empty log message ***
25 //
26 // Revision 1.10 2001/03/30 17:12:49 bpereira
27 // Revision 1.9 2001/02/24 13:35:19 bpereira
28 // Revision 1.8 2001/02/10 12:27:13 bpereira
29 //
30 // Revision 1.7 2001/01/25 22:15:42 bpereira
31 // added heretic support
32 //
33 // Revision 1.6 2000/11/26 00:46:31 hurdler
34 //
35 // Revision 1.5 2000/10/04 17:03:57 hurdler
36 // This is the formule I propose for mouse sensitivity
37 //
38 // Revision 1.4 2000/04/16 18:38:07 bpereira
39 //
40 // Revision 1.3 2000/04/04 00:32:45 stroggonmeth
41 // Initial Boom compatability plus few misc changes all around.
42 //
43 // Revision 1.2 2000/02/27 00:42:10 hurdler
44 // Revision 1.1.1.1 2000/02/22 20:32:32 hurdler
45 // Initial import into CVS (v1.29 pr3)
46 //
47 //
48 // DESCRIPTION:
49 // handle mouse/keyboard/joystick inputs,
50 // maps inputs to game controls (forward,use,open...)
51 //
52 //-----------------------------------------------------------------------------
53
54 #include "doomincl.h"
55 #include "doomstat.h"
56 #include "g_input.h"
57 #include "keys.h"
58 #include "hu_stuff.h" //need HUFONT start & end
59 #include "keys.h"
60 #include "d_net.h"
61 #include "console.h"
62 #include "i_joy.h"
63 #include "i_system.h"
64
65 int num_joybindings = 0;
66 joybinding_t joybindings[MAX_JOYBINDINGS];
67
68
69 CV_PossibleValue_t mousesens_cons_t[]={{1,"MIN"},{MAXMOUSESENSITIVITY,"MAXCURSOR"},{INT_MAX,"MAX"},{0,NULL}};
70 CV_PossibleValue_t onecontrolperkey_cons_t[]={{1,"One"},{2,"Several"},{0,NULL}};
71
72 // mouse values are used once
73 consvar_t cv_mouse_sens_x = {"mousesensx","10",CV_SAVE,mousesens_cons_t};
74 consvar_t cv_mouse_sens_y = {"mousesensy","10",CV_SAVE,mousesens_cons_t};
75 consvar_t cv_controlperkey = {"controlperkey","1",CV_SAVE,onecontrolperkey_cons_t};
76
77 CV_PossibleValue_t usemouse_cons_t[] = { {0, "Off"}, {1, "On"}, {2, "Force"}, {0, NULL} };
78 consvar_t cv_usemouse[2] = {
79 { "use_mouse", "1", CV_SAVE | CV_CALL, usemouse_cons_t, CV_mouse_OnChange },
80 { "use_mouse2", "0", CV_SAVE | CV_CALL, usemouse_cons_t, I_StartupMouse2 }
81 };
82
83 #ifdef MOUSE2
84 #ifdef MOUSE2_NIX
85 CV_PossibleValue_t mouse2port_cons_t[] = {
86 {0, "gpmdata"},
87 {1, "mouse2"}, // indirection
88 {2, "ttyS0"}, {3, "ttyS1"}, {4, "ttyS2"}, {5, "ttyS3"}, {6, "ttyS4"}, {7, "ttyS5"}, {8, "ttyS6"},
89 {0, NULL} };
90 #define CV_DEFAULT_PORT "gpmdata"
91 #endif
92 #ifdef MOUSE2_WIN
93 CV_PossibleValue_t mouse2port_cons_t[] = {
94 {1, "COM1"}, {2, "COM2"}, {3, "COM3"}, {4, "COM4"},
95 {5, "COM5"}, {6, "COM6"}, {7, "COM7"}, {8, "COM8"}, // Some Windows are reported to connect USB or other devices to COM ports
96 {0, NULL} };
97 #define CV_DEFAULT_PORT "COM2"
98 #endif
99 consvar_t cv_mouse2port = { "mouse2port", CV_DEFAULT_PORT , CV_SAVE|CV_STRING|CV_CALL|CV_NOINIT, mouse2port_cons_t, I_StartupMouse2 };
100 consvar_t cv_mouse2opt = { "mouse2opt", "0", CV_SAVE|CV_STRING|CV_CALL|CV_NOINIT, NULL, I_StartupMouse2 };
101 #if defined( SMIF_SDL ) || defined( SMIF_WIN32 )
102 // Only in SDL, WIN32 for now.
103 CV_PossibleValue_t mouse2type_cons_t[] = { {0, "PC"}, {1, "MS"}, {2, "PS2"}, {0, NULL} };
104 consvar_t cv_mouse2type = { "mouse2type", "0" , CV_SAVE|CV_STRING|CV_CALL|CV_NOINIT, mouse2type_cons_t, I_StartupMouse2 };
105 #endif
106 consvar_t cv_mouse2_sens_x = {"mouse2sensx","10",CV_SAVE,mousesens_cons_t};
107 consvar_t cv_mouse2_sens_y = {"mouse2sensy","10",CV_SAVE,mousesens_cons_t};
108 #endif
109
110 #ifdef SMIF_SDL
111 CV_PossibleValue_t mouse_motion_cons_t[]={{0,"Absolute"},{1,"Relative"},{0,NULL}};
112 consvar_t cv_mouse_motion = {"mousemotion","0", CV_SAVE|CV_CALL|CV_NOINIT, mouse_motion_cons_t, CV_mouse_OnChange };
113 #endif
114
115 consvar_t cv_grabinput = {"grabinput","1", CV_SAVE|CV_CALL, CV_OnOff, CV_mouse_OnChange };
116
117 // A normal double click is approx. 6 tics from previous click.
118 CV_PossibleValue_t double_cons_t[]={{1,"MIN"},{40,"MAX"},{0,NULL}}; // double click threshold
119 consvar_t cv_mouse_double = {"mousedouble","8",CV_SAVE, double_cons_t};
120 #ifdef JOY_BUTTONS_DOUBLE
121 consvar_t cv_joy_double = {"joydouble", "8",CV_SAVE, double_cons_t};
122 #endif
123
124
125 // Called for cv_grabinput, cv_mouse_motion, use_mouse
CV_mouse_OnChange(void)126 void CV_mouse_OnChange( void )
127 {
128 I_StartupMouse( !(paused || menuactive) );
129 }
130
131
132 int mousex, mousey;
133 int mouse2x, mouse2y;
134
135 // [WDJ] When boolean, the compiler uses 4 bytes for one bit of information.
136 byte gamekeydown[NUMINPUTS]; // Current state of the keys: true if the key is currently down.
137 byte gamekeytapped[NUMINPUTS]; // True if the key has been pressed since the last G_BuildTiccmd. Useful for impulse-style controls.
138
139
140 // two key codes (or virtual key) per game control
141 int gamecontrol[num_gamecontrols][2];
142 int gamecontrol2[num_gamecontrols][2]; // secondary splitscreen player
143
144
145 // FIXME: this can be simplified to two bytes
146 // [WDJ] Got it down to 3 bytes.
147 typedef struct {
148 byte dtime; // 0..21
149 byte key_down;
150 byte clicks; // 0..2
151 } dclick_t;
152
153 // FIXME: only one mouse, only one joy
154 static dclick_t mouse_dclick[MOUSEBUTTONS];
155 #ifdef JOY_BUTTONS_DOUBLE
156 static dclick_t joy_dclick[JOYBUTTONS];
157 #endif
158
159 static tic_t clicktic = 0; // gametic of last button check
160 static unsigned int click_delta; // tics since last button check, limited 120
161
162 //
163 // General double-click detection routine for any kind of input.
164 //
G_CheckDoubleClick(int key_id,dclick_t * dt,byte double_click_threshold)165 static boolean G_CheckDoubleClick(int key_id, dclick_t *dt, byte double_click_threshold )
166 {
167 // [WDJ] This is only called for each event, so time cannot be determined by counting.
168 byte key_down = gamekeydown[ key_id ];
169 // Limited to 120 tics since last click, anything > 40 tics is a timeout.
170 dt->dtime += click_delta; // + 0..120, must not overflow
171 // This is called infrequently, so check timeouts first.
172 // A normal double click is approx. 6 tics from previous click.
173 if( dt->dtime > double_click_threshold ) // 1..40
174 {
175 dt->dtime = 121; // timeout (with room to add 120)
176 dt->clicks = 0;
177 dt->key_down = false;
178 }
179
180 // Check new state.
181 if( (key_down != dt->key_down) && (dt->dtime > 1) )
182 {
183 dt->key_down = key_down;
184 if( key_down )
185 {
186 dt->clicks++;
187 if(dt->clicks == 2)
188 {
189 dt->clicks = 0;
190 dt->dtime = 0;
191 return true;
192 }
193 }
194 dt->dtime = 0;
195 }
196 return false;
197 }
198
199
200
201 //
202 // Remaps the inputs to game controls.
203 //
204 // A game control can be triggered by one or more keys/buttons.
205 //
206 // Each key/mousebutton/joybutton triggers ONLY ONE game control.
207 //
208 //
G_MapEventsToControls(event_t * ev)209 void G_MapEventsToControls (event_t *ev)
210 {
211 int i;
212
213 switch (ev->type)
214 {
215 case ev_keydown:
216 if (ev->data1 < NUMINPUTS)
217 {
218 gamekeydown[ev->data1] = true;
219 gamekeytapped[ev->data1] = true; // reset in G_BuildTiccmd
220 }
221 break;
222
223 case ev_keyup:
224 if (ev->data1 < NUMINPUTS)
225 gamekeydown[ev->data1] = false;
226 break;
227
228 case ev_mouse: // buttons are virtual keys
229 // [WDJ] To handle multiple mouse motion events per frame instead
230 // of letting the last event be the sole mouse motion,
231 // add the mouse events.
232 // Necessary for OpenBSD which reports x and y in separate events.
233 mousex += ev->data2*((cv_mouse_sens_x.value*cv_mouse_sens_x.value)/110.0f + 0.1);
234 mousey += ev->data3*((cv_mouse_sens_y.value*cv_mouse_sens_y.value)/110.0f + 0.1);
235 break;
236
237 #ifdef MOUSE2
238 case ev_mouse2: // buttons are virtual keys
239 // add multiple mouse motions
240 mouse2x += ev->data2*((cv_mouse2_sens_x.value*cv_mouse2_sens_x.value)/110.0f + 0.1);
241 mouse2y += ev->data3*((cv_mouse2_sens_y.value*cv_mouse2_sens_y.value)/110.0f + 0.1);
242 break;
243 #endif
244
245 default:
246 break;
247 }
248
249 // [WDJ] Only called for events, so click time needs to be based upon gametic.
250 // This is overflow safe, it wraps.
251 click_delta = (gametic - clicktic) / NEWTICRATERATIO; // must be 35 tic/sec based.
252 if( click_delta > 120 ) click_delta = 120;
253 clicktic = gametic;
254
255 // ALWAYS check for mouse & joystick double-clicks
256 // even if no mouse event
257 // FIXME: first MOUSE only
258 for (i=0;i<MOUSEBUTTONS;i++)
259 gamekeydown[KEY_MOUSE1DBL+i] = G_CheckDoubleClick( KEY_MOUSE1+i, &mouse_dclick[i], cv_mouse_double.value );
260
261 #ifdef JOY_BUTTONS_DOUBLE
262 // joystick doubleclicks
263 // FIXME: JOY0 only
264 for (i=0;i<JOYBUTTONS;i++)
265 gamekeydown[KEY_JOY0BUT0DBL+i] = G_CheckDoubleClick( KEY_JOY0BUT0+i, &joy_dclick[i], cv_joy_double.value );
266 #endif
267 }
268
269
270
271
272 typedef struct {
273 int keynum;
274 char name[16];
275 } keyname_t;
276
277 static keyname_t keynames[] =
278 {
279 {KEY_NULL, "null"},
280
281 {KEY_BACKSPACE, "backspace"},
282 {KEY_TAB, "tab"},
283 {KEY_ENTER, "enter"},
284 {KEY_PAUSE, "pause"}, // irrelevant, since this key cannot be remapped...
285 {KEY_ESCAPE, "escape"}, // likewise
286 {KEY_SPACE, "space"},
287
288 {KEY_CONSOLE, "console"},
289
290 {KEY_NUMLOCK, "num lock"},
291 {KEY_CAPSLOCK, "caps lock"},
292 {KEY_SCROLLLOCK, "scroll lock"},
293 {KEY_SYSREQ, "sysreq"},
294 {KEY_RSHIFT, "right shift"},
295 {KEY_LSHIFT, "left shift"},
296 {KEY_RCTRL, "right ctrl"},
297 {KEY_LCTRL, "left ctrl"},
298 {KEY_RALT, "right alt"},
299 {KEY_LALT, "left alt"},
300 {KEY_LWIN, "left win"},
301 {KEY_RWIN, "right win"},
302 {KEY_MODE, "altgr"},
303 {KEY_MENU, "menu"},
304
305 // keypad keys
306 {KEY_KEYPAD0, "keypad 0"},
307 {KEY_KEYPAD1, "keypad 1"},
308 {KEY_KEYPAD2, "keypad 2"},
309 {KEY_KEYPAD3, "keypad 3"},
310 {KEY_KEYPAD4, "keypad 4"},
311 {KEY_KEYPAD5, "keypad 5"},
312 {KEY_KEYPAD6, "keypad 6"},
313 {KEY_KEYPAD7, "keypad 7"},
314 {KEY_KEYPAD8, "keypad 8"},
315 {KEY_KEYPAD9, "keypad 9"},
316 {KEY_KPADPERIOD,"keypad ."},
317 {KEY_KPADSLASH, "keypad /"},
318 {KEY_KPADMULT, "keypad *"},
319 {KEY_MINUSPAD, "keypad -"},
320 {KEY_PLUSPAD, "keypad +"},
321
322 // extended keys (not keypad)
323 {KEY_UPARROW, "up arrow"},
324 {KEY_DOWNARROW, "down arrow"},
325 {KEY_RIGHTARROW,"right arrow"},
326 {KEY_LEFTARROW, "left arrow"},
327 {KEY_INS, "ins"},
328 {KEY_DELETE, "del"},
329 {KEY_HOME, "home"},
330 {KEY_END, "end"},
331 {KEY_PGUP, "pgup"},
332 {KEY_PGDN, "pgdown"},
333
334 // other keys
335 {KEY_F1, "F1"},
336 {KEY_F2, "F2"},
337 {KEY_F3, "F3"},
338 {KEY_F4, "F4"},
339 {KEY_F5, "F5"},
340 {KEY_F6, "F6"},
341 {KEY_F7, "F7"},
342 {KEY_F8, "F8"},
343 {KEY_F9, "F9"},
344 {KEY_F10,"F10"},
345 {KEY_F11,"F11"},
346 {KEY_F12,"F12"},
347
348 // virtual keys for mouse buttons and joystick buttons
349 {KEY_MOUSE1, "mouse 1"},
350 {KEY_MOUSE1+1,"mouse 2"},
351 {KEY_MOUSE1+2,"mouse 3"},
352 {KEY_MOUSEWHEELUP, "mwheel up"},
353 {KEY_MOUSEWHEELDOWN,"mwheel down"},
354 {KEY_MOUSE1+5,"mouse 6"},
355 {KEY_MOUSE1+6,"mouse 7"},
356 {KEY_MOUSE1+7,"mouse 8"},
357 {KEY_MOUSE2, "mouse2 1"},
358 {KEY_MOUSE2+1,"mouse2 2"},
359 {KEY_MOUSE2+2,"mouse2 3"},
360 {KEY_MOUSE2WHEELUP,"m2 mwheel up"},
361 {KEY_MOUSE2WHEELDOWN,"m2 mwheel down"},
362 {KEY_MOUSE2+5,"mouse2 6"},
363 {KEY_MOUSE2+6,"mouse2 7"},
364 {KEY_MOUSE2+7,"mouse2 8"},
365
366 {KEY_MOUSE1DBL, "mouse 1 d"},
367 {KEY_MOUSE1DBL+1, "mouse 2 d"},
368 {KEY_MOUSE1DBL+2, "mouse 3 d"},
369 {KEY_MOUSE1DBL+3, "mouse 4 d"},
370 {KEY_MOUSE1DBL+4, "mouse 5 d"},
371 {KEY_MOUSE1DBL+5, "mouse 6 d"},
372 {KEY_MOUSE1DBL+6, "mouse 7 d"},
373 {KEY_MOUSE1DBL+7, "mouse 8 d"},
374 {KEY_MOUSE2DBL, "mouse2 2 d"},
375 {KEY_MOUSE2DBL+1,"mouse2 1 d"},
376 {KEY_MOUSE2DBL+2,"mouse2 3 d"},
377 {KEY_MOUSE2DBL+3,"mouse2 4 d"},
378 {KEY_MOUSE2DBL+4,"mouse2 5 d"},
379 {KEY_MOUSE2DBL+5,"mouse2 6 d"},
380 {KEY_MOUSE2DBL+6,"mouse2 7 d"},
381 {KEY_MOUSE2DBL+7,"mouse2 8 d"},
382
383 {KEY_JOY0BUT0, "Joy0 b0"},
384 {KEY_JOY0BUT1, "Joy0 b1"},
385 {KEY_JOY0BUT2, "Joy0 b2"},
386 {KEY_JOY0BUT3, "Joy0 b3"},
387 {KEY_JOY0BUT4, "Joy0 b4"},
388 {KEY_JOY0BUT5, "Joy0 b5"},
389 {KEY_JOY0BUT6, "Joy0 b6"},
390 {KEY_JOY0BUT7, "Joy0 b7"},
391 {KEY_JOY0BUT8, "Joy0 b8"},
392 {KEY_JOY0BUT9, "Joy0 b9"},
393 {KEY_JOY0BUT10, "Joy0 b10"},
394 {KEY_JOY0BUT11, "Joy0 b11"},
395 {KEY_JOY0BUT12, "Joy0 b12"},
396 {KEY_JOY0BUT13, "Joy0 b13"},
397 {KEY_JOY0BUT14, "Joy0 b14"},
398 {KEY_JOY0BUT15, "Joy0 b15"},
399
400 {KEY_JOY1BUT0, "Joy1 b0"},
401 {KEY_JOY1BUT1, "Joy1 b1"},
402 {KEY_JOY1BUT2, "Joy1 b2"},
403 {KEY_JOY1BUT3, "Joy1 b3"},
404 {KEY_JOY1BUT4, "Joy1 b4"},
405 {KEY_JOY1BUT5, "Joy1 b5"},
406 {KEY_JOY1BUT6, "Joy1 b6"},
407 {KEY_JOY1BUT7, "Joy1 b7"},
408 {KEY_JOY1BUT8, "Joy1 b8"},
409 {KEY_JOY1BUT9, "Joy1 b9"},
410 {KEY_JOY1BUT10, "Joy1 b10"},
411 {KEY_JOY1BUT11, "Joy1 b11"},
412 {KEY_JOY1BUT12, "Joy1 b12"},
413 {KEY_JOY1BUT13, "Joy1 b13"},
414 {KEY_JOY1BUT14, "Joy1 b14"},
415 {KEY_JOY1BUT15, "Joy1 b15"},
416
417 {KEY_JOY2BUT0, "Joy2 b0"},
418 {KEY_JOY2BUT1, "Joy2 b1"},
419 {KEY_JOY2BUT2, "Joy2 b2"},
420 {KEY_JOY2BUT3, "Joy2 b3"},
421 {KEY_JOY2BUT4, "Joy2 b4"},
422 {KEY_JOY2BUT5, "Joy2 b5"},
423 {KEY_JOY2BUT6, "Joy2 b6"},
424 {KEY_JOY2BUT7, "Joy2 b7"},
425 {KEY_JOY2BUT8, "Joy2 b8"},
426 {KEY_JOY2BUT9, "Joy2 b9"},
427 {KEY_JOY2BUT10, "Joy2 b10"},
428 {KEY_JOY2BUT11, "Joy2 b11"},
429 {KEY_JOY2BUT12, "Joy2 b12"},
430 {KEY_JOY2BUT13, "Joy2 b13"},
431 {KEY_JOY2BUT14, "Joy2 b14"},
432 {KEY_JOY2BUT15, "Joy2 b15"},
433
434 {KEY_JOY3BUT0, "Joy3 b0"},
435 {KEY_JOY3BUT1, "Joy3 b1"},
436 {KEY_JOY3BUT2, "Joy3 b2"},
437 {KEY_JOY3BUT3, "Joy3 b3"},
438 {KEY_JOY3BUT4, "Joy3 b4"},
439 {KEY_JOY3BUT5, "Joy3 b5"},
440 {KEY_JOY3BUT6, "Joy3 b6"},
441 {KEY_JOY3BUT7, "Joy3 b7"},
442 {KEY_JOY3BUT8, "Joy3 b8"},
443 {KEY_JOY3BUT9, "Joy3 b9"},
444 {KEY_JOY3BUT10, "Joy3 b10"},
445 {KEY_JOY3BUT11, "Joy3 b11"},
446 {KEY_JOY3BUT12, "Joy3 b12"},
447 {KEY_JOY3BUT13, "Joy3 b13"},
448 {KEY_JOY3BUT14, "Joy3 b14"},
449 {KEY_JOY3BUT15, "Joy3 b15"},
450
451 {KEY_JOY0HATUP, "Joy0 hu"},
452 {KEY_JOY0HATRIGHT, "Joy0 hr"},
453 {KEY_JOY0HATDOWN, "Joy0 hd"},
454 {KEY_JOY0HATLEFT, "Joy0 hl"},
455
456 {KEY_JOY1HATUP, "Joy1 hu"},
457 {KEY_JOY1HATRIGHT, "Joy1 hr"},
458 {KEY_JOY1HATDOWN, "Joy1 hd"},
459 {KEY_JOY1HATLEFT, "Joy1 hl"},
460
461 {KEY_JOY2HATUP, "Joy2 hu"},
462 {KEY_JOY2HATRIGHT, "Joy2 hr"},
463 {KEY_JOY2HATDOWN, "Joy2 hd"},
464 {KEY_JOY2HATLEFT, "Joy2 hl"},
465
466 {KEY_JOY3HATUP, "Joy3 hu"},
467 {KEY_JOY3HATRIGHT, "Joy3 hr"},
468 {KEY_JOY3HATDOWN, "Joy3 hd"},
469 {KEY_JOY3HATLEFT, "Joy3 hl"},
470
471 {KEY_JOY0LEFTTRIGGER, "Joy0 lt"},
472 {KEY_JOY0RIGHTTRIGGER, "Joy0 rt"},
473
474 {KEY_JOY1LEFTTRIGGER, "Joy1 lt"},
475 {KEY_JOY1RIGHTTRIGGER, "Joy1 rt"},
476
477 {KEY_JOY2LEFTTRIGGER, "Joy2 lt"},
478 {KEY_JOY2RIGHTTRIGGER, "Joy2 rt"},
479
480 {KEY_JOY3LEFTTRIGGER, "Joy3 lt"},
481 {KEY_JOY3RIGHTTRIGGER, "Joy3 rt"},
482 };
483
484 // Index gamecontrols_e
485 char *gamecontrolname[num_gamecontrols] =
486 {
487 "nothing", //a key/button mapped to gc_null has no effect
488 "forward",
489 "backward",
490 "strafe",
491 "straferight",
492 "strafeleft",
493 "speed",
494 "turnleft",
495 "turnright",
496 "fire",
497 "use",
498 "lookup",
499 "lookdown",
500 "centerview",
501 "mouseaiming",
502 "weapon1",
503 "weapon2",
504 "weapon3",
505 "weapon4",
506 "weapon5",
507 "weapon6",
508 "weapon7",
509 "weapon8",
510 "talkkey",
511 "scores",
512 "jump",
513 "console",
514 "nextweapon",
515 "prevweapon",
516 "bestweapon",
517 "inventorynext",
518 "inventoryprev",
519 "inventoryuse",
520 "down",
521 "screenshot",
522 // Mouse and joystick only, Fixed assignment for keyboard.
523 "menuesc", // joystick enter menu, and menu escape key
524 "pause",
525 "automap",
526 };
527
528 #define NUMKEYNAMES (sizeof(keynames)/sizeof(keyname_t))
529
530 //
531 // Detach any keys associated to the given game control
532 // - pass the pointer to the gamecontrol table for the player being edited
G_Clear_ControlKeys(int (* setupcontrols)[2],int control)533 void G_Clear_ControlKeys (int (*setupcontrols)[2], int control)
534 {
535 setupcontrols[control][0] = KEY_NULL;
536 setupcontrols[control][1] = KEY_NULL;
537 }
538
539 //
540 // Returns the name of a key (or virtual key for mouse and joy)
541 // the input value being an keynum
542 //
G_KeynumToString(int keynum)543 char* G_KeynumToString (int keynum)
544 {
545 static char keynamestr[8];
546
547 int j;
548
549 // return a string with the ascii char if displayable
550 if (keynum>' ' && keynum<='z' && keynum!=KEY_CONSOLE)
551 {
552 keynamestr[0] = keynum;
553 keynamestr[1] = '\0';
554 return keynamestr;
555 }
556
557 // find a description for special keys
558 for (j=0;j<NUMKEYNAMES;j++)
559 {
560 if (keynames[j].keynum==keynum)
561 return keynames[j].name;
562 }
563
564 // create a name for Unknown key
565 sprintf(keynamestr,"key%d",keynum);
566 return keynamestr;
567 }
568
569
G_KeyStringtoNum(char * keystr)570 int G_KeyStringtoNum(char *keystr)
571 {
572 int j;
573 int len = strlen(keystr);
574 byte stat = 0;
575
576
577 if(keystr[1]==0 && keystr[0]>' ' && keystr[0]<='z')
578 return keystr[0];
579
580 retry_search:
581 // caseless comparison, uppercase or lowercase input will work
582 for (j=0; j<NUMKEYNAMES; j++)
583 {
584 if (strcasecmp(keynames[j].name,keystr)==0)
585 return keynames[j].keynum;
586 }
587
588 // failed, try to change _ to space
589 if( stat == 0 )
590 {
591 // [WDJ] Got tired trying to fix bugs about a quoted button name
592 // within a the quoted script string like alias.
593 // Let them specify the button name with underlines and we will
594 // equate it to the name with spaces, and it does not require those
595 // escaped quotes.
596 // mouse_3 --> "mouse 3"
597 for (j=0; j<len; j++ )
598 {
599 if ( keystr[j] == '_' )
600 {
601 keystr[j] = ' ';
602 stat = 1;
603 }
604 }
605 if ( stat ) goto retry_search; // found some '_', try it again
606 }
607 // not found, try to interpret it as a number
608
609 if(strlen(keystr)>3)
610 return atoi(&keystr[3]);
611
612 return 0;
613 }
614
615
G_Controldefault(void)616 void G_Controldefault(void)
617 {
618 gamecontrol[gc_forward ][0]=KEY_UPARROW;
619 gamecontrol[gc_forward ][1]=KEY_MOUSE1+2;
620 gamecontrol[gc_backward ][0]=KEY_DOWNARROW;
621 gamecontrol[gc_strafe ][0]=KEY_LALT;
622 gamecontrol[gc_strafe ][1]=KEY_MOUSE1+1;
623 gamecontrol[gc_straferight][0]='.';
624 gamecontrol[gc_strafeleft ][0]=',';
625 gamecontrol[gc_speed ][0]=KEY_LSHIFT;
626 gamecontrol[gc_turnleft ][0]=KEY_LEFTARROW;
627 gamecontrol[gc_turnright ][0]=KEY_RIGHTARROW;
628 gamecontrol[gc_fire ][0]=KEY_RCTRL;
629 gamecontrol[gc_fire ][1]=KEY_MOUSE1;
630 gamecontrol[gc_use ][0]=KEY_SPACE;
631 gamecontrol[gc_lookup ][0]=KEY_PGUP;
632 gamecontrol[gc_lookdown ][0]=KEY_PGDN;
633 gamecontrol[gc_centerview ][0]=KEY_END;
634 gamecontrol[gc_mouseaiming][0]='s';
635 gamecontrol[gc_weapon1 ][0]='1';
636 gamecontrol[gc_weapon2 ][0]='2';
637 gamecontrol[gc_weapon3 ][0]='3';
638 gamecontrol[gc_weapon4 ][0]='4';
639 gamecontrol[gc_weapon5 ][0]='5';
640 gamecontrol[gc_weapon6 ][0]='6';
641 gamecontrol[gc_weapon7 ][0]='7';
642 gamecontrol[gc_weapon8 ][0]='8';
643 gamecontrol[gc_talkkey ][0]='t';
644 gamecontrol[gc_scores ][0]='f';
645 gamecontrol[gc_jump ][0]='/';
646 gamecontrol[gc_console ][0]=KEY_CONSOLE;
647 //gamecontrol[gc_nextweapon ][1]=KEY_JOY0BUT4;
648 //gamecontrol[gc_prevweapon ][1]=KEY_JOY0BUT5;
649 gamecontrol[gc_screenshot ][0]=KEY_SYSREQ;
650
651 if( gamemode == heretic )
652 {
653 gamecontrol[gc_invnext ][0] = ']';
654 gamecontrol[gc_invprev ][0] = '[';
655 gamecontrol[gc_invuse ][0] = KEY_ENTER;
656 gamecontrol[gc_jump ][0] = KEY_INS;
657 gamecontrol[gc_flydown ][0] = KEY_DELETE;
658 }
659 else
660 {
661 gamecontrol[gc_nextweapon ][0]=']';
662 gamecontrol[gc_prevweapon ][0]='[';
663 }
664
665 // Mouse and joystick only, Fixed assignment for keyboard.
666 gamecontrol[gc_menuesc ][0]=KEY_JOY0BUT7; // Start button on Xbox360 controllers
667 gamecontrol[gc_pause ][0]=KEY_JOY0BUT6; // Back button on Xbox360 controllers
668 gamecontrol[gc_automap ][0]=KEY_JOY0BUT8;
669 }
670
G_SaveKeySetting(FILE * f)671 void G_SaveKeySetting(FILE *f)
672 {
673 int i;
674
675 for(i=1;i<num_gamecontrols;i++)
676 {
677 fprintf(f,"setcontrol \"%s\" \"%s\"",
678 gamecontrolname[i],
679 G_KeynumToString(gamecontrol[i][0]));
680
681 if(gamecontrol[i][1])
682 fprintf(f," \"%s\"\n",
683 G_KeynumToString(gamecontrol[i][1]));
684 else
685 fprintf(f,"\n");
686 }
687
688 for(i=1;i<num_gamecontrols;i++)
689 {
690 fprintf(f, "setcontrol2 \"%s\" \"%s\"",
691 gamecontrolname[i],
692 G_KeynumToString(gamecontrol2[i][0]));
693
694 if(gamecontrol2[i][1])
695 fprintf(f, " \"%s\"\n",
696 G_KeynumToString(gamecontrol2[i][1]));
697 else
698 fprintf(f,"\n");
699 }
700
701 // Writes the joystick axis binding commands to the config file.
702 for (i=0; i<num_joybindings; i++)
703 {
704 joybinding_t j = joybindings[i];
705 fprintf(f, "bindjoyaxis %d %d %d %d %f\n",
706 j.joynum, j.axisnum, j.playnum, (int)(j.action), j.scale);
707 }
708 }
709
G_CheckDoubleUsage(int keynum)710 void G_CheckDoubleUsage(int keynum)
711 {
712 if( cv_controlperkey.value==1 )
713 {
714 int i;
715 for(i=0;i<num_gamecontrols;i++)
716 {
717 if( gamecontrol[i][0]==keynum )
718 gamecontrol[i][0]= KEY_NULL;
719 if( gamecontrol[i][1]==keynum )
720 gamecontrol[i][1]= KEY_NULL;
721 if( gamecontrol2[i][0]==keynum )
722 gamecontrol2[i][0]= KEY_NULL;
723 if( gamecontrol2[i][1]==keynum )
724 gamecontrol2[i][1]= KEY_NULL;
725 }
726 }
727 }
728
729 static
setcontrol(int (* gc)[2],const char * cstr)730 void setcontrol(int (*gc)[2], const char * cstr)
731 {
732 int numctrl;
733 char *namectrl;
734 int keynum;
735 COM_args_t carg;
736
737 COM_Args( &carg );
738
739 if ( carg.num!= 3 && carg.num!=4 )
740 {
741 CONS_Printf ("setcontrol%s <controlname> <keyname> [<2nd keyname>]\n", cstr);
742 return;
743 }
744
745 namectrl=carg.arg[1];
746 for(numctrl=0;numctrl<num_gamecontrols
747 && strcasecmp(namectrl,gamecontrolname[numctrl])
748 ;numctrl++);
749 if(numctrl==num_gamecontrols)
750 {
751 CONS_Printf("Control '%s' unknown\n",namectrl);
752 return;
753 }
754 keynum=G_KeyStringtoNum(carg.arg[2]);
755 G_CheckDoubleUsage(keynum);
756 gc[numctrl][0]=keynum;
757
758 if(carg.num==4)
759 gc[numctrl][1]=G_KeyStringtoNum(carg.arg[3]);
760 else
761 gc[numctrl][1]=0;
762 }
763
Command_Setcontrol_f(void)764 void Command_Setcontrol_f(void)
765 {
766 setcontrol(gamecontrol, "");
767 }
768
Command_Setcontrol2_f(void)769 void Command_Setcontrol2_f(void)
770 {
771 setcontrol(gamecontrol2, "2");
772 }
773
774
775
776 //! Magically converts a console command to a joystick axis binding. Also releases bindings.
Command_BindJoyaxis_f()777 void Command_BindJoyaxis_f()
778 {
779 joybinding_t j;
780 unsigned int i;
781 COM_args_t carg;
782
783 COM_Args( &carg );
784
785 if(carg.num == 1)
786 { // Print bindings.
787 CONS_Printf("%d joysticks found.\n", num_joysticks);
788 if(num_joybindings == 0) {
789 CONS_Printf("No joystick axis bindings defined.\n");
790 return;
791 }
792 CONS_Printf("Current axis bindings.\n");
793 for(i=0; i<num_joybindings; i++) {
794 j = joybindings[i];
795 CONS_Printf("%d %d %d %d %f\n", j.joynum, j.axisnum,
796 j.playnum, (int)j.action, j.scale);
797 }
798 return;
799 }
800
801 if (carg.num == 4 || carg.num > 6)
802 {
803 CONS_Printf("bindjoyaxis [joynum] [axisnum] [playnum] [action] [scale] to bind\n"
804 "bindjoyaxis [joynum] [axisnum] to unbind\n");
805 return;
806 }
807
808 j.joynum = atoi( carg.arg[1] );
809 if(j.joynum < 0 || j.joynum >= num_joysticks)
810 {
811 CONS_Printf("Attempting to bind/release non-existent joystick %d.\n", j.joynum);
812 return;
813 }
814
815 j.axisnum = (carg.num >= 3) ? atoi( carg.arg[2] ) : -1;
816 if(j.axisnum < -1 || j.axisnum >= I_JoystickNumAxes(j.joynum))
817 {
818 CONS_Printf("Attempting to bind/release non-existent axis %d.\n", j.axisnum);
819 return;
820 }
821
822 if (carg.num == 3)
823 { // release binding(s)
824 /* Takes one or two parameters. The first one is the joystick number
825 and the second is the axis number. If either is not specified, all
826 values are assumed to match.
827 */
828
829 int num_keep_bindings = 0;
830 joybinding_t keep_bindings[MAX_JOYBINDINGS];
831
832 if(num_joybindings == 0)
833 {
834 CONS_Printf("No bindings to unset.\n");
835 return;
836 }
837
838 unsigned int i;
839 for(i=0; i<num_joybindings; i++)
840 {
841 joybinding_t temp = joybindings[i];
842 if((j.joynum == temp.joynum) &&
843 (j.axisnum == -1 || j.axisnum == temp.axisnum))
844 continue; // We have a binding to prune.
845
846 keep_bindings[num_keep_bindings++] = temp; // keep it
847 }
848
849 // We have the new bindings.
850 if (num_keep_bindings == num_joybindings)
851 {
852 CONS_Printf("No bindings matched the parameters.\n");
853 return;
854 }
855
856 // replace the bindings
857 num_joybindings = num_keep_bindings;
858 for(i=0; i<num_keep_bindings; i++)
859 joybindings[i] = keep_bindings[i];
860 }
861 else
862 { // create a binding
863 j.playnum = atoi( carg.arg[3] );
864 // carg.arg[0..3] only, use COM_Argv for others
865 j.action = (joyactions_e)(atoi(COM_Argv(4)));
866 if (carg.num == 6)
867 j.scale = atof(COM_Argv(5));
868 else
869 j.scale = 1.0f;
870
871 if(j.action < 0 || j.action >= num_joyactions)
872 {
873 CONS_Printf("Attempting to bind non-existent action %d.\n", (int)(j.action));
874 return;
875 }
876
877 // Overwrite existing binding, if any. Otherwise just append.
878 for(i=0; i<num_joybindings; i++)
879 {
880 joybinding_t j2 = joybindings[i];
881 if(j2.joynum == j.joynum && j2.axisnum == j.axisnum)
882 {
883 joybindings[i] = j;
884 CONS_Printf("Joystick binding modified.\n");
885 return;
886 }
887 }
888 // new binding
889 if (num_joybindings < MAX_JOYBINDINGS)
890 {
891 joybindings[num_joybindings++] = j;
892 CONS_Printf("Joystick binding added.\n");
893 }
894 else
895 CONS_Printf("Maximum number of joystick bindings reached.\n");
896 }
897 }
898