DEADSOFTWARE

fixed keyboard polling (no more); ESC should work in several places where it should...
[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;
33 e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
35 e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys - 1;
36 // $$$..$$$ - 321 Keyboard buttons/keys
37 // $$$..$$$ - 4*32 Joystick buttons
38 // $$$..$$$ - 8*2 Joystick axes (- and +)
39 // $$$..$$$ - 4*4 Joystick hats (L U R D)
41 // these are apparently used in g_gui and g_game and elsewhere
42 IK_INVALID = 65535;
43 IK_ESCAPE = SDL_SCANCODE_ESCAPE;
44 IK_RETURN = SDL_SCANCODE_RETURN;
45 IK_KPRETURN= SDL_SCANCODE_KP_ENTER;
46 IK_ENTER = SDL_SCANCODE_RETURN;
47 IK_UP = SDL_SCANCODE_UP;
48 IK_KPUP = SDL_SCANCODE_KP_8;
49 IK_DOWN = SDL_SCANCODE_DOWN;
50 IK_KPDOWN = SDL_SCANCODE_KP_2;
51 IK_LEFT = SDL_SCANCODE_LEFT;
52 IK_KPLEFT = SDL_SCANCODE_KP_4;
53 IK_RIGHT = SDL_SCANCODE_RIGHT;
54 IK_KPRIGHT = SDL_SCANCODE_KP_6;
55 IK_DELETE = SDL_SCANCODE_DELETE;
56 IK_HOME = SDL_SCANCODE_HOME;
57 IK_KPHOME = SDL_SCANCODE_KP_7;
58 IK_INSERT = SDL_SCANCODE_INSERT;
59 IK_SPACE = SDL_SCANCODE_SPACE;
60 IK_CONTROL = SDL_SCANCODE_LCTRL;
61 IK_SHIFT = SDL_SCANCODE_LSHIFT;
62 IK_TAB = SDL_SCANCODE_TAB;
63 IK_PAGEUP = SDL_SCANCODE_PAGEUP;
64 IK_KPPAGEUP= SDL_SCANCODE_KP_9;
65 IK_PAGEDN = SDL_SCANCODE_PAGEDOWN;
66 IK_KPPAGEDN= SDL_SCANCODE_KP_3;
67 IK_F2 = SDL_SCANCODE_F2;
68 IK_F3 = SDL_SCANCODE_F3;
69 IK_F4 = SDL_SCANCODE_F4;
70 IK_F5 = SDL_SCANCODE_F5;
71 IK_F6 = SDL_SCANCODE_F6;
72 IK_F7 = SDL_SCANCODE_F7;
73 IK_F8 = SDL_SCANCODE_F8;
74 IK_F9 = SDL_SCANCODE_F9;
75 IK_F10 = SDL_SCANCODE_F10;
76 IK_END = SDL_SCANCODE_END;
77 IK_KPEND = SDL_SCANCODE_KP_1;
78 IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
79 IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
80 IK_GRAVE = SDL_SCANCODE_GRAVE;
81 IK_PAUSE = SDL_SCANCODE_PAUSE;
82 IK_Y = SDL_SCANCODE_Y;
83 IK_N = SDL_SCANCODE_N;
84 // TODO: think of something better than this shit
85 IK_LASTKEY = SDL_NUM_SCANCODES-1;
87 AX_MINUS = 0;
88 AX_PLUS = 1;
89 HAT_LEFT = 0;
90 HAT_UP = 1;
91 HAT_RIGHT = 2;
92 HAT_DOWN = 3;
94 function e_InitInput(): Boolean;
95 procedure e_ReleaseInput();
96 procedure e_ClearInputBuffer();
97 //function e_PollInput(): Boolean;
98 procedure e_PollJoysticks(); // call this from message loop to update joysticks
99 function e_KeyPressed(Key: Word): Boolean;
100 function e_AnyKeyPressed(): Boolean;
101 function e_GetFirstKeyPressed(): Word;
102 function e_JoystickStateToString(mode: Integer): String;
103 function e_JoyByHandle(handle: Word): Integer;
104 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
105 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
106 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
107 procedure e_SetKeyState(key: Word; state: Integer);
109 procedure e_UnpressAllKeys ();
110 procedure e_KeyUpDown (key: Word; down: Boolean);
112 var
113 {e_MouseInfo: TMouseInfo;}
114 e_EnableInput: Boolean = False;
115 e_JoysticksAvailable: Byte = 0;
116 e_JoystickDeadzones: array [0..e_MaxJoys-1] of Integer = (8192, 8192, 8192, 8192);
117 e_KeyNames: array [0..e_MaxInputKeys] of String;
119 implementation
121 uses Math;
123 const
124 KBRD_END = e_MaxKbdKeys;
125 JOYK_BEG = KBRD_END;
126 JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
127 JOYA_BEG = JOYK_END;
128 JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
129 JOYH_BEG = JOYA_END;
130 JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
132 type
133 TJoystick = record
134 ID: Byte;
135 Handle: PSDL_Joystick;
136 Axes: Byte;
137 Buttons: Byte;
138 Hats: Byte;
139 ButtBuf: array [0..e_MaxJoyBtns] of Boolean;
140 AxisBuf: array [0..e_MaxJoyAxes] of Integer;
141 AxisZero: array [0..e_MaxJoyAxes] of Integer;
142 HatBuf: array [0..e_MaxJoyHats] of array [HAT_LEFT..HAT_DOWN] of Boolean;
143 end;
145 var
146 KeyBuffer: array [0..e_MaxKbdKeys] of Boolean;
147 Joysticks: array of TJoystick = nil;
149 function OpenJoysticks(): Byte;
150 var
151 i, j, k, c: Integer;
152 joy: PSDL_Joystick;
153 begin
154 Result := 0;
155 k := Min(e_MaxJoys, SDL_NumJoysticks());
156 if k = 0 then Exit;
157 c := 0;
158 for i := 0 to k do
159 begin
160 joy := SDL_JoystickOpen(i);
161 if joy <> nil then
162 begin
163 Inc(c);
164 e_WriteLog('Input: Opened SDL joystick ' + IntToStr(i) + ' (' + SDL_JoystickName(joy) +
165 ') as joystick ' + IntToStr(c) + ':', TMsgType.Notify);
166 SetLength(Joysticks, c);
167 with Joysticks[c-1] do
168 begin
169 ID := i;
170 Handle := joy;
171 Axes := Min(e_MaxJoyAxes, SDL_JoystickNumAxes(joy));
172 Buttons := Min(e_MaxJoyBtns, SDL_JoystickNumButtons(joy));
173 Hats := Min(e_MaxJoyHats, SDL_JoystickNumHats(joy));
174 // TODO: find proper solution for this xbox trigger shit
175 for j := 0 to Axes do AxisZero[j] := SDL_JoystickGetAxis(joy, j);
176 e_WriteLog(' ' + IntToStr(Axes) + ' axes, ' + IntToStr(Buttons) + ' buttons, ' +
177 IntToStr(Hats) + ' hats.', TMsgType.Notify);
178 end;
179 end;
180 end;
181 Result := c;
182 end;
184 procedure ReleaseJoysticks();
185 var
186 i: Integer;
187 begin
188 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
189 for i := Low(Joysticks) to High(Joysticks) do
190 with Joysticks[i] do
191 SDL_JoystickClose(Handle);
192 SetLength(Joysticks, 0);
193 end;
196 procedure e_UnpressAllKeys ();
197 var
198 i: Integer;
199 begin
200 for i := 0 to High(KeyBuffer) do KeyBuffer[i] := False;
201 end;
204 procedure e_KeyUpDown (key: Word; down: Boolean);
205 begin
206 if (key > 0) and (key < Length(KeyBuffer)) then KeyBuffer[key] := down;
207 end;
210 function PollKeyboard(): Boolean;
212 var
213 Keys: PByte;
214 NKeys: Integer;
215 i: NativeUInt;
217 begin
218 Result := False;
220 Keys := SDL_GetKeyboardState(@NKeys);
221 if (Keys = nil) or (NKeys < 1) then Exit;
222 for i := 0 to NKeys do
223 begin
224 if ((PByte(NativeUInt(Keys) + i)^) <> 0) then KeyBuffer[i] := false;
225 end;
226 for i := NKeys to High(KeyBuffer) do KeyBuffer[i] := False;
228 end;
230 procedure e_PollJoysticks();
231 var
232 i, j: Word;
233 hat: Byte;
234 begin
235 //Result := False;
236 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
237 SDL_JoystickUpdate();
238 for j := Low(Joysticks) to High(Joysticks) do
239 begin
240 with Joysticks[j] do
241 begin
242 for i := 0 to Buttons do ButtBuf[i] := SDL_JoystickGetButton(Handle, i) <> 0;
243 for i := 0 to Axes do AxisBuf[i] := SDL_JoystickGetAxis(Handle, i);
244 for i := 0 to Hats do
245 begin
246 hat := SDL_JoystickGetHat(Handle, i);
247 HatBuf[i, HAT_UP] := LongBool(hat and SDL_HAT_UP);
248 HatBuf[i, HAT_DOWN] := LongBool(hat and SDL_HAT_DOWN);
249 HatBuf[i, HAT_LEFT] := LongBool(hat and SDL_HAT_LEFT);
250 HatBuf[i, HAT_RIGHT] := LongBool(hat and SDL_HAT_RIGHT);
251 end;
252 end;
253 end;
254 end;
256 procedure GenerateKeyNames();
257 var
258 i, j, k: LongWord;
259 begin
260 // keyboard key names
261 for i := 0 to IK_LASTKEY do
262 e_KeyNames[i] := SDL_GetScancodeName(i);
264 // joysticks
265 for j := 0 to e_MaxJoys-1 do
266 begin
267 k := JOYK_BEG + j * e_MaxJoyBtns;
268 // buttons
269 for i := 0 to e_MaxJoyBtns-1 do
270 e_KeyNames[k + i] := Format('JOY%d B%d', [j, i]);
271 k := JOYA_BEG + j * e_MaxJoyAxes * 2;
272 // axes
273 for i := 0 to e_MaxJoyAxes-1 do
274 begin
275 e_KeyNames[k + i*2 ] := Format('JOY%d A%d+', [j, i]);
276 e_KeyNames[k + i*2 + 1] := Format('JOY%d A%d-', [j, i]);
277 end;
278 k := JOYH_BEG + j * e_MaxJoyHats * 4;
279 // hats
280 for i := 0 to e_MaxJoyHats-1 do
281 begin
282 e_KeyNames[k + i*4 ] := Format('JOY%d D%dL', [j, i]);
283 e_KeyNames[k + i*4 + 1] := Format('JOY%d D%dU', [j, i]);
284 e_KeyNames[k + i*4 + 2] := Format('JOY%d D%dR', [j, i]);
285 e_KeyNames[k + i*4 + 3] := Format('JOY%d D%dD', [j, i]);
286 end;
287 end;
288 end;
290 function e_InitInput(): Boolean;
291 begin
292 Result := False;
294 e_JoysticksAvailable := OpenJoysticks();
295 e_EnableInput := True;
296 GenerateKeyNames();
298 Result := True;
299 end;
301 procedure e_ReleaseInput();
302 begin
303 ReleaseJoysticks();
304 e_JoysticksAvailable := 0;
305 end;
307 procedure e_ClearInputBuffer();
308 var
309 i, j, d: Integer;
310 begin
311 for i := Low(KeyBuffer) to High(KeyBuffer) do
312 KeyBuffer[i] := False;
313 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then
314 for i := Low(Joysticks) to High(Joysticks) do
315 begin
316 for j := Low(Joysticks[i].ButtBuf) to High(Joysticks[i].ButtBuf) do
317 Joysticks[i].ButtBuf[j] := False;
318 for j := Low(Joysticks[i].AxisBuf) to High(Joysticks[i].AxisBuf) do
319 Joysticks[i].AxisBuf[j] := 0;
320 for j := Low(Joysticks[i].HatBuf) to High(Joysticks[i].HatBuf) do
321 for d := Low(Joysticks[i].HatBuf[j]) to High(Joysticks[i].HatBuf[j]) do
322 Joysticks[i].HatBuf[j, d] := False;
323 end;
324 end;
327 function e_PollInput(): Boolean;
328 var
329 kb, js: Boolean;
330 begin
331 kb := PollKeyboard();
332 js := e_PollJoysticks();
334 Result := kb or js;
335 end;
338 function e_KeyPressed(Key: Word): Boolean;
339 var
340 joyi, dir: Integer;
341 begin
342 Result := False;
343 if (Key = IK_INVALID) or (Key = 0) then Exit;
345 if (Key < KBRD_END) then
346 begin // Keyboard buttons/keys
347 Result := KeyBuffer[Key];
348 end
350 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
351 begin // Joystick buttons
352 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
353 if JoyI >= e_JoysticksAvailable then
354 Result := False
355 else
356 begin
357 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
358 Result := Joysticks[JoyI].ButtBuf[Key];
359 end;
360 end
362 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
363 begin // Joystick axes
364 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
365 if JoyI >= e_JoysticksAvailable then
366 Result := False
367 else
368 begin
369 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
370 dir := Key mod 2;
371 if dir = AX_MINUS then
372 Result := Joysticks[JoyI].AxisBuf[Key div 2] <
373 Joysticks[JoyI].AxisZero[Key div 2] - e_JoystickDeadzones[JoyI]
374 else
375 Result := Joysticks[JoyI].AxisBuf[Key div 2] >
376 Joysticks[JoyI].AxisZero[Key div 2] + e_JoystickDeadzones[JoyI]
377 end;
378 end
380 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
381 begin // Joystick hats
382 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
383 if JoyI >= e_JoysticksAvailable then
384 Result := False
385 else
386 begin
387 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
388 dir := Key mod 4;
389 Result := Joysticks[JoyI].HatBuf[Key div 4, dir];
390 end;
391 end;
392 end;
394 procedure e_SetKeyState(key: Word; state: Integer);
395 var
396 JoyI, dir: Integer;
397 begin
398 if (Key = IK_INVALID) or (Key = 0) then Exit;
400 if (Key < KBRD_END) then
401 begin // Keyboard buttons/keys
402 keyBuffer[key] := (state <> 0);
403 end
405 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
406 begin // Joystick buttons
407 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
408 if JoyI >= e_JoysticksAvailable then
409 Exit
410 else
411 begin
412 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
413 Joysticks[JoyI].ButtBuf[Key] := (state <> 0);
414 end;
415 end
417 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
418 begin // Joystick axes
419 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
420 if JoyI >= e_JoysticksAvailable then
421 Exit
422 else
423 begin
424 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
425 Joysticks[JoyI].AxisBuf[Key div 2] := state;
426 end;
427 end
429 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
430 begin // Joystick hats
431 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
432 if JoyI >= e_JoysticksAvailable then
433 Exit
434 else
435 begin
436 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
437 dir := Key mod 4;
438 Joysticks[JoyI].HatBuf[Key div 4, dir] := (state <> 0);
439 end;
440 end;
441 end;
443 function e_AnyKeyPressed(): Boolean;
444 var
445 k: Word;
446 begin
447 Result := False;
449 for k := 1 to e_MaxInputKeys do
450 if e_KeyPressed(k) then
451 begin
452 Result := True;
453 Break;
454 end;
455 end;
457 function e_GetFirstKeyPressed(): Word;
458 var
459 k: Word;
460 begin
461 Result := IK_INVALID;
463 for k := 1 to e_MaxInputKeys do
464 if e_KeyPressed(k) then
465 begin
466 Result := k;
467 Break;
468 end;
469 end;
471 ////////////////////////////////////////////////////////////////////////////////
473 function e_JoystickStateToString(mode: Integer): String;
474 begin
475 Result := '';
476 end;
478 function e_JoyByHandle(handle: Word): Integer;
479 var
480 i: Integer;
481 begin
482 Result := -1;
483 if Joysticks = nil then Exit;
484 for i := Low(Joysticks) to High(Joysticks) do
485 if Joysticks[i].ID = handle then
486 begin
487 Result := i;
488 Exit;
489 end;
490 end;
492 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
493 begin
494 Result := 0;
495 if id >= Length(Joysticks) then Exit;
496 Result := JOYK_BEG + id*e_MaxJoyBtns + btn;
497 end;
499 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
500 begin
501 Result := 0;
502 if id >= Length(Joysticks) then Exit;
503 Result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir;
504 end;
506 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
507 begin
508 Result := 0;
509 if id >= Length(Joysticks) then Exit;
510 Result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir;
511 end;
513 end.