DEADSOFTWARE

095a76eed045a32d91d6c743c7a5e51fabbb989a
[d2df-sdl.git] / src / engine / e_input.pas
1 {$MODE DELPHI}
2 unit e_input;
4 interface
6 uses
7 SysUtils,
8 e_log,
9 SDL2;
11 const
12 e_MaxKbdKeys = SDL_NUM_SCANCODES;
13 e_MaxJoys = 4;
14 e_MaxJoyBtns = 32;
15 e_MaxJoyAxes = 4;
16 e_MaxJoyHats = 4;
18 e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
20 e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys - 1;
21 // $$$..$$$ - 321 Keyboard buttons/keys
22 // $$$..$$$ - 4*32 Joystick buttons
23 // $$$..$$$ - 4*4 Joystick axes (- and +)
24 // $$$..$$$ - 4*4 Joystick hats (L U R D)
26 // these are apparently used in g_gui and g_game and elsewhere
27 IK_INVALID = 65535;
28 IK_ESCAPE = SDL_SCANCODE_ESCAPE;
29 IK_RETURN = SDL_SCANCODE_RETURN;
30 IK_KPRETURN= SDL_SCANCODE_KP_ENTER;
31 IK_ENTER = SDL_SCANCODE_RETURN;
32 IK_UP = SDL_SCANCODE_UP;
33 IK_KPUP = SDL_SCANCODE_KP_8;
34 IK_DOWN = SDL_SCANCODE_DOWN;
35 IK_KPDOWN = SDL_SCANCODE_KP_2;
36 IK_LEFT = SDL_SCANCODE_LEFT;
37 IK_KPLEFT = SDL_SCANCODE_KP_4;
38 IK_RIGHT = SDL_SCANCODE_RIGHT;
39 IK_KPRIGHT = SDL_SCANCODE_KP_6;
40 IK_DELETE = SDL_SCANCODE_DELETE;
41 IK_HOME = SDL_SCANCODE_HOME;
42 IK_KPHOME = SDL_SCANCODE_KP_7;
43 IK_INSERT = SDL_SCANCODE_INSERT;
44 IK_SPACE = SDL_SCANCODE_SPACE;
45 IK_CONTROL = SDL_SCANCODE_LCTRL;
46 IK_SHIFT = SDL_SCANCODE_LSHIFT;
47 IK_TAB = SDL_SCANCODE_TAB;
48 IK_PAGEUP = SDL_SCANCODE_PAGEUP;
49 IK_KPPAGEUP= SDL_SCANCODE_KP_9;
50 IK_PAGEDN = SDL_SCANCODE_PAGEDOWN;
51 IK_KPPAGEDN= SDL_SCANCODE_KP_3;
52 IK_F2 = SDL_SCANCODE_F2;
53 IK_F3 = SDL_SCANCODE_F3;
54 IK_F4 = SDL_SCANCODE_F4;
55 IK_F5 = SDL_SCANCODE_F5;
56 IK_F6 = SDL_SCANCODE_F6;
57 IK_F7 = SDL_SCANCODE_F7;
58 IK_F8 = SDL_SCANCODE_F8;
59 IK_F9 = SDL_SCANCODE_F9;
60 IK_F10 = SDL_SCANCODE_F10;
61 IK_END = SDL_SCANCODE_END;
62 IK_KPEND = SDL_SCANCODE_KP_1;
63 IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
64 IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
65 IK_GRAVE = SDL_SCANCODE_GRAVE;
66 IK_PAUSE = SDL_SCANCODE_PAUSE;
67 IK_Y = SDL_SCANCODE_Y;
68 IK_N = SDL_SCANCODE_N;
69 // TODO: think of something better than this shit
70 IK_LASTKEY = SDL_NUM_SCANCODES-1;
72 AX_MINUS = 0;
73 AX_PLUS = 1;
74 HAT_LEFT = 0;
75 HAT_UP = 1;
76 HAT_RIGHT = 2;
77 HAT_DOWN = 3;
79 function e_InitInput(): Boolean;
80 procedure e_ReleaseInput();
81 procedure e_ClearInputBuffer();
82 function e_PollInput(): Boolean;
83 function e_KeyPressed(Key: Word): Boolean;
84 function e_AnyKeyPressed(): Boolean;
85 function e_GetFirstKeyPressed(): Word;
86 function e_JoystickStateToString(mode: Integer): String;
87 function e_JoyByHandle(handle: Word): Integer;
88 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
89 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
90 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
91 procedure e_SetKeyState(key: Word; state: Integer);
93 var
94 {e_MouseInfo: TMouseInfo;}
95 e_EnableInput: Boolean = False;
96 e_JoysticksAvailable: Byte = 0;
97 e_JoystickDeadzones: array [0..e_MaxJoys-1] of Integer = (8192, 8192, 8192, 8192);
98 e_KeyNames: array [0..e_MaxInputKeys] of String;
100 implementation
102 uses Math;
104 const
105 KBRD_END = e_MaxKbdKeys;
106 JOYK_BEG = KBRD_END;
107 JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
108 JOYA_BEG = JOYK_END;
109 JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
110 JOYH_BEG = JOYA_END;
111 JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
113 type
114 TJoystick = record
115 ID: Byte;
116 Handle: PSDL_Joystick;
117 Axes: Byte;
118 Buttons: Byte;
119 Hats: Byte;
120 ButtBuf: array [0..e_MaxJoyBtns] of Boolean;
121 AxisBuf: array [0..e_MaxJoyAxes] of Integer;
122 HatBuf: array [0..e_MaxJoyHats] of array [HAT_LEFT..HAT_DOWN] of Boolean;
123 end;
125 var
126 KeyBuffer: array [0..e_MaxKbdKeys] of Boolean;
127 Joysticks: array of TJoystick = nil;
129 function OpenJoysticks(): Byte;
130 var
131 i, k, c: Integer;
132 joy: PSDL_Joystick;
133 begin
134 Result := 0;
135 k := Min(e_MaxJoys, SDL_NumJoysticks());
136 if k = 0 then Exit;
137 c := 0;
138 for i := 0 to k do
139 begin
140 joy := SDL_JoystickOpen(i);
141 if joy <> nil then
142 begin
143 Inc(c);
144 e_WriteLog('Input: Opened SDL joystick ' + IntToStr(i) + ' as joystick ' + IntToStr(c) + ':', MSG_NOTIFY);
145 SetLength(Joysticks, c);
146 with Joysticks[c-1] do
147 begin
148 ID := i;
149 Handle := joy;
150 Axes := Min(e_MaxJoyAxes, SDL_JoystickNumAxes(joy));
151 Buttons := Min(e_MaxJoyBtns, SDL_JoystickNumButtons(joy));
152 Hats := Min(e_MaxJoyHats, SDL_JoystickNumHats(joy));
153 e_WriteLog(' ' + IntToStr(Axes) + ' axes, ' + IntToStr(Buttons) + ' buttons, ' +
154 IntToStr(Hats) + ' hats.', MSG_NOTIFY);
155 end;
156 end;
157 end;
158 Result := c;
159 end;
161 procedure ReleaseJoysticks();
162 var
163 i: Integer;
164 begin
165 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
166 for i := Low(Joysticks) to High(Joysticks) do
167 with Joysticks[i] do
168 SDL_JoystickClose(Handle);
169 SetLength(Joysticks, 0);
170 end;
172 function PollKeyboard(): Boolean;
173 var
174 Keys: PByte;
175 NKeys: Integer;
176 i: Cardinal;
177 begin
178 Result := False;
179 Keys := SDL_GetKeyboardState(@NKeys);
180 if (Keys = nil) or (NKeys < 1) then
181 Exit;
182 for i := 0 to NKeys do
183 KeyBuffer[i] := ((PByte(Cardinal(Keys) + i)^) <> 0);
184 for i := NKeys to High(KeyBuffer) do
185 KeyBuffer[i] := False;
186 end;
188 function PollJoysticks(): Boolean;
189 var
190 i, j: Word;
191 hat: Byte;
192 begin
193 Result := False;
194 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
195 SDL_JoystickUpdate();
196 for j := Low(Joysticks) to High(Joysticks) do
197 with Joysticks[j] do
198 begin
199 for i := 0 to Buttons do
200 ButtBuf[i] := SDL_JoystickGetButton(Handle, i) <> 0;
201 for i := 0 to Axes do
202 AxisBuf[i] := SDL_JoystickGetAxis(Handle, i);
203 for i := 0 to Hats do
204 begin
205 hat := SDL_JoystickGetHat(Handle, i);
206 HatBuf[i, HAT_UP] := LongBool(hat and SDL_HAT_UP);
207 HatBuf[i, HAT_DOWN] := LongBool(hat and SDL_HAT_DOWN);
208 HatBuf[i, HAT_LEFT] := LongBool(hat and SDL_HAT_LEFT);
209 HatBuf[i, HAT_RIGHT] := LongBool(hat and SDL_HAT_RIGHT);
210 end;
211 end;
212 end;
214 procedure GenerateKeyNames();
215 var
216 i, j, k: LongWord;
217 begin
218 // keyboard key names
219 for i := 0 to IK_LASTKEY do
220 e_KeyNames[i] := SDL_GetScancodeName(i);
222 // joysticks
223 for j := 0 to e_MaxJoys-1 do
224 begin
225 k := JOYK_BEG + j * e_MaxJoyBtns;
226 // buttons
227 for i := 0 to e_MaxJoyBtns-1 do
228 e_KeyNames[k + i] := Format('JOY%d B%d', [j, i]);
229 k := JOYA_BEG + j * e_MaxJoyAxes * 2;
230 // axes
231 for i := 0 to e_MaxJoyAxes-1 do
232 begin
233 e_KeyNames[k + i*2 ] := Format('JOY%d A%d+', [j, i]);
234 e_KeyNames[k + i*2 + 1] := Format('JOY%d A%d-', [j, i]);
235 end;
236 k := JOYH_BEG + j * e_MaxJoyHats * 4;
237 // hats
238 for i := 0 to e_MaxJoyHats-1 do
239 begin
240 e_KeyNames[k + i*4 ] := Format('JOY%d D%dL', [j, i]);
241 e_KeyNames[k + i*4 + 1] := Format('JOY%d D%dU', [j, i]);
242 e_KeyNames[k + i*4 + 2] := Format('JOY%d D%dR', [j, i]);
243 e_KeyNames[k + i*4 + 3] := Format('JOY%d D%dD', [j, i]);
244 end;
245 end;
246 end;
248 function e_InitInput(): Boolean;
249 begin
250 Result := False;
252 e_JoysticksAvailable := OpenJoysticks();
253 e_EnableInput := True;
254 GenerateKeyNames();
256 Result := True;
257 end;
259 procedure e_ReleaseInput();
260 begin
261 ReleaseJoysticks();
262 e_JoysticksAvailable := 0;
263 end;
265 procedure e_ClearInputBuffer();
266 var
267 i, j, d: Integer;
268 begin
269 for i := Low(KeyBuffer) to High(KeyBuffer) do
270 KeyBuffer[i] := False;
271 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then
272 for i := Low(Joysticks) to High(Joysticks) do
273 begin
274 for j := Low(Joysticks[i].ButtBuf) to High(Joysticks[i].ButtBuf) do
275 Joysticks[i].ButtBuf[j] := False;
276 for j := Low(Joysticks[i].AxisBuf) to High(Joysticks[i].AxisBuf) do
277 Joysticks[i].AxisBuf[j] := 0;
278 for j := Low(Joysticks[i].HatBuf) to High(Joysticks[i].HatBuf) do
279 for d := Low(Joysticks[i].HatBuf[j]) to High(Joysticks[i].HatBuf[j]) do
280 Joysticks[i].HatBuf[j, d] := False;
281 end;
282 end;
284 function e_PollInput(): Boolean;
285 var
286 kb, js: Boolean;
287 begin
288 kb := PollKeyboard();
289 js := PollJoysticks();
291 Result := kb or js;
292 end;
294 function e_KeyPressed(Key: Word): Boolean;
295 var
296 joyi, dir: Integer;
297 begin
298 Result := False;
299 if (Key = IK_INVALID) or (Key = 0) then Exit;
301 if (Key < KBRD_END) then
302 begin // Keyboard buttons/keys
303 Result := KeyBuffer[Key];
304 end
306 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
307 begin // Joystick buttons
308 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
309 if JoyI >= e_JoysticksAvailable then
310 Result := False
311 else
312 begin
313 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
314 Result := Joysticks[JoyI].ButtBuf[Key];
315 end;
316 end
318 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
319 begin // Joystick axes
320 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
321 if JoyI >= e_JoysticksAvailable then
322 Result := False
323 else
324 begin
325 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
326 dir := Key mod 2;
327 if dir = AX_MINUS then
328 Result := Joysticks[JoyI].AxisBuf[Key div 2] < -e_JoystickDeadzones[JoyI]
329 else
330 Result := Joysticks[JoyI].AxisBuf[Key div 2] > e_JoystickDeadzones[JoyI]
331 end;
332 end
334 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
335 begin // Joystick hats
336 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
337 if JoyI >= e_JoysticksAvailable then
338 Result := False
339 else
340 begin
341 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
342 dir := Key mod 4;
343 Result := Joysticks[JoyI].HatBuf[Key div 4, dir];
344 end;
345 end;
346 end;
348 procedure e_SetKeyState(key: Word; state: Integer);
349 var
350 JoyI, dir: Integer;
351 begin
352 if (Key = IK_INVALID) or (Key = 0) then Exit;
354 if (Key < KBRD_END) then
355 begin // Keyboard buttons/keys
356 keyBuffer[key] := (state <> 0);
357 end
359 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
360 begin // Joystick buttons
361 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
362 if JoyI >= e_JoysticksAvailable then
363 Exit
364 else
365 begin
366 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
367 Joysticks[JoyI].ButtBuf[Key] := (state <> 0);
368 end;
369 end
371 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
372 begin // Joystick axes
373 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
374 if JoyI >= e_JoysticksAvailable then
375 Exit
376 else
377 begin
378 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
379 Joysticks[JoyI].AxisBuf[Key div 2] := state;
380 end;
381 end
383 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
384 begin // Joystick hats
385 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
386 if JoyI >= e_JoysticksAvailable then
387 Exit
388 else
389 begin
390 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
391 dir := Key mod 4;
392 Joysticks[JoyI].HatBuf[Key div 4, dir] := (state <> 0);
393 end;
394 end;
395 end;
397 function e_AnyKeyPressed(): Boolean;
398 var
399 k: Word;
400 begin
401 Result := False;
403 for k := 1 to e_MaxInputKeys do
404 if e_KeyPressed(k) then
405 begin
406 Result := True;
407 Break;
408 end;
409 end;
411 function e_GetFirstKeyPressed(): Word;
412 var
413 k: Word;
414 begin
415 Result := IK_INVALID;
417 for k := 1 to e_MaxInputKeys do
418 if e_KeyPressed(k) then
419 begin
420 Result := k;
421 Break;
422 end;
423 end;
425 ////////////////////////////////////////////////////////////////////////////////
427 function e_JoystickStateToString(mode: Integer): String;
428 begin
429 Result := '';
430 end;
432 function e_JoyByHandle(handle: Word): Integer;
433 var
434 i: Integer;
435 begin
436 Result := -1;
437 if Joysticks = nil then Exit;
438 for i := Low(Joysticks) to High(Joysticks) do
439 if Joysticks[i].ID = handle then
440 begin
441 Result := i;
442 Exit;
443 end;
444 end;
446 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
447 begin
448 Result := 0;
449 if id >= Length(Joysticks) then Exit;
450 Result := JOYK_BEG + id*e_MaxJoyBtns + btn;
451 end;
453 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
454 begin
455 Result := 0;
456 if id >= Length(Joysticks) then Exit;
457 Result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir;
458 end;
460 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
461 begin
462 Result := 0;
463 if id >= Length(Joysticks) then Exit;
464 Result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir;
465 end;
467 end.