DEADSOFTWARE

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