1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 Copyright (C) 2019 Shockolate Project
5 
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 //
22 // DG 2018: (eventually) SDL versions of the functions previously in kbMac.c, mouse.c and kbcook.c
23 //
24 
25 #include "lg.h"
26 #include "kb.h"
27 #include "mouse.h"
28 #include <stdlib.h>
29 #include <SDL.h>
30 #include <OpenGL.h>
31 
32 extern SDL_Window *window;
33 extern SDL_Renderer *renderer;
34 
35 bool fullscreenActive = false;
36 
toggleFullScreen()37 static void toggleFullScreen() {
38     fullscreenActive = !fullscreenActive;
39     SDL_SetWindowFullscreen(window, fullscreenActive ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
40 
41     if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED))
42         SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
43 }
44 
45 // current state of the keys, based on the SystemShock/Mac Keycodes (sshockKeyStates[keyCode] has the state for that
46 // key) set at the beginning of each frame in pump_events()
47 uchar sshockKeyStates[256];
48 
49 enum { kNumKBevents = 128, kNumMouseEvents = 128 };
50 
51 // queue keyboard events, created in pump_events(), consumed by kb_next()
52 static kbs_event kbEvents[kNumKBevents];
53 static int nextKBevent = 0; // where next to insert (also, if 0 there are no events)
54 
addKBevent(const kbs_event * ev)55 static void addKBevent(const kbs_event *ev) {
56     if (nextKBevent < kNumKBevents) {
57         kbEvents[nextKBevent] = *ev;
58         ++nextKBevent;
59     } else {
60         // printf("WTF, the kbEvents queue is full?!");
61         // drop the oldest event
62         memmove(&kbEvents[0], &kbEvents[1], sizeof(kbs_event) * (kNumKBevents - 1));
63         kbEvents[kNumKBevents - 1] = *ev;
64     }
65 }
66 
67 // same for mouse events, also created in pump_events(), consumed by mouse_next()
68 static ss_mouse_event mouseEvents[kNumMouseEvents];
69 static int nextMouseEvent = 0;
70 
71 // latest mouse state as input for MousePollProc() in mouse.c
72 ss_mouse_event latestMouseEvent;
73 
addMouseEvent(const ss_mouse_event * ev)74 static void addMouseEvent(const ss_mouse_event *ev) {
75     latestMouseEvent = *ev;
76 
77     if (nextMouseEvent < kNumMouseEvents) {
78         mouseEvents[nextMouseEvent] = latestMouseEvent;
79         ++nextMouseEvent;
80     } else {
81         // printf("WTF, the mouseEvents queue is full?!");
82         // drop the oldest event
83         memmove(&mouseEvents[0], &mouseEvents[1], sizeof(ss_mouse_event) * (kNumMouseEvents - 1));
84         mouseEvents[kNumMouseEvents - 1] = latestMouseEvent;
85     }
86 }
87 
sdlKeyCodeToSSHOCKkeyCode(SDL_Keycode kc)88 static uchar sdlKeyCodeToSSHOCKkeyCode(SDL_Keycode kc) {
89     // apparently System Shock uses the same keycodes as Mac
90     // which are luckily documented, see
91     // see http://snipplr.com/view/42797/
92     // and https://stackoverflow.com/a/16125341
93     // see also GameSrc/movekeys.c for a very short list
94 
95     // printf("sdlKeyCodeToSSHOCKkeyCode: %x\n", kc);
96 
97     switch (kc) {
98     case SDLK_a:
99         return 0x00; //  kVK_ANSI_A = 0x00,
100     case SDLK_s:
101         return 0x01; //  kVK_ANSI_S = 0x01,
102     case SDLK_d:
103         return 0x02; //  kVK_ANSI_D = 0x02,
104     case SDLK_f:
105         return 0x03; //  kVK_ANSI_F = 0x03,
106     case SDLK_h:
107         return 0x04; //  kVK_ANSI_H = 0x04,
108     case SDLK_g:
109         return 0x05; //  kVK_ANSI_G = 0x05,
110     case SDLK_z:
111         return 0x06; //  kVK_ANSI_Z = 0x06,
112     case SDLK_x:
113         return 0x07; //  kVK_ANSI_X = 0x07,
114     case SDLK_c:
115         return 0x08; //  kVK_ANSI_C = 0x08,
116     case SDLK_v:
117         return 0x09; //  kVK_ANSI_V = 0x09,
118     case SDLK_b:
119         return 0x0B; //  kVK_ANSI_B = 0x0B,
120     case SDLK_q:
121         return 0x0C; //  kVK_ANSI_Q = 0x0C,
122     case SDLK_w:
123         return 0x0D; //  kVK_ANSI_W = 0x0D,
124     case SDLK_e:
125         return 0x0E; //  kVK_ANSI_E = 0x0E,
126     case SDLK_r:
127         return 0x0F; //  kVK_ANSI_R = 0x0F,
128     case SDLK_y:
129         return 0x10; //  kVK_ANSI_Y = 0x10,
130     case SDLK_t:
131         return 0x11; //  kVK_ANSI_T = 0x11,
132     case SDLK_1:
133         return 0x12; //  kVK_ANSI_1 = 0x12,
134     case SDLK_2:
135         return 0x13; //  kVK_ANSI_2 = 0x13,
136     case SDLK_3:
137         return 0x14; //  kVK_ANSI_3 = 0x14,
138     case SDLK_4:
139         return 0x15; //  kVK_ANSI_4 = 0x15,
140     case SDLK_6:
141         return 0x16; //  kVK_ANSI_6 = 0x16,
142     case SDLK_5:
143         return 0x17; //  kVK_ANSI_5 = 0x17,
144     case SDLK_EQUALS:
145         return 0x18; //  kVK_ANSI_Equal = 0x18,
146     case SDLK_9:
147         return 0x19; //  kVK_ANSI_9 = 0x19,
148     case SDLK_7:
149         return 0x1A; //  kVK_ANSI_7 = 0x1A,
150     case SDLK_MINUS:
151         return 0x1B; //  kVK_ANSI_Minus = 0x1B,
152     case SDLK_8:
153         return 0x1C; //  kVK_ANSI_8 = 0x1C,
154     case SDLK_0:
155         return 0x1D; //  kVK_ANSI_0 = 0x1D,
156     case SDLK_RIGHTBRACKET:
157         return 0x1E; //  kVK_ANSI_RightBracket = 0x1E,
158     case SDLK_o:
159         return 0x1F; //  kVK_ANSI_O = 0x1F,
160     case SDLK_u:
161         return 0x20; //  kVK_ANSI_U = 0x20,
162     case SDLK_LEFTBRACKET:
163         return 0x21; //  kVK_ANSI_LeftBracket = 0x21,
164     case SDLK_i:
165         return 0x22; //  kVK_ANSI_I = 0x22,
166     case SDLK_p:
167         return 0x23; //  kVK_ANSI_P = 0x23,
168     case SDLK_l:
169         return 0x25; //  kVK_ANSI_L = 0x25,
170     case SDLK_j:
171         return 0x26; //  kVK_ANSI_J = 0x26,
172     case SDLK_QUOTE:
173         return 0x27; //  kVK_ANSI_Quote = 0x27, // TODO: or QUOTEDBL ?
174     case SDLK_k:
175         return 0x28; //  kVK_ANSI_K = 0x28,
176     case SDLK_SEMICOLON:
177         return 0x29; //  kVK_ANSI_Semicolon = 0x29,
178     case SDLK_BACKSLASH:
179         return 0x2A; //  kVK_ANSI_Backslash = 0x2A,
180     case SDLK_COMMA:
181         return 0x2B; //  kVK_ANSI_Comma = 0x2B,
182     case SDLK_SLASH:
183         return 0x2C; //  kVK_ANSI_Slash = 0x2C,
184     case SDLK_n:
185         return 0x2D; //  kVK_ANSI_N = 0x2D,
186     case SDLK_m:
187         return 0x2E; //  kVK_ANSI_M = 0x2E,
188     case SDLK_PERIOD:
189         return 0x2F; //  kVK_ANSI_Period = 0x2F,
190     case SDLK_BACKQUOTE:
191         return 0x32; //  kVK_ANSI_Grave = 0x32, // TODO: really?
192     case SDLK_KP_DECIMAL:
193         return 0x41; //  kVK_ANSI_KeypadDecimal   = 0x41,
194     case SDLK_KP_MULTIPLY:
195         return 0x43; //  kVK_ANSI_KeypadMultiply = 0x43,
196     case SDLK_KP_PLUS:
197         return 0x45; //  kVK_ANSI_KeypadPlus = 0x45,
198     case SDLK_KP_CLEAR:
199         return 0x47; //  kVK_ANSI_KeypadClear = 0x47,
200     case SDLK_KP_DIVIDE:
201         return 0x4B; //  kVK_ANSI_KeypadDivide = 0x4B,
202     case SDLK_KP_ENTER:
203         return 0x4C; //  kVK_ANSI_KeypadEnter   = 0x4C, aka _ENTER2_
204     case SDLK_KP_MINUS:
205         return 0x4E; //  kVK_ANSI_KeypadMinus   = 0x4E,
206     case SDLK_KP_EQUALS:
207         return 0x51; //  kVK_ANSI_KeypadEquals = 0x51,
208     case SDLK_KP_0:
209         return 0x52; //  kVK_ANSI_Keypad0 = 0x52,
210     case SDLK_KP_1:
211         return 0x53; //  kVK_ANSI_Keypad1 = 0x53, aka _END2_
212     case SDLK_KP_2:
213         return 0x54; //  kVK_ANSI_Keypad2 = 0x54, aka _DOWN2_
214     case SDLK_KP_3:
215         return 0x55; //  kVK_ANSI_Keypad3 = 0x55, aka _PGDN2_
216     case SDLK_KP_4:
217         return 0x56; //  kVK_ANSI_Keypad4 = 0x56, aka _LEFT2_
218     case SDLK_KP_5:
219         return 0x57; //  kVK_ANSI_Keypad5 = 0x57, aka _PAD5_
220     case SDLK_KP_6:
221         return 0x58; //  kVK_ANSI_Keypad6 = 0x58, aka _RIGHT2_
222     case SDLK_KP_7:
223         return 0x59; //  kVK_ANSI_Keypad7 = 0x59, aka _HOME2_
224     case SDLK_KP_8:
225         return 0x5B; //  kVK_ANSI_Keypad8 = 0x5B, aka _UP2_
226     case SDLK_KP_9:
227         return 0x5C; //  kVK_ANSI_Keypad9 = 0x5C, aka _PGUP2_
228 
229     // keycodes for keys that are independent of keyboard layout
230     case SDLK_RETURN:
231         return 0x24; //  kVK_Return  = 0x24,
232     case SDLK_TAB:
233         return 0x30; //  kVK_Tab     = 0x30,
234     case SDLK_SPACE:
235         return 0x31; //  kVK_Space   = 0x31,
236     case SDLK_DELETE:
237         return 0x33; //  kVK_Delete  = 0x33,
238     case SDLK_BACKSPACE:
239         return 0x33; //  kVK_Delete  = 0x33,
240     case SDLK_ESCAPE:
241         return 0x35; //  kVK_Escape  = 0x35,
242 
243         //    returning these is unnecessary and can cause keypresses to be missed
244         //    (esp keys with modifiers)
245         // case SDLK_LGUI : // fall-through
246         // case SDLK_RGUI : return 0x37; //  kVK_Command = 0x37, // FIXME: I think command is the windows/meta key?
247         // case SDLK_LSHIFT : return 0x38; //  kVK_Shift   = 0x38,
248         // case SDLK_CAPSLOCK : return 0x39; //  kVK_CapsLock= 0x39,
249         // case SDLK_LALT : return 0x3A; //  kVK_Option  = 0x3A, Option == Aalt
250         // case SDLK_LCTRL : return 0x3B; //  kVK_Control = 0x3B,
251         // case SDLK_RSHIFT : return 0x3C; //  kVK_RightShift  = 0x3C,
252         // case SDLK_RALT : return 0x3D; //  kVK_RightOption = 0x3D,
253         // case SDLK_RCTRL : return 0x3E; //  kVK_RightControl = 0x3E,
254 
255     // case SDLK_ : return 0x3F; //  kVK_Function = 0x3F, // TODO: what's this?
256     case SDLK_F17:
257         return 0x40; //  kVK_F17 = 0x40,
258     case SDLK_VOLUMEUP:
259         return 0x48; //  kVK_VolumeUp = 0x48,
260     case SDLK_VOLUMEDOWN:
261         return 0x49; //  kVK_VolumeDown = 0x49,
262     case SDLK_MUTE:
263         return 0x4A; //  kVK_Mute = 0x4A,
264     case SDLK_F18:
265         return 0x4F; //  kVK_F18 = 0x4F,
266     case SDLK_F19:
267         return 0x50; //  kVK_F19 = 0x50,
268     case SDLK_F20:
269         return 0x5A; //  kVK_F20 = 0x5A,
270     case SDLK_F5:
271         return 0x60; //  kVK_F5  = 0x60,
272     case SDLK_F6:
273         return 0x61; //  kVK_F6  = 0x61,
274     case SDLK_F7:
275         return 0x62; //  kVK_F7  = 0x62,
276     case SDLK_F3:
277         return 0x63; //  kVK_F3  = 0x63,
278     case SDLK_F8:
279         return 0x64; //  kVK_F8  = 0x64,
280     case SDLK_F9:
281         return 0x65; //  kVK_F9  = 0x65,
282     case SDLK_F11:
283         return 0x67; //  kVK_F11 = 0x67,
284     case SDLK_F13:
285         return 0x69; //  kVK_F13 = 0x69,
286     case SDLK_F16:
287         return 0x6A; //  kVK_F16 = 0x6A,
288     case SDLK_F14:
289         return 0x6B; //  kVK_F14 = 0x6B,
290     case SDLK_F10:
291         return 0x6D; //  kVK_F10 = 0x6D,
292     case SDLK_F12:
293         return 0x6F; //  kVK_F12 = 0x6F,
294     case SDLK_F15:
295         return 0x71; //  kVK_F15 = 0x71,
296     case SDLK_HELP:
297         return 0x72; //  kVK_Help = 0x72,
298     case SDLK_HOME:
299         return 0x73; //  kVK_Home = 0x73,
300     case SDLK_PAGEUP:
301         return 0x74; //  kVK_PageUp = 0x74,
302     // case SDLK_ : return 0x75; //  kVK_ForwardDelete = 0x75, // TODO: what's this?
303     case SDLK_F4:
304         return 0x76; //  kVK_F4 = 0x76,
305     case SDLK_END:
306         return 0x77; //  kVK_End = 0x77,
307     case SDLK_F2:
308         return 0x78; //  kVK_F2 = 0x78,
309     case SDLK_PAGEDOWN:
310         return 0x79; //  kVK_PageDown = 0x79,
311     case SDLK_F1:
312         return 0x7A; //  kVK_F1 = 0x7A,
313     case SDLK_LEFT:
314         return 0x7B; //  kVK_LeftArrow  = 0x7B, aka _LEFT_
315     case SDLK_RIGHT:
316         return 0x7C; //  kVK_RightArrow = 0x7C, aka _RIGHT
317     case SDLK_DOWN:
318         return 0x7D; //  kVK_DownArrow  = 0x7D, aka _DOWN_
319     case SDLK_UP:
320         return 0x7E; //  kVK_UpArrow    = 0x7E, aka _UP_
321     default:
322         return KBC_NONE;
323     }
324 }
325 
326 int MouseX;
327 int MouseY;
328 
329 int MouseChaosX;
330 int MouseChaosY;
331 
332 extern bool MouseCaptured;
333 
SetMouseXY(int mx,int my)334 void SetMouseXY(int mx, int my) {
335     int physical_width, physical_height;
336     SDL_GetWindowSize(window, &physical_width, &physical_height);
337 
338     int w, h;
339     SDL_RenderGetLogicalSize(renderer, &w, &h);
340 
341     float scale_x = (float)physical_width / w;
342     float scale_y = (float)physical_height / h;
343 
344     int x, y;
345     if (scale_x >= scale_y) {
346         x = (physical_width - w * scale_x) / 2;
347         y = 0;
348     } else {
349         x = 0;
350         y = (physical_height - h * scale_y) / 2;
351     }
352 
353     bool inside = (mx >= x && mx < x + w && my >= y && my < y + h);
354     bool focus = (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS); //checking mouse focus isn't what we want here
355 
356     if (!inside && focus) {
357         if (mx < x)
358             mx = x;
359         if (mx > x + w - 1)
360             mx = x + w - 1;
361         if (my < y)
362             my = y;
363         if (my > y + h - 1)
364             my = y + h - 1;
365     }
366 
367     if (focus) {
368         MouseX = mx;
369         MouseY = my;
370     }
371 
372     SDL_ShowCursor((!focus || (!inside && !MouseCaptured)) ? SDL_ENABLE : SDL_DISABLE);
373 }
374 
375 void get_mouselook_vel(int *vx, int *vy);
376 
377 extern bool TriggerRelMouseMode;
378 
379 static SDL_bool saved_rel_mouse = FALSE;
380 
381 // same codes as returned by sdlKeyCodeToSSHOCKkeyCode()
382 uchar Ascii2Code[95] = {
383     0x31, // space
384     0x12, // !
385     0x27, // "
386     0x14, // #
387     0x15, // $
388     0x17, // %
389     0x1A, // &
390     0x27, // '
391     0x19, // (
392     0x1D, // )
393     0x1C, // *
394     0x18, // +
395     0x2B, // ,
396     0x1B, // -
397     0x2F, // .
398     0x2C, // /
399     0x1D, // 0
400     0x12, // 1
401     0x13, // 2
402     0x14, // 3
403     0x15, // 4
404     0x17, // 5
405     0x16, // 6
406     0x1A, // 7
407     0x1C, // 8
408     0x19, // 9
409     0x29, // :
410     0x29, // ;
411     0x2B, // <
412     0x18, // =
413     0x2F, // >
414     0x2C, // ?
415     0x13, // @
416     0x00, // A
417     0x0B, // B
418     0x08, // C
419     0x02, // D
420     0x0E, // E
421     0x03, // F
422     0x05, // G
423     0x04, // H
424     0x22, // I
425     0x26, // J
426     0x28, // K
427     0x25, // L
428     0x2E, // M
429     0x2D, // N
430     0x1F, // O
431     0x23, // P
432     0x0C, // Q
433     0x0F, // R
434     0x01, // S
435     0x11, // T
436     0x20, // U
437     0x09, // V
438     0x0D, // W
439     0x07, // X
440     0x10, // Y
441     0x06, // Z
442     0x21, // [
443     0x2A, // backslash
444     0x1E, // ]
445     0x16, // ^
446     0x1B, // _
447     0x32, // `
448     0x00, // a
449     0x0B, // b
450     0x08, // c
451     0x02, // d
452     0x0E, // e
453     0x03, // f
454     0x05, // g
455     0x04, // h
456     0x22, // i
457     0x26, // j
458     0x28, // k
459     0x25, // l
460     0x2E, // m
461     0x2D, // n
462     0x1F, // o
463     0x23, // p
464     0x0C, // q
465     0x0F, // r
466     0x01, // s
467     0x11, // t
468     0x20, // u
469     0x09, // v
470     0x0D, // w
471     0x07, // x
472     0x10, // y
473     0x06, // z
474     0x21, // {
475     0x2A, // |
476     0x1E, // }
477     0x32  // ~
478 };
479 
pump_events(void)480 void pump_events(void) {
481     SDL_Event ev;
482 
483     while (SDL_PollEvent(&ev)) {
484         switch (ev.type) {
485         case SDL_QUIT:
486             // a bit hacky at this place, but this would allow exiting the game via the window's [x] button
487             exit(0); // TODO: I guess there is a better way.
488             break;
489 
490         // TODO: really also handle key up here? the mac code apparently didn't, but where else do
491         //       kbs_events with .state == KBS_UP come from?
492         case SDL_KEYUP:
493         case SDL_KEYDOWN: {
494             uchar c = sdlKeyCodeToSSHOCKkeyCode(ev.key.keysym.sym);
495             if (c != KBC_NONE) {
496                 kbs_event keyEvent = {0};
497 
498                 keyEvent.code = c;
499                 keyEvent.ascii = 0;
500                 keyEvent.modifiers = 0;
501 
502                 // https://wiki.libsdl.org/SDLKeycodeLookup
503                 // Keycodes for keys with printable characters are represented by the
504                 // character byte in parentheses. Keycodes without character representations
505                 // are determined by their scancode bitwise OR-ed with 1<<30 (0x40000000).
506 
507                 if (ev.key.keysym.sym >= 0x08 && ev.key.keysym.sym <= 127)
508                     keyEvent.ascii = ev.key.keysym.sym;
509                 else {
510                     // use these invented "ascii" codes for hotkey system
511                     // see MacSrc/Prefs.c
512                     switch (ev.key.keysym.sym) {
513                     case SDLK_F1:
514                         keyEvent.ascii = 128 + 0;
515                         break;
516                     case SDLK_F2:
517                         keyEvent.ascii = 128 + 1;
518                         break;
519                     case SDLK_F3:
520                         keyEvent.ascii = 128 + 2;
521                         break;
522                     case SDLK_F4:
523                         keyEvent.ascii = 128 + 3;
524                         break;
525                     case SDLK_F5:
526                         keyEvent.ascii = 128 + 4;
527                         break;
528                     case SDLK_F6:
529                         keyEvent.ascii = 128 + 5;
530                         break;
531                     case SDLK_F7:
532                         keyEvent.ascii = 128 + 6;
533                         break;
534                     case SDLK_F8:
535                         keyEvent.ascii = 128 + 7;
536                         break;
537                     case SDLK_F9:
538                         keyEvent.ascii = 128 + 8;
539                         break;
540                     case SDLK_F10:
541                         keyEvent.ascii = 128 + 9;
542                         break;
543                     case SDLK_F11:
544                         keyEvent.ascii = 128 + 10;
545                         break;
546                     case SDLK_F12:
547                         keyEvent.ascii = 128 + 11;
548                         break;
549                     case SDLK_KP_DIVIDE:
550                         keyEvent.ascii = 128 + 12;
551                         break;
552                     case SDLK_KP_MULTIPLY:
553                         keyEvent.ascii = 128 + 13;
554                         break;
555                     case SDLK_KP_MINUS:
556                         keyEvent.ascii = 128 + 14;
557                         break;
558                     case SDLK_KP_PLUS:
559                         keyEvent.ascii = 128 + 15;
560                         break;
561                     case SDLK_KP_ENTER:
562                         keyEvent.ascii = 128 + 16;
563                         break;
564                     case SDLK_KP_DECIMAL:
565                         keyEvent.ascii = 128 + 17;
566                         break;
567                     case SDLK_KP_0:
568                         keyEvent.ascii = 128 + 18;
569                         break;
570                     }
571                 }
572 
573                 Uint16 mod = ev.key.keysym.mod;
574 
575                 if (mod & KMOD_SHIFT)
576                     keyEvent.modifiers |= KB_MOD_SHIFT;
577                 if (mod & KMOD_CTRL)
578                     keyEvent.modifiers |= KB_MOD_CTRL;
579                 if (mod & KMOD_ALT)
580                     keyEvent.modifiers |= KB_MOD_ALT;
581 
582                 if (ev.key.state == SDL_PRESSED) {
583                     if (ev.key.keysym.sym == SDLK_RETURN && mod & KMOD_ALT) {
584                         toggleFullScreen();
585                         break;
586                     }
587 
588                     // handle non-printable or ctrl'd or alt'd keys here
589                     // other cases are handled by text input event below
590                     if (ev.key.keysym.sym < 32 || ev.key.keysym.sym > 126 || (mod & KMOD_CTRL) || (mod & KMOD_ALT)) {
591                         keyEvent.state = KBS_DOWN;
592                         addKBevent(&keyEvent);
593 
594                         sshockKeyStates[c] = keyEvent.modifiers | KB_MOD_PRESSED;
595                     }
596                 } else {
597                     // key up following text input event case below is handled here
598 
599                     keyEvent.state = KBS_UP;
600                     addKBevent(&keyEvent);
601 
602                     sshockKeyStates[c] = 0;
603                 }
604             }
605 
606             // hack to allow pressing shift after move key
607             // sets all current shock states in array to shifted or non-shifted
608             if (ev.key.keysym.sym == SDLK_LSHIFT || ev.key.keysym.sym == SDLK_RSHIFT) {
609                 for (int i = 0; i < 256; i++)
610                     if (sshockKeyStates[i]) {
611                         if (ev.key.state == SDL_PRESSED)
612                             sshockKeyStates[i] |= KB_MOD_SHIFT;
613                         else
614                             sshockKeyStates[i] &= ~KB_MOD_SHIFT;
615                     }
616             }
617         } break;
618 
619         case SDL_TEXTINPUT: {
620             uint32_t len = strlen(ev.text.text);
621 
622             // for every utf8 char in null-terminated string
623             for (uint32_t i = 0; i < len; i++) {
624                 int ch = ev.text.text[i];
625 
626                 // ignore if non-printable key
627                 if (!isprint(ch))
628                     continue;
629 
630                 kbs_event keyEvent = {0};
631 
632                 keyEvent.modifiers = 0;
633 
634                 // if uppercase, lower it and set shift modifier
635                 if (isupper(ch)) {
636                     ch = tolower(ch);
637                     keyEvent.modifiers |= KB_MOD_SHIFT;
638                 }
639 
640                 // get code for this printable ascii key
641                 int c = Ascii2Code[ch - 32];
642 
643                 keyEvent.code = c;
644                 keyEvent.ascii = ch;
645 
646                 // this is a key down event; key up will be handled in event case above
647                 keyEvent.state = KBS_DOWN;
648                 addKBevent(&keyEvent);
649 
650                 sshockKeyStates[c] = keyEvent.modifiers | KB_MOD_PRESSED;
651             }
652         } break;
653 
654         case SDL_MOUSEBUTTONDOWN:
655         case SDL_MOUSEBUTTONUP: {
656             bool down = (ev.button.state == SDL_PRESSED);
657             ss_mouse_event mouseEvent = {0};
658             mouseEvent.type = 0;
659 
660             // TODO: the old mac code used to emulate right mouse clicks if space, enter, or return
661             //       was pressed at the same time - do the same? (=> could check sshockKeyStates[])
662 
663             mouseEvent.buttons = 0;
664 
665             switch (ev.button.button) {
666             case SDL_BUTTON_LEFT:
667                 mouseEvent.type = down ? MOUSE_LDOWN : MOUSE_LUP;
668                 mouseEvent.buttons |= down ? (1 << MOUSE_LBUTTON) : 0;
669                 break;
670 
671             case SDL_BUTTON_RIGHT:
672                 mouseEvent.type = down ? MOUSE_RDOWN : MOUSE_RUP;
673                 mouseEvent.buttons |= down ? (1 << MOUSE_RBUTTON) : 0;
674                 break;
675 
676                 // case SDL_BUTTON_MIDDLE: // TODO: is this MOUSE_CDOWN/UP ?
677                 // break;
678             }
679 
680             if (mouseEvent.type != 0) {
681                 bool shifted = ((SDL_GetModState() & KMOD_SHIFT) != 0);
682 
683                 mouseEvent.x = MouseX;
684                 mouseEvent.y = MouseY;
685                 mouseEvent.timestamp = mouse_get_time();
686                 mouseEvent.modifiers = (shifted ? 1 : 0);
687                 addMouseEvent(&mouseEvent);
688             }
689         } break;
690 
691         case SDL_MOUSEMOTION: {
692             // call this first; it sets MouseX and MouseY
693             if (SDL_GetRelativeMouseMode() == SDL_TRUE)
694                 SetMouseXY(MouseX + ev.motion.xrel, MouseY + ev.motion.yrel);
695             else
696                 SetMouseXY(ev.motion.x, ev.motion.y);
697 
698             ss_mouse_event mouseEvent = {0};
699             mouseEvent.type = MOUSE_MOTION;
700             mouseEvent.x = MouseX;
701             mouseEvent.y = MouseY;
702             mouseEvent.buttons = 0;
703             if (ev.motion.state & SDL_BUTTON_LMASK)
704                 mouseEvent.buttons |= (1 << MOUSE_LBUTTON);
705             if (ev.motion.state & SDL_BUTTON_RMASK)
706                 mouseEvent.buttons |= (1 << MOUSE_RBUTTON);
707             mouseEvent.timestamp = mouse_get_time();
708             addMouseEvent(&mouseEvent);
709 
710             if (TriggerRelMouseMode) {
711                 TriggerRelMouseMode = FALSE;
712 
713                 SDL_SetRelativeMouseMode(SDL_TRUE);
714                 // throw away this first relative mouse reading
715                 int mvelx, mvely;
716                 get_mouselook_vel(&mvelx, &mvely);
717             }
718         } break;
719 
720         case SDL_MOUSEWHEEL:
721             if (ev.wheel.y != 0) {
722                 ss_mouse_event mouseEvent = {0};
723                 mouseEvent.type = ev.wheel.y < 0 ? MOUSE_WHEELDN : MOUSE_WHEELUP;
724                 mouseEvent.x = MouseX;
725                 mouseEvent.y = MouseY;
726                 mouseEvent.buttons = 0;
727                 mouseEvent.timestamp = mouse_get_time();
728                 addMouseEvent(&mouseEvent);
729             }
730             break;
731 
732         case SDL_WINDOWEVENT:
733             switch (ev.window.event) {
734             case SDL_WINDOWEVENT_SIZE_CHANGED:
735                 if (can_use_opengl())
736                     opengl_resize(ev.window.data1, ev.window.data2);
737                 break;
738 
739             case SDL_WINDOWEVENT_MOVED:
740             case SDL_WINDOWEVENT_RESIZED:
741                 break;
742 
743             case SDL_WINDOWEVENT_FOCUS_GAINED:
744                 SDL_SetRelativeMouseMode(saved_rel_mouse);
745                 if (saved_rel_mouse == SDL_TRUE) {
746                     // throw away this first relative mouse reading
747                     int mvelx, mvely;
748                     get_mouselook_vel(&mvelx, &mvely);
749                 }
750                 SDL_ShowCursor(SDL_DISABLE);
751                 break;
752 
753             case SDL_WINDOWEVENT_FOCUS_LOST:
754                 saved_rel_mouse = SDL_GetRelativeMouseMode();
755                 SDL_SetRelativeMouseMode(SDL_FALSE);
756                 SDL_ShowCursor(SDL_ENABLE);
757                 break;
758             }
759             break;
760         }
761     }
762 }
763 
764 //===============================================================
765 //
766 // This section is adapted from:
767 // kbMac.c - All the keyboard handling routines that are specific to the Macintosh.
768 //
769 //===============================================================
770 
771 //------------------
772 //  Globals
773 //------------------
774 int pKbdStatusFlags;
775 
776 //---------------------------------------------------------------
777 //  Startup and keyboard handlers and initialize globals.   Shutdown follows.
778 //---------------------------------------------------------------
kb_startup(void * v)779 int kb_startup(void *v) {
780     pKbdStatusFlags = 0;
781 
782     memset(sshockKeyStates, 0, sizeof(sshockKeyStates));
783     nextKBevent = 0;
784 
785     return (0);
786 }
787 
kb_shutdown(void)788 int kb_shutdown(void) { return (0); }
789 
790 //---------------------------------------------------------------
791 //  Get and set the global flags.
792 //---------------------------------------------------------------
kb_get_flags()793 int kb_get_flags() { return (pKbdStatusFlags); }
794 
kb_set_flags(int flags)795 void kb_set_flags(int flags) { pKbdStatusFlags = flags; }
796 
797 //---------------------------------------------------------------
798 //  Get the next available key from the event queue.
799 //---------------------------------------------------------------
kb_next(void)800 kbs_event kb_next(void) {
801     kbs_event retEvent = kb_look_next();
802     // kb_look_next() doesn't remove events from the queue, this function does,
803     // right here (but only if there actually was an event in the queue, of course):
804     if (nextKBevent > 0) {
805         --nextKBevent;
806         memmove(&kbEvents[0], &kbEvents[1], sizeof(kbs_event) * (kNumKBevents - 1));
807     }
808     return retEvent;
809 
810 #if 0
811 	bool gotKey = FALSE;
812 	EventRecord	theEvent;
813 	while(!gotKey)
814 	{
815 		gotKey = GetOSEvent(keyDownMask | autoKeyMask, &theEvent);		// Get a key
816 		if (gotKey)
817 		{
818 			retEvent.code = (uchar)(theEvent.message >> 8); // keyCodeMask == 0x0000FF00
819 			retEvent.state = KBS_DOWN;
820 			retEvent.ascii = (uchar)(theEvent.message & charCodeMask);
821 			retEvent.modifiers = (uchar)(theEvent.modifiers >> 8);
822 		}
823 		else if ((flags & KBF_BLOCK) == 0)					// If there was no key and we're
824 			return (retEvent);										// not blocking, then return.
825 	}
826 	return (retEvent);
827 #endif
828 }
829 
830 //---------------------------------------------------------------
831 //  See if there is a key waiting in the queue.
832 //---------------------------------------------------------------
kb_look_next(void)833 kbs_event kb_look_next(void) {
834     kbs_event retEvent = {0xFF, 0x00};
835 
836     int flags = kb_get_flags();
837     if (flags & KBF_BLOCK) {
838         while (nextKBevent == 0) {
839             pump_events();
840         }
841     }
842 
843     if (nextKBevent > 0) {
844         retEvent = kbEvents[0];
845     }
846     return retEvent;
847 
848 #if 0
849 	bool				gotKey = FALSE;
850 	EventRecord	theEvent;
851 	while(!gotKey)
852 	{
853 		gotKey = OSEventAvail(keyDownMask | autoKeyMask, &theEvent);		// Get a key
854 		if (gotKey)
855 		{
856 			retEvent.code = (uchar)(theEvent.message >> 8);
857 			retEvent.state = KBS_DOWN;
858 			retEvent.ascii = (uchar)(theEvent.message & charCodeMask);
859 			retEvent.modifiers = (uchar)(theEvent.modifiers >> 8);
860 		}
861 		else if (flags & KBF_BLOCK == 0)					// If there was no key and we're
862 			return (retEvent);										// not blocking, then return.
863 	}
864 	return (retEvent);
865 #endif
866 }
867 
868 //---------------------------------------------------------------
869 //  Flush keyboard events from the event queue.
870 //---------------------------------------------------------------
kb_flush(void)871 void kb_flush(void) {
872     // http://mirror.informatimago.com/next/developer.apple.com/documentation/Carbon/Reference/Event_Manager/event_mgr_ref/function_group_5.html#//apple_ref/c/func/FlushEvents
873     // FlushEvents(keyDownMask | autoKeyMask, 0);
874 
875     SDL_FlushEvents(SDL_KEYDOWN, SDL_KEYUP); // Note: that's a range!
876 
877     nextKBevent = 0; // this flushes the keyboard events already buffered - TODO is that desirable?
878 }
879 
880 //---------------------------------------------------------------
881 //  Return the state of the indicated key (scan code).
882 //---------------------------------------------------------------
883 
kb_state(uchar code)884 uchar kb_state(uchar code) {
885     // see
886     // http://mirror.informatimago.com/next/developer.apple.com/documentation/Carbon/Reference/Event_Manager/event_mgr_ref/function_group_4.html#//apple_ref/c/func/GetKeys
887     // GetKeys((UInt32 *) pKbdGetKeys);
888     // return ((pKbdGetKeys[code>>3] >> (code & 7)) & 1);
889 
890     return sshockKeyStates[code] != 0;
891 }
892 
893 //---------------------------
894 //
895 // MOUSE STUFF
896 //
897 //---------------------------
898 
899 // ---------------------------------------------------------
900 // mouse_next gets the event in the front event queue,
901 // and removes the event from the queue.
902 // res = ptr to event to be filled.
903 //	---------------------------------------------------------
904 //  For Mac version: Get event from the normal Mac event queue for mouse events.
905 //  The events looked for depend on the 'mouseMask' setting.
906 
907 uchar btn_left = FALSE;
908 uchar btn_right = FALSE;
mouse_next(ss_mouse_event * res)909 errtype mouse_next(ss_mouse_event *res) {
910     if (nextMouseEvent <= 0)
911         return ERR_DUNDERFLOW;
912 
913     *res = mouseEvents[0];
914 
915     --nextMouseEvent;
916     memmove(&mouseEvents[0], &mouseEvents[1], sizeof(ss_mouse_event) * (kNumMouseEvents - 1));
917 
918     return OK;
919 }
920 
mouse_flush(void)921 errtype mouse_flush(void) {
922     // FlushEvents(mouseDown | mouseUp, 0);
923     //   Spew(DSRC_MOUSE_Flush,("Entering mouse_flush()\n"));
924     // mouseQueueIn = mouseQueueOut = 0;
925     nextMouseEvent = 0;
926     // TODO: anything else?
927     return OK;
928 }
929 
mouse_get_xy(short * x,short * y)930 errtype mouse_get_xy(short *x, short *y) {
931     *x = MouseX;
932     *y = MouseY;
933 
934     return OK;
935 }
936 
middleize_mouse(void)937 void middleize_mouse(void) {
938     int w, h;
939     SDL_RenderGetLogicalSize(renderer, &w, &h);
940 
941     MouseX = latestMouseEvent.x = w / 2;
942     MouseY = latestMouseEvent.y = h / 2;
943 }
944 
get_mouselook_vel(int * vx,int * vy)945 void get_mouselook_vel(int *vx, int *vy) {
946     if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)
947         *vx = *vy = 0;
948     else {
949         SDL_GetRelativeMouseState(vx, vy);
950 
951         *vx += MouseChaosX;
952         MouseChaosX = 0;
953         *vy += MouseChaosY;
954         MouseChaosY = 0;
955     }
956 }
957 
mouse_put_xy(short x,short y)958 errtype mouse_put_xy(short x, short y) {
959     MouseX = x;
960     MouseY = y;
961 
962     return OK;
963 }
964 
set_mouse_chaos(short dx,short dy)965 void set_mouse_chaos(short dx, short dy) {
966     MouseChaosX = dx;
967     MouseChaosY = dy;
968 }
969 
sdl_mouse_init(void)970 void sdl_mouse_init(void) { nextMouseEvent = 0; }
971