DEADSOFTWARE

15cc2aa6ff3a348cf6271fb7b9d1023a668d53a6
[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 {$MODE DELPHI}
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 = 4;
31 e_MaxJoyHats = 4;
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 // $$$..$$$ - 4*4 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 function e_KeyPressed(Key: Word): Boolean;
99 function e_AnyKeyPressed(): Boolean;
100 function e_GetFirstKeyPressed(): Word;
101 function e_JoystickStateToString(mode: Integer): String;
102 function e_JoyByHandle(handle: Word): Integer;
103 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
104 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
105 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
106 procedure e_SetKeyState(key: Word; state: Integer);
108 var
109 {e_MouseInfo: TMouseInfo;}
110 e_EnableInput: Boolean = False;
111 e_JoysticksAvailable: Byte = 0;
112 e_JoystickDeadzones: array [0..e_MaxJoys-1] of Integer = (8192, 8192, 8192, 8192);
113 e_KeyNames: array [0..e_MaxInputKeys] of String;
115 implementation
117 uses Math;
119 const
120 KBRD_END = e_MaxKbdKeys;
121 JOYK_BEG = KBRD_END;
122 JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
123 JOYA_BEG = JOYK_END;
124 JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
125 JOYH_BEG = JOYA_END;
126 JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
128 type
129 TJoystick = record
130 ID: Byte;
131 Handle: PSDL_Joystick;
132 Axes: Byte;
133 Buttons: Byte;
134 Hats: Byte;
135 ButtBuf: array [0..e_MaxJoyBtns] of Boolean;
136 AxisBuf: array [0..e_MaxJoyAxes] of Integer;
137 HatBuf: array [0..e_MaxJoyHats] of array [HAT_LEFT..HAT_DOWN] of Boolean;
138 end;
140 var
141 KeyBuffer: array [0..e_MaxKbdKeys] of Boolean;
142 Joysticks: array of TJoystick = nil;
144 function OpenJoysticks(): Byte;
145 var
146 i, k, c: Integer;
147 joy: PSDL_Joystick;
148 begin
149 Result := 0;
150 k := Min(e_MaxJoys, SDL_NumJoysticks());
151 if k = 0 then Exit;
152 c := 0;
153 for i := 0 to k do
154 begin
155 joy := SDL_JoystickOpen(i);
156 if joy <> nil then
157 begin
158 Inc(c);
159 e_WriteLog('Input: Opened SDL joystick ' + IntToStr(i) + ' as joystick ' + IntToStr(c) + ':', MSG_NOTIFY);
160 SetLength(Joysticks, c);
161 with Joysticks[c-1] do
162 begin
163 ID := i;
164 Handle := joy;
165 Axes := Min(e_MaxJoyAxes, SDL_JoystickNumAxes(joy));
166 Buttons := Min(e_MaxJoyBtns, SDL_JoystickNumButtons(joy));
167 Hats := Min(e_MaxJoyHats, SDL_JoystickNumHats(joy));
168 e_WriteLog(' ' + IntToStr(Axes) + ' axes, ' + IntToStr(Buttons) + ' buttons, ' +
169 IntToStr(Hats) + ' hats.', MSG_NOTIFY);
170 end;
171 end;
172 end;
173 Result := c;
174 end;
176 procedure ReleaseJoysticks();
177 var
178 i: Integer;
179 begin
180 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
181 for i := Low(Joysticks) to High(Joysticks) do
182 with Joysticks[i] do
183 SDL_JoystickClose(Handle);
184 SetLength(Joysticks, 0);
185 end;
187 function PollKeyboard(): Boolean;
188 var
189 Keys: PByte;
190 NKeys: Integer;
191 i: Cardinal;
192 begin
193 Result := False;
194 Keys := SDL_GetKeyboardState(@NKeys);
195 if (Keys = nil) or (NKeys < 1) then
196 Exit;
197 for i := 0 to NKeys do
198 KeyBuffer[i] := ((PByte(Cardinal(Keys) + i)^) <> 0);
199 for i := NKeys to High(KeyBuffer) do
200 KeyBuffer[i] := False;
201 end;
203 function PollJoysticks(): Boolean;
204 var
205 i, j: Word;
206 hat: Byte;
207 begin
208 Result := False;
209 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
210 SDL_JoystickUpdate();
211 for j := Low(Joysticks) to High(Joysticks) do
212 with Joysticks[j] do
213 begin
214 for i := 0 to Buttons do
215 ButtBuf[i] := SDL_JoystickGetButton(Handle, i) <> 0;
216 for i := 0 to Axes do
217 AxisBuf[i] := SDL_JoystickGetAxis(Handle, i);
218 for i := 0 to Hats do
219 begin
220 hat := SDL_JoystickGetHat(Handle, i);
221 HatBuf[i, HAT_UP] := LongBool(hat and SDL_HAT_UP);
222 HatBuf[i, HAT_DOWN] := LongBool(hat and SDL_HAT_DOWN);
223 HatBuf[i, HAT_LEFT] := LongBool(hat and SDL_HAT_LEFT);
224 HatBuf[i, HAT_RIGHT] := LongBool(hat and SDL_HAT_RIGHT);
225 end;
226 end;
227 end;
229 procedure GenerateKeyNames();
230 var
231 i, j, k: LongWord;
232 begin
233 // keyboard key names
234 for i := 0 to IK_LASTKEY do
235 e_KeyNames[i] := SDL_GetScancodeName(i);
237 // joysticks
238 for j := 0 to e_MaxJoys-1 do
239 begin
240 k := JOYK_BEG + j * e_MaxJoyBtns;
241 // buttons
242 for i := 0 to e_MaxJoyBtns-1 do
243 e_KeyNames[k + i] := Format('JOY%d B%d', [j, i]);
244 k := JOYA_BEG + j * e_MaxJoyAxes * 2;
245 // axes
246 for i := 0 to e_MaxJoyAxes-1 do
247 begin
248 e_KeyNames[k + i*2 ] := Format('JOY%d A%d+', [j, i]);
249 e_KeyNames[k + i*2 + 1] := Format('JOY%d A%d-', [j, i]);
250 end;
251 k := JOYH_BEG + j * e_MaxJoyHats * 4;
252 // hats
253 for i := 0 to e_MaxJoyHats-1 do
254 begin
255 e_KeyNames[k + i*4 ] := Format('JOY%d D%dL', [j, i]);
256 e_KeyNames[k + i*4 + 1] := Format('JOY%d D%dU', [j, i]);
257 e_KeyNames[k + i*4 + 2] := Format('JOY%d D%dR', [j, i]);
258 e_KeyNames[k + i*4 + 3] := Format('JOY%d D%dD', [j, i]);
259 end;
260 end;
261 end;
263 function e_InitInput(): Boolean;
264 begin
265 Result := False;
267 e_JoysticksAvailable := OpenJoysticks();
268 e_EnableInput := True;
269 GenerateKeyNames();
271 Result := True;
272 end;
274 procedure e_ReleaseInput();
275 begin
276 ReleaseJoysticks();
277 e_JoysticksAvailable := 0;
278 end;
280 procedure e_ClearInputBuffer();
281 var
282 i, j, d: Integer;
283 begin
284 for i := Low(KeyBuffer) to High(KeyBuffer) do
285 KeyBuffer[i] := False;
286 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then
287 for i := Low(Joysticks) to High(Joysticks) do
288 begin
289 for j := Low(Joysticks[i].ButtBuf) to High(Joysticks[i].ButtBuf) do
290 Joysticks[i].ButtBuf[j] := False;
291 for j := Low(Joysticks[i].AxisBuf) to High(Joysticks[i].AxisBuf) do
292 Joysticks[i].AxisBuf[j] := 0;
293 for j := Low(Joysticks[i].HatBuf) to High(Joysticks[i].HatBuf) do
294 for d := Low(Joysticks[i].HatBuf[j]) to High(Joysticks[i].HatBuf[j]) do
295 Joysticks[i].HatBuf[j, d] := False;
296 end;
297 end;
299 function e_PollInput(): Boolean;
300 var
301 kb, js: Boolean;
302 begin
303 kb := PollKeyboard();
304 js := PollJoysticks();
306 Result := kb or js;
307 end;
309 function e_KeyPressed(Key: Word): Boolean;
310 var
311 joyi, dir: Integer;
312 begin
313 Result := False;
314 if (Key = IK_INVALID) or (Key = 0) then Exit;
316 if (Key < KBRD_END) then
317 begin // Keyboard buttons/keys
318 Result := KeyBuffer[Key];
319 end
321 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
322 begin // Joystick buttons
323 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
324 if JoyI >= e_JoysticksAvailable then
325 Result := False
326 else
327 begin
328 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
329 Result := Joysticks[JoyI].ButtBuf[Key];
330 end;
331 end
333 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
334 begin // Joystick axes
335 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
336 if JoyI >= e_JoysticksAvailable then
337 Result := False
338 else
339 begin
340 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
341 dir := Key mod 2;
342 if dir = AX_MINUS then
343 Result := Joysticks[JoyI].AxisBuf[Key div 2] < -e_JoystickDeadzones[JoyI]
344 else
345 Result := Joysticks[JoyI].AxisBuf[Key div 2] > e_JoystickDeadzones[JoyI]
346 end;
347 end
349 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
350 begin // Joystick hats
351 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
352 if JoyI >= e_JoysticksAvailable then
353 Result := False
354 else
355 begin
356 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
357 dir := Key mod 4;
358 Result := Joysticks[JoyI].HatBuf[Key div 4, dir];
359 end;
360 end;
361 end;
363 procedure e_SetKeyState(key: Word; state: Integer);
364 var
365 JoyI, dir: Integer;
366 begin
367 if (Key = IK_INVALID) or (Key = 0) then Exit;
369 if (Key < KBRD_END) then
370 begin // Keyboard buttons/keys
371 keyBuffer[key] := (state <> 0);
372 end
374 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
375 begin // Joystick buttons
376 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
377 if JoyI >= e_JoysticksAvailable then
378 Exit
379 else
380 begin
381 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
382 Joysticks[JoyI].ButtBuf[Key] := (state <> 0);
383 end;
384 end
386 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
387 begin // Joystick axes
388 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
389 if JoyI >= e_JoysticksAvailable then
390 Exit
391 else
392 begin
393 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
394 Joysticks[JoyI].AxisBuf[Key div 2] := state;
395 end;
396 end
398 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
399 begin // Joystick hats
400 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
401 if JoyI >= e_JoysticksAvailable then
402 Exit
403 else
404 begin
405 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
406 dir := Key mod 4;
407 Joysticks[JoyI].HatBuf[Key div 4, dir] := (state <> 0);
408 end;
409 end;
410 end;
412 function e_AnyKeyPressed(): Boolean;
413 var
414 k: Word;
415 begin
416 Result := False;
418 for k := 1 to e_MaxInputKeys do
419 if e_KeyPressed(k) then
420 begin
421 Result := True;
422 Break;
423 end;
424 end;
426 function e_GetFirstKeyPressed(): Word;
427 var
428 k: Word;
429 begin
430 Result := IK_INVALID;
432 for k := 1 to e_MaxInputKeys do
433 if e_KeyPressed(k) then
434 begin
435 Result := k;
436 Break;
437 end;
438 end;
440 ////////////////////////////////////////////////////////////////////////////////
442 function e_JoystickStateToString(mode: Integer): String;
443 begin
444 Result := '';
445 end;
447 function e_JoyByHandle(handle: Word): Integer;
448 var
449 i: Integer;
450 begin
451 Result := -1;
452 if Joysticks = nil then Exit;
453 for i := Low(Joysticks) to High(Joysticks) do
454 if Joysticks[i].ID = handle then
455 begin
456 Result := i;
457 Exit;
458 end;
459 end;
461 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
462 begin
463 Result := 0;
464 if id >= Length(Joysticks) then Exit;
465 Result := JOYK_BEG + id*e_MaxJoyBtns + btn;
466 end;
468 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
469 begin
470 Result := 0;
471 if id >= Length(Joysticks) then Exit;
472 Result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir;
473 end;
475 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
476 begin
477 Result := 0;
478 if id >= Length(Joysticks) then Exit;
479 Result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir;
480 end;
482 end.