DEADSOFTWARE

fixed cheats and YN prompts
[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_ENTER = SDL_SCANCODE_RETURN;
30 IK_UP = SDL_SCANCODE_UP;
31 IK_DOWN = SDL_SCANCODE_DOWN;
32 IK_LEFT = SDL_SCANCODE_LEFT;
33 IK_RIGHT = SDL_SCANCODE_RIGHT;
34 IK_DELETE = SDL_SCANCODE_DELETE;
35 IK_HOME = SDL_SCANCODE_HOME;
36 IK_INSERT = SDL_SCANCODE_INSERT;
37 IK_SPACE = SDL_SCANCODE_SPACE;
38 IK_CONTROL = SDL_SCANCODE_LCTRL;
39 IK_SHIFT = SDL_SCANCODE_LSHIFT;
40 IK_TAB = SDL_SCANCODE_TAB;
41 IK_PAGEUP = SDL_SCANCODE_PAGEUP;
42 IK_PAGEDN = SDL_SCANCODE_PAGEDOWN;
43 IK_F2 = SDL_SCANCODE_F2;
44 IK_F3 = SDL_SCANCODE_F3;
45 IK_F4 = SDL_SCANCODE_F4;
46 IK_F5 = SDL_SCANCODE_F5;
47 IK_F6 = SDL_SCANCODE_F6;
48 IK_F7 = SDL_SCANCODE_F7;
49 IK_F8 = SDL_SCANCODE_F8;
50 IK_F9 = SDL_SCANCODE_F9;
51 IK_F10 = SDL_SCANCODE_F10;
52 IK_END = SDL_SCANCODE_END;
53 IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
54 IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
55 IK_GRAVE = SDL_SCANCODE_GRAVE;
56 IK_PAUSE = SDL_SCANCODE_PAUSE;
57 IK_Y = SDL_SCANCODE_Y;
58 IK_N = SDL_SCANCODE_N;
59 // TODO: think of something better than this shit
60 IK_LASTKEY = SDL_NUM_SCANCODES-1;
62 AX_MINUS = 0;
63 AX_PLUS = 1;
64 HAT_LEFT = 0;
65 HAT_UP = 1;
66 HAT_RIGHT = 2;
67 HAT_DOWN = 3;
69 function e_InitInput(): Boolean;
70 procedure e_ReleaseInput();
71 procedure e_ClearInputBuffer();
72 function e_PollInput(): Boolean;
73 function e_KeyPressed(Key: Word): Boolean;
74 function e_AnyKeyPressed(): Boolean;
75 function e_GetFirstKeyPressed(): Word;
76 function e_JoystickStateToString(mode: Integer): String;
77 function e_JoyByHandle(handle: Word): Integer;
78 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
79 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
80 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
81 procedure e_SetKeyState(key: Word; state: Integer);
83 var
84 {e_MouseInfo: TMouseInfo;}
85 e_EnableInput: Boolean = False;
86 e_JoysticksAvailable: Byte = 0;
87 e_JoystickDeadzones: array [0..e_MaxJoys-1] of Integer = (8192, 8192, 8192, 8192);
88 e_KeyNames: array [0..e_MaxInputKeys] of String;
90 implementation
92 uses Math;
94 const
95 KBRD_END = e_MaxKbdKeys;
96 JOYK_BEG = KBRD_END;
97 JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
98 JOYA_BEG = JOYK_END;
99 JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
100 JOYH_BEG = JOYA_END;
101 JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
103 type
104 TJoystick = record
105 ID: Byte;
106 Handle: PSDL_Joystick;
107 Axes: Byte;
108 Buttons: Byte;
109 Hats: Byte;
110 ButtBuf: array [0..e_MaxJoyBtns] of Boolean;
111 AxisBuf: array [0..e_MaxJoyAxes] of Integer;
112 HatBuf: array [0..e_MaxJoyHats] of array [HAT_LEFT..HAT_DOWN] of Boolean;
113 end;
115 var
116 KeyBuffer: array [0..e_MaxKbdKeys] of Boolean;
117 Joysticks: array of TJoystick = nil;
119 function OpenJoysticks(): Byte;
120 var
121 i, k, c: Integer;
122 joy: PSDL_Joystick;
123 begin
124 Result := 0;
125 k := Min(e_MaxJoys, SDL_NumJoysticks());
126 if k = 0 then Exit;
127 c := 0;
128 for i := 0 to k do
129 begin
130 joy := SDL_JoystickOpen(i);
131 if joy <> nil then
132 begin
133 Inc(c);
134 e_WriteLog('Input: Opened SDL joystick ' + IntToStr(i) + ' as joystick ' + IntToStr(c) + ':', MSG_NOTIFY);
135 SetLength(Joysticks, c);
136 with Joysticks[c-1] do
137 begin
138 ID := i;
139 Handle := joy;
140 Axes := Min(e_MaxJoyAxes, SDL_JoystickNumAxes(joy));
141 Buttons := Min(e_MaxJoyBtns, SDL_JoystickNumButtons(joy));
142 Hats := Min(e_MaxJoyHats, SDL_JoystickNumHats(joy));
143 e_WriteLog(' ' + IntToStr(Axes) + ' axes, ' + IntToStr(Buttons) + ' buttons, ' +
144 IntToStr(Hats) + ' hats.', MSG_NOTIFY);
145 end;
146 end;
147 end;
148 Result := c;
149 end;
151 procedure ReleaseJoysticks();
152 var
153 i: Integer;
154 begin
155 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
156 for i := Low(Joysticks) to High(Joysticks) do
157 with Joysticks[i] do
158 SDL_JoystickClose(Handle);
159 SetLength(Joysticks, 0);
160 end;
162 function PollKeyboard(): Boolean;
163 var
164 Keys: PByte;
165 NKeys: Integer;
166 i: Cardinal;
167 begin
168 Result := False;
169 Keys := SDL_GetKeyboardState(@NKeys);
170 if (Keys = nil) or (NKeys < 1) then
171 Exit;
172 for i := 0 to NKeys do
173 KeyBuffer[i] := ((PByte(Cardinal(Keys) + i)^) <> 0);
174 for i := NKeys to High(KeyBuffer) do
175 KeyBuffer[i] := False;
176 end;
178 function PollJoysticks(): Boolean;
179 var
180 i, j: Word;
181 hat: Byte;
182 begin
183 Result := False;
184 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then Exit;
185 SDL_JoystickUpdate();
186 for j := Low(Joysticks) to High(Joysticks) do
187 with Joysticks[j] do
188 begin
189 for i := 0 to Buttons do
190 ButtBuf[i] := SDL_JoystickGetButton(Handle, i) <> 0;
191 for i := 0 to Axes do
192 AxisBuf[i] := SDL_JoystickGetAxis(Handle, i);
193 for i := 0 to Hats do
194 begin
195 hat := SDL_JoystickGetHat(Handle, i);
196 HatBuf[i, HAT_UP] := LongBool(hat and SDL_HAT_UP);
197 HatBuf[i, HAT_DOWN] := LongBool(hat and SDL_HAT_DOWN);
198 HatBuf[i, HAT_LEFT] := LongBool(hat and SDL_HAT_LEFT);
199 HatBuf[i, HAT_RIGHT] := LongBool(hat and SDL_HAT_RIGHT);
200 end;
201 end;
202 end;
204 procedure GenerateKeyNames();
205 var
206 i, j, k: LongWord;
207 begin
208 // keyboard key names
209 for i := 0 to IK_LASTKEY do
210 e_KeyNames[i] := SDL_GetScancodeName(i);
212 // joysticks
213 for j := 0 to e_MaxJoys-1 do
214 begin
215 k := JOYK_BEG + j * e_MaxJoyBtns;
216 // buttons
217 for i := 0 to e_MaxJoyBtns-1 do
218 e_KeyNames[k + i] := Format('JOY%d B%d', [j, i]);
219 k := JOYA_BEG + j * e_MaxJoyAxes * 2;
220 // axes
221 for i := 0 to e_MaxJoyAxes-1 do
222 begin
223 e_KeyNames[k + i*2 ] := Format('JOY%d A%d+', [j, i]);
224 e_KeyNames[k + i*2 + 1] := Format('JOY%d A%d-', [j, i]);
225 end;
226 k := JOYH_BEG + j * e_MaxJoyHats * 4;
227 // hats
228 for i := 0 to e_MaxJoyHats-1 do
229 begin
230 e_KeyNames[k + i*4 ] := Format('JOY%d D%dL', [j, i]);
231 e_KeyNames[k + i*4 + 1] := Format('JOY%d D%dU', [j, i]);
232 e_KeyNames[k + i*4 + 2] := Format('JOY%d D%dR', [j, i]);
233 e_KeyNames[k + i*4 + 3] := Format('JOY%d D%dD', [j, i]);
234 end;
235 end;
236 end;
238 function e_InitInput(): Boolean;
239 begin
240 Result := False;
242 e_JoysticksAvailable := OpenJoysticks();
243 e_EnableInput := True;
244 GenerateKeyNames();
246 Result := True;
247 end;
249 procedure e_ReleaseInput();
250 begin
251 ReleaseJoysticks();
252 e_JoysticksAvailable := 0;
253 end;
255 procedure e_ClearInputBuffer();
256 var
257 i, j, d: Integer;
258 begin
259 for i := Low(KeyBuffer) to High(KeyBuffer) do
260 KeyBuffer[i] := False;
261 if (Joysticks = nil) or (e_JoysticksAvailable = 0) then
262 for i := Low(Joysticks) to High(Joysticks) do
263 begin
264 for j := Low(Joysticks[i].ButtBuf) to High(Joysticks[i].ButtBuf) do
265 Joysticks[i].ButtBuf[j] := False;
266 for j := Low(Joysticks[i].AxisBuf) to High(Joysticks[i].AxisBuf) do
267 Joysticks[i].AxisBuf[j] := 0;
268 for j := Low(Joysticks[i].HatBuf) to High(Joysticks[i].HatBuf) do
269 for d := Low(Joysticks[i].HatBuf[j]) to High(Joysticks[i].HatBuf[j]) do
270 Joysticks[i].HatBuf[j, d] := False;
271 end;
272 end;
274 function e_PollInput(): Boolean;
275 var
276 kb, js: Boolean;
277 begin
278 kb := PollKeyboard();
279 js := PollJoysticks();
281 Result := kb or js;
282 end;
284 function e_KeyPressed(Key: Word): Boolean;
285 var
286 joyi, dir: Integer;
287 begin
288 Result := False;
289 if (Key = IK_INVALID) or (Key = 0) then Exit;
291 if (Key < KBRD_END) then
292 begin // Keyboard buttons/keys
293 Result := KeyBuffer[Key];
294 end
296 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
297 begin // Joystick buttons
298 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
299 if JoyI >= e_JoysticksAvailable then
300 Result := False
301 else
302 begin
303 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
304 Result := Joysticks[JoyI].ButtBuf[Key];
305 end;
306 end
308 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
309 begin // Joystick axes
310 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
311 if JoyI >= e_JoysticksAvailable then
312 Result := False
313 else
314 begin
315 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
316 dir := Key mod 2;
317 if dir = AX_MINUS then
318 Result := Joysticks[JoyI].AxisBuf[Key div 2] < -e_JoystickDeadzones[JoyI]
319 else
320 Result := Joysticks[JoyI].AxisBuf[Key div 2] > e_JoystickDeadzones[JoyI]
321 end;
322 end
324 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
325 begin // Joystick hats
326 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
327 if JoyI >= e_JoysticksAvailable then
328 Result := False
329 else
330 begin
331 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
332 dir := Key mod 4;
333 Result := Joysticks[JoyI].HatBuf[Key div 4, dir];
334 end;
335 end;
336 end;
338 procedure e_SetKeyState(key: Word; state: Integer);
339 var
340 JoyI, dir: Integer;
341 begin
342 if (Key = IK_INVALID) or (Key = 0) then Exit;
344 if (Key < KBRD_END) then
345 begin // Keyboard buttons/keys
346 keyBuffer[key] := (state <> 0);
347 end
349 else if (Key >= JOYK_BEG) and (Key < JOYK_END) then
350 begin // Joystick buttons
351 JoyI := (Key - JOYK_BEG) div e_MaxJoyBtns;
352 if JoyI >= e_JoysticksAvailable then
353 Exit
354 else
355 begin
356 Key := (Key - JOYK_BEG) mod e_MaxJoyBtns;
357 Joysticks[JoyI].ButtBuf[Key] := (state <> 0);
358 end;
359 end
361 else if (Key >= JOYA_BEG) and (Key < JOYA_END) then
362 begin // Joystick axes
363 JoyI := (Key - JOYA_BEG) div (e_MaxJoyAxes*2);
364 if JoyI >= e_JoysticksAvailable then
365 Exit
366 else
367 begin
368 Key := (Key - JOYA_BEG) mod (e_MaxJoyAxes*2);
369 Joysticks[JoyI].AxisBuf[Key div 2] := state;
370 end;
371 end
373 else if (Key >= JOYH_BEG) and (Key < JOYH_END) then
374 begin // Joystick hats
375 JoyI := (Key - JOYH_BEG) div (e_MaxJoyHats*4);
376 if JoyI >= e_JoysticksAvailable then
377 Exit
378 else
379 begin
380 Key := (Key - JOYH_BEG) mod (e_MaxJoyHats*4);
381 dir := Key mod 4;
382 Joysticks[JoyI].HatBuf[Key div 4, dir] := (state <> 0);
383 end;
384 end;
385 end;
387 function e_AnyKeyPressed(): Boolean;
388 var
389 k: Word;
390 begin
391 Result := False;
393 for k := 1 to e_MaxInputKeys do
394 if e_KeyPressed(k) then
395 begin
396 Result := True;
397 Break;
398 end;
399 end;
401 function e_GetFirstKeyPressed(): Word;
402 var
403 k: Word;
404 begin
405 Result := IK_INVALID;
407 for k := 1 to e_MaxInputKeys do
408 if e_KeyPressed(k) then
409 begin
410 Result := k;
411 Break;
412 end;
413 end;
415 ////////////////////////////////////////////////////////////////////////////////
417 function e_JoystickStateToString(mode: Integer): String;
418 begin
419 Result := '';
420 end;
422 function e_JoyByHandle(handle: Word): Integer;
423 var
424 i: Integer;
425 begin
426 Result := -1;
427 if Joysticks = nil then Exit;
428 for i := Low(Joysticks) to High(Joysticks) do
429 if Joysticks[i].ID = handle then
430 begin
431 Result := i;
432 Exit;
433 end;
434 end;
436 function e_JoyButtonToKey(id: Word; btn: Byte): Word;
437 begin
438 Result := 0;
439 if id >= Length(Joysticks) then Exit;
440 Result := JOYK_BEG + id*e_MaxJoyBtns + btn;
441 end;
443 function e_JoyAxisToKey(id: Word; ax: Byte; dir: Byte): Word;
444 begin
445 Result := 0;
446 if id >= Length(Joysticks) then Exit;
447 Result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir;
448 end;
450 function e_JoyHatToKey(id: Word; hat: Byte; dir: Byte): Word;
451 begin
452 Result := 0;
453 if id >= Length(Joysticks) then Exit;
454 Result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir;
455 end;
457 end.