DEADSOFTWARE

99b338cdc92f3d610c22a7d555c46c75f3070854
[d2df-sdl.git] / src / game / sdl / g_system.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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_system;
18 interface
20 uses Utils;
22 (* --- Utils --- *)
23 function sys_GetTicks (): Int64;
24 procedure sys_Delay (ms: Integer);
26 (* --- Graphics --- *)
27 function sys_GetDisplayModes (bpp: Integer): SSArray;
28 function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen, maximized: Boolean): Boolean;
29 procedure sys_EnableVSync (yes: Boolean);
30 procedure sys_Repaint;
32 (* --- Input --- *)
33 function sys_HandleInput (): Boolean;
34 procedure sys_RequestQuit;
36 (* --- Init --- *)
37 procedure sys_Init;
38 procedure sys_Final;
40 var (* hooks *)
41 sys_CharPress: procedure (ch: AnsiChar) = nil;
43 implementation
45 uses
46 {$IF DEFINED(DARWIN) OR DEFINED(MACOS)}
47 Keyboards, Events,
48 {$IFDEF CPU64}
49 {$linkframework Carbon}
50 {$ENDIF}
51 {$ENDIF}
52 SysUtils, SDL, Math,
53 {$INCLUDE ../nogl/noGLuses.inc}
54 e_log, r_graphics, e_input, e_sound,
55 g_options, g_console, g_game, g_menu, g_gui, g_basic;
57 const
58 GameTitle = 'Doom 2D: Forever (SDL 1.2, %s, %s)';
60 var
61 userResize: Boolean;
62 modeResize: Integer;
63 useScancodes: Boolean;
64 screen: PSDL_Surface;
65 JoystickHandle: array [0..e_MaxJoys - 1] of PSDL_Joystick;
66 JoystickHatState: array [0..e_MaxJoys - 1, 0..e_MaxJoyHats - 1, HAT_LEFT..HAT_DOWN] of Boolean;
67 JoystickZeroAxes: array [0..e_MaxJoys - 1, 0..e_MaxJoyAxes - 1] of Integer;
69 (* --------- Utils --------- *)
71 function sys_GetTicks (): Int64;
72 begin
73 result := SDL_GetTicks()
74 end;
76 procedure sys_Delay (ms: Integer);
77 begin
78 SDL_Delay(ms)
79 end;
81 (* --------- Graphics --------- *)
83 function LoadGL: Boolean;
84 var ltmp: Integer;
85 begin
86 result := true;
87 {$IFDEF NOGL_INIT}
88 nogl_Init;
89 if glRenderToFBO and (not nogl_ExtensionSupported('GL_OES_framebuffer_object')) then
90 begin
91 e_LogWriteln('GL: framebuffer objects not supported; disabling FBO rendering');
92 glRenderToFBO := false;
93 end;
94 {$ELSE}
95 if glRenderToFBO and (not Load_GL_ARB_framebuffer_object) then
96 begin
97 e_LogWriteln('GL: framebuffer objects not supported; disabling FBO rendering');
98 glRenderToFBO := false;
99 end;
100 {$ENDIF}
101 if SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, ltmp) = 0 then
102 begin
103 e_LogWritefln('stencil buffer size: %s', [ltmp]);
104 gwin_has_stencil := (ltmp > 0);
105 end;
106 end;
108 procedure FreeGL;
109 begin
110 {$IFDEF NOGL_INIT}
111 nogl_Quit();
112 {$ENDIF}
113 end;
115 procedure UpdateSize (w, h: Integer);
116 begin
117 gWinSizeX := w;
118 gWinSizeY := h;
119 gRC_Width := w;
120 gRC_Height := h;
121 if glRenderToFBO then
122 begin
123 // store real window size in gWinSize, downscale resolution now
124 w := round(w / r_pixel_scale);
125 h := round(h / r_pixel_scale);
126 if not e_ResizeFramebuffer(w, h) then
127 begin
128 e_LogWriteln('GL: could not create framebuffer, falling back to --no-fbo');
129 glRenderToFBO := False;
130 w := gWinSizeX;
131 h := gWinSizeY;
132 end;
133 end;
134 gScreenWidth := w;
135 gScreenHeight := h;
136 {$IFDEF ENABLE_HOLMES}
137 fuiScrWdt := w;
138 fuiScrHgt := h;
139 {$ENDIF}
140 e_ResizeWindow(w, h);
141 e_InitGL;
142 g_Game_SetupScreenSize;
143 g_Menu_Reset;
144 g_Game_ClearLoading;
145 end;
147 function GetDriver (): AnsiString;
148 var buf: array [0..31] of AnsiChar;
149 begin
150 buf := '';
151 SDL_VideoDriverName(buf, Length(buf));
152 result := AnsiString(buf);
153 end;
155 function GetTitle (): AnsiString;
156 var info: AnsiString;
157 begin
158 info := g_GetBuildHash(false);
159 if info = 'custom build' then
160 info := info + ' by ' + g_GetBuilderName() + ' ' + GAME_BUILDDATE + ' ' + GAME_BUILDTIME;
161 result := Format(GameTitle, [GetDriver(), info]);
162 end;
164 function InitWindow (w, h, bpp: Integer; fullScreen: Boolean): Boolean;
165 var flags: Uint32; title: AnsiString;
166 begin
167 e_LogWritefln('InitWindow %s %s %s %s', [w, h, bpp, fullScreen]);
168 result := false;
169 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
170 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
171 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
172 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
173 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
174 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // lights; it is enough to have 1-bit stencil buffer for lighting, but...
175 flags := SDL_OPENGL;
176 if fullScreen then flags := flags or SDL_FULLSCREEN;
177 if userResize then flags := flags or SDL_VIDEORESIZE;
178 if (screen = nil) or (SDL_VideoModeOk(w, h, bpp, flags) <> 0) then
179 begin
180 SDL_FreeSurface(screen);
181 screen := SDL_SetVideoMode(w, h, bpp, flags);
182 if screen <> nil then
183 begin
184 if not LoadGL then
185 begin
186 e_LogWriteln('GL: unable to load OpenGL functions', TMsgType.Fatal);
187 exit;
188 end;
189 title := GetTitle();
190 SDL_WM_SetCaption(PChar(title), nil);
191 gFullScreen := fullscreen;
192 gRC_FullScreen := fullscreen;
193 UpdateSize(w, h);
194 result := True
195 end
196 end
197 else
198 begin
199 e_LogWritefln('SDL: video mode not supported', [])
200 end
201 end;
203 procedure sys_Repaint;
204 begin
205 SDL_GL_SwapBuffers
206 end;
208 procedure sys_EnableVSync (yes: Boolean);
209 begin
210 (* ??? *)
211 end;
213 function sys_GetDisplayModes (bpp: Integer): SSArray;
214 var m: PPSDL_Rect; f: TSDL_PixelFormat; i, count: Integer;
215 begin
216 result := nil;
217 FillChar(f, sizeof(f), 0);
218 f.palette := nil;
219 f.BitsPerPixel := bpp;
220 f.BytesPerPixel := (bpp + 7) div 8;
221 m := SDL_ListModes(@f, SDL_OPENGL or SDL_FULLSCREEN);
222 if (m <> NIL) and (UIntPtr(m) <> UIntPtr(-1)) then
223 begin
224 count := 0;
225 while m[count] <> nil do inc(count);
226 SetLength(result, count);
227 for i := 0 to count - 1 do
228 result[i] := IntToStr(m[i].w) + 'x' + IntToStr(m[i].h);
229 end
230 end;
232 function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen, maximized: Boolean): Boolean;
233 begin
234 result := InitWindow(w, h, bpp, fullscreen)
235 end;
237 (* --------- Joystick --------- *)
239 procedure HandleJoyButton (var ev: TSDL_JoyButtonEvent);
240 var down: Boolean; key: Integer;
241 begin
242 if (ev.which < e_MaxJoys) and (ev.button < e_MaxJoyBtns) then
243 begin
244 key := e_JoyButtonToKey(ev.which, ev.button);
245 down := ev.type_ = SDL_JOYBUTTONDOWN;
246 if g_dbg_input then
247 e_LogWritefln('Input Debug: jbutton, joy=%s, button=%s, keycode=%s, press=%s', [ev.which, ev.button, key, down]);
248 e_KeyUpDown(key, down);
249 g_Console_ProcessBind(key, down)
250 end
251 else
252 begin
253 if g_dbg_input then
254 begin
255 down := ev.type_ = SDL_JOYBUTTONDOWN;
256 e_LogWritefln('Input Debug: NOT IN RANGE! jbutton, joy=%s, button=%s, press=%s', [ev.which, ev.button, down])
257 end
258 end
259 end;
261 procedure HandleJoyAxis (var ev: TSDL_JoyAxisEvent);
262 var key, minuskey: Integer;
263 begin
264 if (ev.which < e_MaxJoys) and (ev.axis < e_MaxJoyAxes) then
265 begin
266 key := e_JoyAxisToKey(ev.which, ev.axis, AX_PLUS);
267 minuskey := e_JoyAxisToKey(ev.which, ev.axis, AX_MINUS);
269 if g_dbg_input then
270 e_LogWritefln('Input Debug: jaxis, joy=%s, axis=%s, value=%s, zeroaxes=%s, deadzone=%s', [ev.which, ev.axis, ev.value, JoystickZeroAxes[ev.which, ev.axis], e_JoystickDeadzones[ev.which]]);
272 if ev.value < JoystickZeroAxes[ev.which, ev.axis] - e_JoystickDeadzones[ev.which] then
273 begin
274 if (e_KeyPressed(key)) then
275 begin
276 e_KeyUpDown(key, False);
277 g_Console_ProcessBind(key, False)
278 end;
279 e_KeyUpDown(minuskey, True);
280 g_Console_ProcessBind(minuskey, True)
281 end
282 else if ev.value > JoystickZeroAxes[ev.which, ev.axis] + e_JoystickDeadzones[ev.which] then
283 begin
284 if (e_KeyPressed(minuskey)) then
285 begin
286 e_KeyUpDown(minuskey, False);
287 g_Console_ProcessBind(minuskey, False)
288 end;
289 e_KeyUpDown(key, True);
290 g_Console_ProcessBind(key, True)
291 end
292 else
293 begin
294 if (e_KeyPressed(minuskey)) then
295 begin
296 e_KeyUpDown(minuskey, False);
297 g_Console_ProcessBind(minuskey, False)
298 end;
299 if (e_KeyPressed(key)) then
300 begin
301 e_KeyUpDown(key, False);
302 g_Console_ProcessBind(key, False)
303 end
304 end
305 end
306 else
307 begin
308 if g_dbg_input then
309 e_LogWritefln('Input Debug: NOT IN RANGE! jaxis, joy=%s, axis=%s, value=%s, zeroaxes=%s, deadzone=%s', [ev.which, ev.axis, ev.value, JoystickZeroAxes[ev.which, ev.axis], e_JoystickDeadzones[ev.which]])
310 end
311 end;
313 procedure HandleJoyHat (var ev: TSDL_JoyHatEvent);
314 var
315 down: Boolean;
316 i, key: Integer;
317 hat: array [HAT_LEFT..HAT_DOWN] of Boolean;
318 begin
319 if (ev.which < e_MaxJoys) and (ev.hat < e_MaxJoyHats) then
320 begin
321 if g_dbg_input then
322 e_LogWritefln('Input Debug: jhat, joy=%s, hat=%s, value=%s', [ev.which, ev.hat, ev.value]);
323 hat[HAT_UP] := LongBool(ev.value and SDL_HAT_UP);
324 hat[HAT_DOWN] := LongBool(ev.value and SDL_HAT_DOWN);
325 hat[HAT_LEFT] := LongBool(ev.value and SDL_HAT_LEFT);
326 hat[HAT_RIGHT] := LongBool(ev.value and SDL_HAT_RIGHT);
327 for i := HAT_LEFT to HAT_DOWN do
328 begin
329 if JoystickHatState[ev.which, ev.hat, i] <> hat[i] then
330 begin
331 down := hat[i];
332 key := e_JoyHatToKey(ev.which, ev.hat, i);
333 e_KeyUpDown(key, down);
334 g_Console_ProcessBind(key, down)
335 end
336 end;
337 JoystickHatState[ev.which, ev.hat] := hat
338 end
339 else
340 begin
341 if g_dbg_input then
342 e_LogWritefln('Input Debug: NOT IN RANGE! jhat, joy=%s, hat=%s, value=%s', [ev.which, ev.hat, ev.value])
343 end
344 end;
346 procedure AddJoystick (which: Integer);
347 var i: Integer;
348 begin
349 assert(which < e_MaxJoys);
350 JoystickHandle[which] := SDL_JoystickOpen(which);
351 if JoystickHandle[which] <> nil then
352 begin
353 e_LogWritefln('Added Joystick %s', [which]);
354 e_JoystickAvailable[which] := True;
355 for i := 0 to Min(SDL_JoystickNumAxes(JoystickHandle[which]), e_MaxJoyAxes) - 1 do
356 JoystickZeroAxes[which, i] := SDL_JoystickGetAxis(JoystickHandle[which], i)
357 end
358 else
359 begin
360 e_LogWritefln('Failed to open Joystick %s', [which])
361 end
362 end;
364 procedure RemoveJoystick (which: Integer);
365 begin
366 assert(which < e_MaxJoys);
367 e_LogWritefln('Remove Joystick %s', [which]);
368 e_JoystickAvailable[which] := False;
369 if JoystickHandle[which] <> nil then
370 SDL_JoystickClose(JoystickHandle[which]);
371 JoystickHandle[which] := nil
372 end;
374 (* --------- Input --------- *)
376 {$IF DEFINED(DARWIN) OR DEFINED(MACOS)}
377 var
378 IsMacPlatform: Boolean;
380 function IsMacModSym (sym: Integer): Boolean;
381 begin
382 case sym of
383 SDLK_NUMLOCK,
384 SDLK_CAPSLOCK,
385 SDLK_RCTRL, SDLK_LCTRL,
386 SDLK_RSHIFT, SDLK_LSHIFT,
387 SDLK_RALT, SDLK_LALT,
388 SDLK_RSUPER, SDLK_LSUPER,
389 SDLK_RMETA, SDLK_LMETA:
390 result := true;
391 otherwise
392 result := false;
393 end;
394 end;
396 function Mac2Stub (scancode: Integer): Integer;
397 begin
398 (* SDL 2 swap tilda/grave and paragraph/plus-minus buttons on ISO keyboards *)
399 if ((scancode = 10) or (scancode = 50)) and (KBGetLayoutType(LMGetKbdType()) = kKeyboardISO) then
400 scancode := 60 - scancode;
401 case scancode of
402 0: result := IK_A;
403 1: result := IK_S;
404 2: result := IK_D;
405 3: result := IK_F;
406 4: result := IK_H;
407 5: result := IK_G;
408 6: result := IK_Z;
409 7: result := IK_X;
410 8: result := IK_C;
411 9: result := IK_V;
412 10: result := IK_NONUSBACKSLASH;
413 11: result := IK_B;
414 12: result := IK_Q;
415 13: result := IK_W;
416 14: result := IK_E;
417 15: result := IK_R;
418 16: result := IK_Y;
419 17: result := IK_T;
420 18: result := IK_1;
421 19: result := IK_2;
422 20: result := IK_3;
423 21: result := IK_4;
424 22: result := IK_6;
425 23: result := IK_5;
426 24: result := IK_EQUALS;
427 25: result := IK_9;
428 26: result := IK_7;
429 27: result := IK_MINUS;
430 28: result := IK_8;
431 29: result := IK_0;
432 30: result := {IK_RIGHTBRACKET} IK_RBRACKET;
433 31: result := IK_O;
434 32: result := IK_U;
435 33: result := {IK_LEFTBRACKET} IK_LBRACKET;
436 34: result := IK_I;
437 35: result := IK_P;
438 36: result := IK_RETURN;
439 37: result := IK_L;
440 38: result := IK_J;
441 39: result := {IK_APOSTROPHE} IK_QUOTE;
442 40: result := IK_K;
443 41: result := IK_SEMICOLON;
444 42: result := IK_BACKSLASH;
445 43: result := IK_COMMA;
446 44: result := IK_SLASH;
447 45: result := IK_N;
448 46: result := IK_M;
449 47: result := {IK_PERIOD} IK_DOT;
450 48: result := IK_TAB;
451 49: result := IK_SPACE;
452 50: result := IK_GRAVE;
453 51: result := IK_BACKSPACE;
454 52: result := {IK_KP_ENTER} IK_KPRETURN;
455 53: result := IK_ESCAPE;
456 54: result := {IK_RGUI} IK_RWIN;
457 55: result := {IK_LGUI} IK_WIN;
458 56: result := {IK_LSHIFT} IK_SHIFT;
459 57: result := IK_CAPSLOCK;
460 58: result := {IK_LALT} IK_ALT;
461 59: result := {IK_LCTRL} IK_CTRL;
462 60: result := IK_RSHIFT;
463 61: result := IK_RALT;
464 62: result := IK_RCTRL;
465 63: result := {IK_RGUI} IK_RWIN;
466 {64: result := IK_F17;}
467 65: result := {IK_KP_PERIOD} IK_KPDOT;
468 66: result := IK_INVALID; (* unused? *)
469 67: result := {IK_KP_MULTIPLY} IK_KPMULTIPLE;
470 68: result := IK_INVALID; (* unused? *)
471 69: result := {IK_KP_PLUS} IK_KPPLUS;
472 70: result := IK_INVALID; (* unused? *)
473 71: result := {IK_NUMLOCKCLEAR} IK_NUMLOCK;
474 {72: result := IK_VOLUMEUP;}
475 {73: result := IK_VOLUMEDOWN;}
476 {74: result := IK_MUTE;}
477 75: result := {IK_KP_DIVIDE} IK_KPDIVIDE;
478 76: result := {IK_KP_ENTER} IK_KPRETURN;
479 77: result := IK_INVALID; (* unused? *)
480 78: result := {IK_KP_MINUS} IK_KPMINUS;
481 {79: result := IK_F18;}
482 {80: result := IK_F19;}
483 {81: result := IK_KP_EQUALS;}
484 82: result := {IK_KP_0} IK_KPINSERT;
485 83: result := {IK_KP_1} IK_KPEND;
486 84: result := {IK_KP_2} IK_KPDOWN;
487 85: result := {IK_KP_3} IK_KPPAGEDN;
488 86: result := {IK_KP_4} IK_KPLEFT;
489 87: result := {IK_KP_5} IK_KP5;
490 88: result := {IK_KP_6} IK_KPRIGHT;
491 89: result := {IK_KP_7} IK_KPHOME;
492 90: result := IK_INVALID; (* unused? *)
493 91: result := {IK_KP_8} IK_KPUP;
494 92: result := {IK_KP_9} IK_KPPAGEUP;
495 {93: result := IK_INTERNATIONAL3;}
496 {94: result := IK_INTERNATIONAL1;}
497 {95: result := IK_KP_COMMA;}
498 96: result := IK_F5;
499 97: result := IK_F6;
500 98: result := IK_F7;
501 99: result := IK_F3;
502 100: result := IK_F8;
503 101: result := IK_F9;
504 {102: result := IK_LANG2;}
505 103: result := IK_F11;
506 {104: result := IK_LANG1;}
507 105: result := {IK_PRINTSCREEN} IK_PRINTSCR;
508 {106: result := IK_F16;}
509 107: result := IK_SCROLLLOCK;
510 108: result := IK_INVALID; (* unused? *)
511 109: result := IK_F10;
512 {110: result := IK_APPLICATION;}
513 111: result := IK_F12;
514 112: result := IK_INVALID; (* unused? *)
515 113: result := IK_PAUSE;
516 114: result := IK_INSERT;
517 115: result := IK_HOME;
518 116: result := IK_PAGEUP;
519 117: result := IK_DELETE;
520 118: result := IK_F4;
521 119: result := IK_END;
522 120: result := IK_F2;
523 121: result := {IK_PAGEDOWN} IK_PAGEDN;
524 122: result := IK_F1;
525 123: result := IK_LEFT;
526 124: result := IK_RIGHT;
527 125: result := IK_DOWN;
528 126: result := IK_UP;
529 {127: result := IK_POWER;}
530 otherwise result := IK_INVALID
531 end
532 end;
533 {$ENDIF}
535 function Key2Stub (key: Integer): Integer;
536 var x: Integer;
537 begin
538 case key of
539 SDLK_ESCAPE: x := IK_ESCAPE;
540 SDLK_RETURN: x := IK_RETURN;
541 SDLK_KP_ENTER: x := IK_KPRETURN;
542 SDLK_KP0: x := IK_KPINSERT;
543 SDLK_UP: x := IK_UP;
544 SDLK_KP8: x := IK_KPUP;
545 SDLK_DOWN: x := IK_DOWN;
546 SDLK_KP2: x := IK_KPDOWN;
547 SDLK_LEFT: x := IK_LEFT;
548 SDLK_KP4: x := IK_KPLEFT;
549 SDLK_RIGHT: x := IK_RIGHT;
550 SDLK_KP6: x := IK_KPRIGHT;
551 SDLK_DELETE: x := IK_DELETE;
552 SDLK_HOME: x := IK_HOME;
553 SDLK_KP7: x := IK_KPHOME;
554 SDLK_INSERT: x := IK_INSERT;
555 SDLK_SPACE: x := IK_SPACE;
556 SDLK_LSHIFT: x := IK_SHIFT;
557 SDLK_LALT: x := IK_ALT;
558 SDLK_TAB: x := IK_TAB;
559 SDLK_PAGEUP: x := IK_PAGEUP;
560 SDLK_KP9: x := IK_KPPAGEUP;
561 SDLK_PAGEDOWN: x := IK_PAGEDN;
562 SDLK_KP3: x := IK_KPPAGEDN;
563 SDLK_KP5: x := IK_KP5;
564 SDLK_NUMLOCK: x := IK_NUMLOCK;
565 SDLK_KP_DIVIDE: x := IK_KPDIVIDE;
566 SDLK_KP_MULTIPLY: x := IK_KPMULTIPLE;
567 SDLK_KP_MINUS: x := IK_KPMINUS;
568 SDLK_KP_PLUS: x := IK_KPPLUS;
569 SDLK_KP_PERIOD: x := IK_KPDOT;
570 SDLK_CAPSLOCK: x := IK_CAPSLOCK;
571 SDLK_RSHIFT: x := IK_RSHIFT;
572 SDLK_LCTRL: x := IK_CTRL;
573 SDLK_RCTRL: x := IK_RCTRL;
574 SDLK_RALT: x := IK_RALT;
575 SDLK_LSUPER: x := IK_WIN;
576 SDLK_RSUPER: x := IK_RWIN;
577 SDLK_MENU: x := IK_MENU;
578 SDLK_PRINT: x := IK_PRINTSCR;
579 SDLK_SCROLLOCK: x := IK_SCROLLLOCK;
580 SDLK_LEFTBRACKET: x := IK_LBRACKET;
581 SDLK_RIGHTBRACKET: x := IK_RBRACKET;
582 SDLK_SEMICOLON: x := IK_SEMICOLON;
583 SDLK_QUOTE: x := IK_QUOTE;
584 SDLK_BACKSLASH: x := IK_BACKSLASH;
585 SDLK_SLASH: x := IK_SLASH;
586 SDLK_COMMA: x := IK_COMMA;
587 SDLK_PERIOD: x := IK_DOT;
588 SDLK_EQUALS: x := IK_EQUALS;
589 SDLK_0: x := IK_0;
590 SDLK_1: x := IK_1;
591 SDLK_2: x := IK_2;
592 SDLK_3: x := IK_3;
593 SDLK_4: x := IK_4;
594 SDLK_5: x := IK_5;
595 SDLK_6: x := IK_6;
596 SDLK_7: x := IK_7;
597 SDLK_8: x := IK_8;
598 SDLK_9: x := IK_9;
599 SDLK_F1: x := IK_F1;
600 SDLK_F2: x := IK_F2;
601 SDLK_F3: x := IK_F3;
602 SDLK_F4: x := IK_F4;
603 SDLK_F5: x := IK_F5;
604 SDLK_F6: x := IK_F6;
605 SDLK_F7: x := IK_F7;
606 SDLK_F8: x := IK_F8;
607 SDLK_F9: x := IK_F9;
608 SDLK_F10: x := IK_F10;
609 SDLK_F11: x := IK_F11;
610 SDLK_F12: x := IK_F12;
611 SDLK_END: x := IK_END;
612 SDLK_KP1: x := IK_KPEND;
613 SDLK_BACKSPACE: x := IK_BACKSPACE;
614 SDLK_BACKQUOTE: x := IK_BACKQUOTE;
615 SDLK_PAUSE: x := IK_PAUSE;
616 SDLK_A..SDLK_Z: x := IK_A + (key - SDLK_A);
617 SDLK_MINUS: x := IK_MINUS;
618 else
619 x := IK_INVALID
620 end;
621 result := x
622 end;
624 procedure HandleKeyboard (var ev: TSDL_KeyboardEvent);
625 var down, repeated: Boolean; key: Integer; ch: Char;
626 begin
627 key := IK_INVALID;
628 if useScancodes then
629 begin
630 {$IF DEFINED(DARWIN) OR DEFINED(MACOS)}
631 if IsMacPlatform then
632 if IsMacModSym(ev.keysym.sym) = false then
633 key := Mac2Stub(ev.keysym.scancode);
634 {$ENDIF}
635 end;
636 if key = IK_INVALID then
637 key := Key2Stub(ev.keysym.sym);
638 down := (ev.type_ = SDL_KEYDOWN);
639 repeated := down and e_KeyPressed(key);
640 ch := wchar2win(WideChar(ev.keysym.unicode));
641 if g_dbg_input then
642 e_LogWritefln('Input Debug: keysym, scancode=%s, down=%s, sym=%s, state=%s, unicode=%s, stubsym=%s, cp1251=%s', [ev.keysym.scancode, down, ev.keysym.sym, ev.state, ev.keysym.unicode, key, Ord(ch)]);
643 if not repeated then
644 begin
645 e_KeyUpDown(key, down);
646 g_Console_ProcessBind(key, down);
647 end
648 else
649 begin
650 g_Console_ProcessBindRepeat(key)
651 end;
652 if @sys_CharPress <> nil then
653 if down and IsValid1251(ev.keysym.unicode) and IsPrintable1251(ch) then
654 sys_CharPress(ch)
655 end;
657 procedure HandleResize (var ev: TSDL_ResizeEvent);
658 begin
659 if g_dbg_input then
660 e_LogWritefln('Input Debug: SDL_VIDEORESIZE %s %s', [ev.w, ev.h]);
661 if modeResize = 1 then
662 UpdateSize(ev.w, ev.h)
663 else if modeResize > 1 then
664 InitWindow(ev.w, ev.h, gBPP, gFullscreen)
665 end;
667 function sys_HandleInput (): Boolean;
668 var ev: TSDL_Event;
669 begin
670 result := false;
671 while SDL_PollEvent(@ev) <> 0 do
672 begin
673 case ev.type_ of
674 SDL_QUITEV: result := true;
675 SDL_VIDEORESIZE: HandleResize(ev.resize);
676 SDL_KEYUP, SDL_KEYDOWN: HandleKeyboard(ev.key);
677 SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP: HandleJoyButton(ev.jbutton);
678 SDL_JOYAXISMOTION: HandleJoyAxis(ev.jaxis);
679 SDL_JOYHATMOTION: HandleJoyHat(ev.jhat);
680 SDL_VIDEOEXPOSE: sys_Repaint;
681 SDL_ACTIVEEVENT: e_MuteChannels((ev.active.gain = 0) and gMuteWhenInactive);
682 end
683 end
684 end;
686 procedure sys_RequestQuit;
687 var ev: TSDL_Event;
688 begin
689 ev.quit.type_ := SDL_QUITEV;
690 SDL_PushEvent(@ev)
691 end;
693 (* --------- Init --------- *)
695 procedure sys_Init;
696 var flags: Uint32; i: Integer; name: AnsiString;
697 begin
698 e_WriteLog('Init SDL', TMsgType.Notify);
699 flags := SDL_INIT_VIDEO or SDL_INIT_AUDIO or
700 SDL_INIT_TIMER or SDL_INIT_JOYSTICK
701 (*or SDL_INIT_NOPARACHUTE*);
702 if SDL_Init(flags) <> 0 then
703 raise Exception.Create('SDL: Init failed: ' + SDL_GetError);
704 name := GetDriver();
705 e_LogWritefln('SDL: Video Driver "%s"', [name]);
706 {$IF DEFINED(DARWIN) OR DEFINED(MACOS)}
707 IsMacPlatform := (name = 'Quartz') or (name = 'toolbox') or (name = 'DSp');
708 {$ENDIF}
709 SDL_EnableUNICODE(1);
710 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
711 for i := 0 to e_MaxJoys - 1 do
712 AddJoystick(i)
713 end;
715 procedure sys_Final;
716 var i: Integer;
717 begin
718 e_WriteLog('Releasing SDL', TMsgType.Notify);
719 for i := 0 to e_MaxJoys - 1 do
720 RemoveJoystick(i);
721 if screen <> nil then
722 begin
723 FreeGL;
724 SDL_FreeSurface(screen)
725 end;
726 SDL_Quit
727 end;
729 initialization
730 (* window resize are broken both on linux and osx, so disabled by default *)
731 conRegVar('sdl_allow_resize', @userResize, 'allow to resize window by user', 'allow to resize window by user');
732 conRegVar('sdl_resize_action', @modeResize, 'set window resize mode (0: ignore, 1: change, 2: reset)', '');
733 conRegVar('sdl_use_scancodes', @useScancodes, 'use platform-specific scancodes when possible', '');
734 userResize := false;
735 modeResize := 0;
736 useScancodes := true;
737 end.