DEADSOFTWARE

1c27249fc44465151cf00dc129c9bf85fa6a5f51
[d2df-sdl.git] / src / engine / e_input.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit e_input;
19 interface
21 uses
22 SysUtils,
23 e_log,
24 SDL2;
26 const
27 e_MaxKbdKeys = SDL_NUM_SCANCODES;
28 e_MaxJoys = 4;
29 e_MaxJoyBtns = 32;
30 e_MaxJoyAxes = 8;
31 e_MaxJoyHats = 8;
32 e_MaxVirtKeys = 48;
34 e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
36 e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
37 // $$$..$$$ - 321 Keyboard buttons/keys
38 // $$$..$$$ - 4*32 Joystick buttons
39 // $$$..$$$ - 8*2 Joystick axes (- and +)
40 // $$$..$$$ - 4*4 Joystick hats (L U R D)
41 // $$$..$$$ - 48 Virtual buttons/keys
43 // these are apparently used in g_gui and g_game and elsewhere
44 IK_INVALID = 65535;
45 IK_ESCAPE = SDL_SCANCODE_ESCAPE;
46 IK_RETURN = SDL_SCANCODE_RETURN;
47 IK_KPRETURN= SDL_SCANCODE_KP_ENTER;
48 IK_ENTER = SDL_SCANCODE_RETURN;
49 IK_UP = SDL_SCANCODE_UP;
50 IK_KPUP = SDL_SCANCODE_KP_8;
51 IK_DOWN = SDL_SCANCODE_DOWN;
52 IK_KPDOWN = SDL_SCANCODE_KP_2;
53 IK_LEFT = SDL_SCANCODE_LEFT;
54 IK_KPLEFT = SDL_SCANCODE_KP_4;
55 IK_RIGHT = SDL_SCANCODE_RIGHT;
56 IK_KPRIGHT = SDL_SCANCODE_KP_6;
57 IK_DELETE = SDL_SCANCODE_DELETE;
58 IK_HOME = SDL_SCANCODE_HOME;
59 IK_KPHOME = SDL_SCANCODE_KP_7;
60 IK_INSERT = SDL_SCANCODE_INSERT;
61 IK_SPACE = SDL_SCANCODE_SPACE;
62 IK_CONTROL = SDL_SCANCODE_LCTRL;
63 IK_SHIFT = SDL_SCANCODE_LSHIFT;
64 IK_TAB = SDL_SCANCODE_TAB;
65 IK_PAGEUP = SDL_SCANCODE_PAGEUP;
66 IK_KPPAGEUP= SDL_SCANCODE_KP_9;
67 IK_PAGEDN = SDL_SCANCODE_PAGEDOWN;
68 IK_KPPAGEDN= SDL_SCANCODE_KP_3;
69 IK_F2 = SDL_SCANCODE_F2;
70 IK_F3 = SDL_SCANCODE_F3;
71 IK_F4 = SDL_SCANCODE_F4;
72 IK_F5 = SDL_SCANCODE_F5;
73 IK_F6 = SDL_SCANCODE_F6;
74 IK_F7 = SDL_SCANCODE_F7;
75 IK_F8 = SDL_SCANCODE_F8;
76 IK_F9 = SDL_SCANCODE_F9;
77 IK_F10 = SDL_SCANCODE_F10;
78 IK_END = SDL_SCANCODE_END;
79 IK_KPEND = SDL_SCANCODE_KP_1;
80 IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
81 IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
82 IK_GRAVE = SDL_SCANCODE_GRAVE;
83 IK_PAUSE = SDL_SCANCODE_PAUSE;
84 IK_Y = SDL_SCANCODE_Y;
85 IK_N = SDL_SCANCODE_N;
86 // TODO: think of something better than this shit
87 IK_LASTKEY = SDL_NUM_SCANCODES-1;
89 VK_FIRSTKEY = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys;
90 VK_LEFT = VK_FIRSTKEY + 0;
91 VK_RIGHT = VK_FIRSTKEY + 1;
92 VK_UP = VK_FIRSTKEY + 2;
93 VK_DOWN = VK_FIRSTKEY + 3;
94 VK_FIRE = VK_FIRSTKEY + 4;
95 VK_OPEN = VK_FIRSTKEY + 5;
96 VK_JUMP = VK_FIRSTKEY + 6;
97 VK_CHAT = VK_FIRSTKEY + 7;
98 VK_ESCAPE = VK_FIRSTKEY + 8;
99 VK_0 = VK_FIRSTKEY + 9;
100 VK_1 = VK_FIRSTKEY + 10;
101 VK_2 = VK_FIRSTKEY + 11;
102 VK_3 = VK_FIRSTKEY + 12;
103 VK_4 = VK_FIRSTKEY + 13;
104 VK_5 = VK_FIRSTKEY + 14;
105 VK_6 = VK_FIRSTKEY + 15;
106 VK_7 = VK_FIRSTKEY + 16;
107 VK_8 = VK_FIRSTKEY + 17;
108 VK_9 = VK_FIRSTKEY + 18;
109 VK_A = VK_FIRSTKEY + 19;
110 VK_B = VK_FIRSTKEY + 20;
111 VK_C = VK_FIRSTKEY + 21;
112 VK_D = VK_FIRSTKEY + 22;
113 VK_E = VK_FIRSTKEY + 23;
114 VK_F = VK_FIRSTKEY + 24;
115 VK_CONSOLE = VK_FIRSTKEY + 25;
116 VK_STATUS = VK_FIRSTKEY + 26;
117 VK_TEAM = VK_FIRSTKEY + 27;
118 VK_PREV = VK_FIRSTKEY + 28;
119 VK_NEXT = VK_FIRSTKEY + 29;
120 VK_STRAFE = VK_FIRSTKEY + 30;
121 VK_LSTRAFE = VK_FIRSTKEY + 31;
122 VK_RSTRAFE = VK_FIRSTKEY + 32;
123 VK_PRINTSCR = VK_FIRSTKEY + 33;
124 VK_LASTKEY = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
126 AX_MINUS = 0;
127 AX_PLUS = 1;
128 HAT_LEFT = 0;
129 HAT_UP = 1;
130 HAT_RIGHT = 2;
131 HAT_DOWN = 3;
133 function e_InitInput(): Boolean;
134 procedure e_ReleaseInput();
135 procedure e_ClearInputBuffer();
136 //function e_PollInput(): Boolean;
137 procedure e_PollJoysticks(); // call this from message loop to update joysticks
138 function e_KeyPressed(Key: Word): Boolean;
139 function e_AnyKeyPressed(): Boolean;
140 function e_GetFirstKeyPressed(): Word;
141 function e_JoystickStateToString(mode: Integer): String;
142 function e_JoyByHandle(handle: Word): Integer;
143 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
144 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
145 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
146 procedure e_SetKeyState(key: Word; state: Integer);
148 procedure e_UnpressAllKeys ();
149 procedure e_KeyUpDown (key: Word; down: Boolean);
151 var
152 {e_MouseInfo: TMouseInfo;}
153 e_EnableInput: Boolean = False;
154 e_JoysticksAvailable: Byte = 0;
155 e_JoystickDeadzones: array [0..e_MaxJoys-1] of Integer = (8192, 8192, 8192, 8192);
156 e_KeyNames: array [0..e_MaxInputKeys] of String;
158 implementation
160 uses Math;
162 const
163 KBRD_END = e_MaxKbdKeys;
164 JOYK_BEG = KBRD_END;
165 JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
166 JOYA_BEG = JOYK_END;
167 JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
168 JOYH_BEG = JOYA_END;
169 JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
170 VIRT_BEG = JOYH_END;
171 VIRT_END = VIRT_BEG + e_MaxVirtKeys;
173 type
174 TJoystick = record
175 ID: Byte;
176 Handle: PSDL_Joystick;
177 Axes: Byte;
178 Buttons: Byte;
179 Hats: Byte;
180 ButtBuf: array [0..e_MaxJoyBtns] of Boolean;
181 AxisBuf: array [0..e_MaxJoyAxes] of Integer;
182 AxisZero: array [0..e_MaxJoyAxes] of Integer;
183 HatBuf: array [0..e_MaxJoyHats] of array [HAT_LEFT..HAT_DOWN] of Boolean;
184 end;
186 var
187 KeyBuffer: array [0..e_MaxKbdKeys] of Boolean;
188 VirtBuffer: array [0..e_MaxVirtKeys] of Boolean;
189 Joysticks: array of TJoystick = nil;
191 function OpenJoysticks(): Byte;
192 var
193 i, j, k, c: Integer;
194 joy: PSDL_Joystick;
195 begin
196 Result := 0;
197 k := Min(e_MaxJoys, SDL_NumJoysticks());
198 if k = 0 then Exit;
199 c := 0;
200 for i := 0 to k do
201 begin
202 joy := SDL_JoystickOpen(i);
203 if joy <> nil then
204 begin
205 Inc(c);
206 e_WriteLog('Input: Opened SDL joystick ' + IntToStr(i) + ' (' + SDL_JoystickName(joy) +
207 ') as joystick ' + IntToStr(c) + ':', TMsgType.Notify);
208 SetLength(Joysticks, c);
209 with Joysticks[c-1] do
210 begin
211 ID := i;
212 Handle := joy;
213 Axes := Min(e_MaxJoyAxes, SDL_JoystickNumAxes(joy));
214 Buttons := Min(e_MaxJoyBtns, SDL_JoystickNumButtons(joy));
215 Hats := Min(e_MaxJoyHats, SDL_JoystickNumHats(joy));
216 // TODO: find proper solution for this xbox trigger shit
217 for j := 0 to Axes do AxisZero[j] := SDL_JoystickGetAxis(joy, j);
218 e_WriteLog(' ' + IntToStr(Axes) + ' axes, ' + IntToStr(Buttons) + ' buttons, ' +
219 IntToStr(Hats) + ' hats.', TMsgType.Notify);
220 end;
221 end;
222 end;
223 Result := c;
224 end;
226 procedure ReleaseJoysticks();
227 var
228 i: Integer;
229 begin
230 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
231 for i := Low(Joysticks) to High(Joysticks) do
232 with Joysticks[i] do
233 SDL_JoystickClose(Handle);
234 SetLength(Joysticks, 0);
235 end;
238 procedure e_UnpressAllKeys ();
239 var
240 i: Integer;
241 begin
242 for i := 0 to High(KeyBuffer) do KeyBuffer[i] := False;
243 for i := 0 to High(VirtBuffer) do VirtBuffer[i] := False;
244 end;
247 procedure e_KeyUpDown (key: Word; down: Boolean);
248 begin
249 if (key > 0) and (key < Length(KeyBuffer)) then KeyBuffer[key] := down
250 else if (key >= VIRT_BEG) and (key < VIRT_END) then VirtBuffer[key - VIRT_BEG] := down
251 end;
254 function PollKeyboard(): Boolean;
256 var
257 Keys: PByte;
258 NKeys: Integer;
259 i: NativeUInt;
261 begin
262 Result := False;
264 Keys := SDL_GetKeyboardState(@NKeys);
265 if (Keys = nil) or (NKeys < 1) then Exit;
266 for i := 0 to NKeys do
267 begin
268 if ((PByte(NativeUInt(Keys) + i)^) <> 0) then KeyBuffer[i] := false;
269 end;
270 for i := NKeys to High(KeyBuffer) do KeyBuffer[i] := False;
272 end;
274 procedure e_PollJoysticks();
275 var
276 i, j: Word;
277 hat: Byte;
278 begin
279 //Result := False;
280 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
281 SDL_JoystickUpdate();
282 for j := Low(Joysticks) to High(Joysticks) do
283 begin
284 with Joysticks[j] do
285 begin
286 for i := 0 to Buttons do ButtBuf[i] := SDL_JoystickGetButton(Handle, i) <> 0;
287 for i := 0 to Axes do AxisBuf[i] := SDL_JoystickGetAxis(Handle, i);
288 for i := 0 to Hats do
289 begin
290 hat := SDL_JoystickGetHat(Handle, i);
291 HatBuf[i, HAT_UP] := LongBool(hat and SDL_HAT_UP);
292 HatBuf[i, HAT_DOWN] := LongBool(hat and SDL_HAT_DOWN);
293 HatBuf[i, HAT_LEFT] := LongBool(hat and SDL_HAT_LEFT);
294 HatBuf[i, HAT_RIGHT] := LongBool(hat and SDL_HAT_RIGHT);
295 end;
296 end;
297 end;
298 end;
300 procedure GenerateKeyNames();
301 var
302 i, j, k: LongWord;
303 begin
304 // keyboard key names
305 for i := 0 to IK_LASTKEY do
306 e_KeyNames[i] := SDL_GetScancodeName(i);
308 // joysticks
309 for j := 0 to e_MaxJoys-1 do
310 begin
311 k := JOYK_BEG + j * e_MaxJoyBtns;
312 // buttons
313 for i := 0 to e_MaxJoyBtns-1 do
314 e_KeyNames[k + i] := Format('JOY%d B%d', [j, i]);
315 k := JOYA_BEG + j * e_MaxJoyAxes * 2;
316 // axes
317 for i := 0 to e_MaxJoyAxes-1 do
318 begin
319 e_KeyNames[k + i*2 ] := Format('JOY%d A%d+', [j, i]);
320 e_KeyNames[k + i*2 + 1] := Format('JOY%d A%d-', [j, i]);
321 end;
322 k := JOYH_BEG + j * e_MaxJoyHats * 4;
323 // hats
324 for i := 0 to e_MaxJoyHats-1 do
325 begin
326 e_KeyNames[k + i*4 ] := Format('JOY%d D%dL', [j, i]);
327 e_KeyNames[k + i*4 + 1] := Format('JOY%d D%dU', [j, i]);
328 e_KeyNames[k + i*4 + 2] := Format('JOY%d D%dR', [j, i]);
329 e_KeyNames[k + i*4 + 3] := Format('JOY%d D%dD', [j, i]);
330 end;
331 end;
333 // vitrual keys
334 for i := 0 to e_MaxVirtKeys-1 do
335 e_KeyNames[VIRT_BEG + i] := 'VIRTUAL ' + IntToStr(i);
336 end;
338 function e_InitInput(): Boolean;
339 begin
340 Result := False;
342 e_JoysticksAvailable := OpenJoysticks();
343 e_EnableInput := True;
344 GenerateKeyNames();
346 Result := True;
347 end;
349 procedure e_ReleaseInput();
350 begin
351 ReleaseJoysticks();
352 e_JoysticksAvailable := 0;
353 end;
355 procedure e_ClearInputBuffer();
356 var
357 i, j, d: Integer;
358 begin
359 for i := Low(KeyBuffer) to High(KeyBuffer) do
360 KeyBuffer[i] := False;
361 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then
362 for i := Low(Joysticks) to High(Joysticks) do
363 begin
364 for j := Low(Joysticks[i].ButtBuf) to High(Joysticks[i].ButtBuf) do
365 Joysticks[i].ButtBuf[j] := False;
366 for j := Low(Joysticks[i].AxisBuf) to High(Joysticks[i].AxisBuf) do
367 Joysticks[i].AxisBuf[j] := 0;
368 for j := Low(Joysticks[i].HatBuf) to High(Joysticks[i].HatBuf) do
369 for d := Low(Joysticks[i].HatBuf[j]) to High(Joysticks[i].HatBuf[j]) do
370 Joysticks[i].HatBuf[j, d] := False;
371 end;
372 for i := Low(VirtBuffer) to High(VirtBuffer) do
373 VirtBuffer[i] := False;
374 end;
377 function e_PollInput(): Boolean;
378 var
379 kb, js: Boolean;
380 begin
381 kb := PollKeyboard();
382 js := e_PollJoysticks();
384 Result := kb or js;
385 end;
388 function e_KeyPressed(Key: Word): Boolean;
389 var
390 joyi, dir: Integer;
391 begin
392 Result := False;
393 if (Key = IK_INVALID) or (Key = 0) then Exit;
395 if (Key < KBRD_END) then
396 begin // Keyboard buttons/keys
397 Result := KeyBuffer[Key];
398 end
400 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
401 begin // Joystick buttons
402 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
403 if JoyI >= e_JoysticksAvailable then
404 Result := False
405 else
406 begin
407 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
408 Result := Joysticks[JoyI].ButtBuf[Key];
409 end;
410 end
412 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
413 begin // Joystick axes
414 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
415 if JoyI >= e_JoysticksAvailable then
416 Result := False
417 else
418 begin
419 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
420 dir := Key mod 2;
421 if dir = AX_MINUS then
422 Result := Joysticks[JoyI].AxisBuf[Key div 2] <
423 Joysticks[JoyI].AxisZero[Key div 2] - e_JoystickDeadzones[JoyI]
424 else
425 Result := Joysticks[JoyI].AxisBuf[Key div 2] >
426 Joysticks[JoyI].AxisZero[Key div 2] + e_JoystickDeadzones[JoyI]
427 end;
428 end
430 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
431 begin // Joystick hats
432 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
433 if JoyI >= e_JoysticksAvailable then
434 Result := False
435 else
436 begin
437 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
438 dir := Key mod 4;
439 Result := Joysticks[JoyI].HatBuf[Key div 4, dir];
440 end;
441 end
443 else if (Key >= VIRT_BEG) and (Key < VIRT_END) then
444 Result := VirtBuffer[Key - VIRT_BEG]
445 end;
447 procedure e_SetKeyState(key: Word; state: Integer);
448 var
449 JoyI, dir: Integer;
450 begin
451 if (Key = IK_INVALID) or (Key = 0) then Exit;
453 if (Key < KBRD_END) then
454 begin // Keyboard buttons/keys
455 keyBuffer[key] := (state <> 0);
456 end
458 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
459 begin // Joystick buttons
460 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
461 if JoyI >= e_JoysticksAvailable then
462 Exit
463 else
464 begin
465 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
466 Joysticks[JoyI].ButtBuf[Key] := (state <> 0);
467 end;
468 end
470 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
471 begin // Joystick axes
472 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
473 if JoyI >= e_JoysticksAvailable then
474 Exit
475 else
476 begin
477 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
478 Joysticks[JoyI].AxisBuf[Key div 2] := state;
479 end;
480 end
482 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
483 begin // Joystick hats
484 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
485 if JoyI >= e_JoysticksAvailable then
486 Exit
487 else
488 begin
489 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
490 dir := Key mod 4;
491 Joysticks[JoyI].HatBuf[Key div 4, dir] := (state <> 0);
492 end;
493 end
495 else if (Key >= VIRT_BEG) and (Key < VIRT_END) then
496 VirtBuffer[Key - VIRT_BEG] := (state <> 0)
497 end;
499 function e_AnyKeyPressed(): Boolean;
500 var
501 k: Word;
502 begin
503 Result := False;
505 for k := 1 to e_MaxInputKeys do
506 if e_KeyPressed(k) then
507 begin
508 Result := True;
509 Break;
510 end;
511 end;
513 function e_GetFirstKeyPressed(): Word;
514 var
515 k: Word;
516 begin
517 Result := IK_INVALID;
519 for k := 1 to e_MaxInputKeys do
520 if e_KeyPressed(k) then
521 begin
522 Result := k;
523 Break;
524 end;
525 end;
527 ////////////////////////////////////////////////////////////////////////////////
529 function e_JoystickStateToString(mode: Integer): String;
530 begin
531 Result := '';
532 end;
534 function e_JoyByHandle(handle: Word): Integer;
535 var
536 i: Integer;
537 begin
538 Result := -1;
539 if Joysticks = nil then Exit;
540 for i := Low(Joysticks) to High(Joysticks) do
541 if Joysticks[i].ID = handle then
542 begin
543 Result := i;
544 Exit;
545 end;
546 end;
548 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
549 begin
550 Result := 0;
551 if id >= Length(Joysticks) then Exit;
552 Result := JOYK_BEG + id*e_MaxJoyBtns + btn;
553 end;
555 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
556 begin
557 Result := 0;
558 if id >= Length(Joysticks) then Exit;
559 Result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir;
560 end;
562 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
563 begin
564 Result := 0;
565 if id >= Length(Joysticks) then Exit;
566 Result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir;
567 end;
569 end.