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