summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m')
-rw-r--r--contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m604
1 files changed, 604 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m
new file mode 100644
index 0000000..e458be9
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m
@@ -0,0 +1,604 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_COCOA
24
25#include "SDL_cocoavideo.h"
26
27#include "../../events/SDL_events_c.h"
28#include "../../events/SDL_keyboard_c.h"
29#include "../../events/scancodes_darwin.h"
30
31#include <Carbon/Carbon.h>
32
33#if 0
34#define DEBUG_IME NSLog
35#else
36#define DEBUG_IME(...)
37#endif
38
39@interface SDL3TranslatorResponder : NSView <NSTextInputClient>
40{
41 NSString *_markedText;
42 NSRange _markedRange;
43 NSRange _selectedRange;
44 SDL_Rect _inputRect;
45 int _pendingRawCode;
46 SDL_Scancode _pendingScancode;
47 Uint64 _pendingTimestamp;
48}
49- (void)doCommandBySelector:(SEL)myselector;
50- (void)setInputRect:(const SDL_Rect *)rect;
51- (void)setPendingKey:(int)rawcode scancode:(SDL_Scancode)scancode timestamp:(Uint64)timestamp;
52- (void)sendPendingKey;
53- (void)clearPendingKey;
54@end
55
56@implementation SDL3TranslatorResponder
57
58- (void)setInputRect:(const SDL_Rect *)rect
59{
60 SDL_copyp(&_inputRect, rect);
61}
62
63- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
64{
65 const char *str;
66
67 DEBUG_IME(@"insertText: %@ replacementRange: (%d, %d)", aString,
68 (int)replacementRange.location, (int)replacementRange.length);
69
70 /* Could be NSString or NSAttributedString, so we have
71 * to test and convert it before return as SDL event */
72 if ([aString isKindOfClass:[NSAttributedString class]]) {
73 str = [[aString string] UTF8String];
74 } else {
75 str = [aString UTF8String];
76 }
77
78 // We're likely sending the composed text, so we reset the IME status.
79 if ([self hasMarkedText]) {
80 [self unmarkText];
81 }
82
83 // Deliver the raw key event that generated this text
84 [self sendPendingKey];
85
86 if ((int)replacementRange.location != -1) {
87 // We're replacing the last character
88 SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_BACKSPACE, true);
89 SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_BACKSPACE, false);
90 }
91
92 SDL_SendKeyboardText(str);
93}
94
95- (void)doCommandBySelector:(SEL)myselector
96{
97 /* No need to do anything since we are not using Cocoa
98 selectors to handle special keys, instead we use SDL
99 key events to do the same job.
100 */
101}
102
103- (BOOL)hasMarkedText
104{
105 return _markedText != nil;
106}
107
108- (NSRange)markedRange
109{
110 return _markedRange;
111}
112
113- (NSRange)selectedRange
114{
115 return _selectedRange;
116}
117
118- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
119{
120 if ([aString isKindOfClass:[NSAttributedString class]]) {
121 aString = [aString string];
122 }
123
124 if ([aString length] == 0) {
125 [self unmarkText];
126 return;
127 }
128
129 if (_markedText != aString) {
130 _markedText = aString;
131 }
132
133 _selectedRange = selectedRange;
134 _markedRange = NSMakeRange(0, [aString length]);
135
136 // This key event was consumed by the IME
137 [self clearPendingKey];
138
139 NSUInteger utf32SelectedRangeLocation = [[aString substringToIndex:selectedRange.location] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
140 NSUInteger utf32SelectionRangeEnd = [[aString substringToIndex:(selectedRange.location + selectedRange.length)] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
141 NSUInteger utf32SelectionRangeLength = utf32SelectionRangeEnd - utf32SelectedRangeLocation;
142
143 SDL_SendEditingText([aString UTF8String],
144 (int)utf32SelectedRangeLocation, (int)utf32SelectionRangeLength);
145
146 DEBUG_IME(@"setMarkedText: %@, (%d, %d) replacement range (%d, %d)", _markedText,
147 (int)selectedRange.location, (int)selectedRange.length,
148 (int)replacementRange.location, (int)replacementRange.length);
149}
150
151- (void)unmarkText
152{
153 _markedText = nil;
154
155 // This key event was consumed by the IME
156 [self clearPendingKey];
157
158 SDL_SendEditingText("", 0, 0);
159}
160
161- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
162{
163 NSWindow *window = [self window];
164 NSRect contentRect = [window contentRectForFrameRect:[window frame]];
165 float windowHeight = contentRect.size.height;
166 NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h,
167 _inputRect.w, _inputRect.h);
168
169 if (actualRange) {
170 *actualRange = aRange;
171 }
172
173 DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@",
174 (int)aRange.location, (int)aRange.length, windowHeight,
175 NSStringFromRect(rect));
176
177 rect = [window convertRectToScreen:rect];
178
179 return rect;
180}
181
182- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
183{
184 DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", (int)aRange.location, (int)aRange.length);
185 return nil;
186}
187
188- (NSInteger)conversationIdentifier
189{
190 return (NSInteger)self;
191}
192
193/* This method returns the index for character that is
194 * nearest to thePoint. thPoint is in screen coordinate system.
195 */
196- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
197{
198 DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y);
199 return 0;
200}
201
202/* This method is the key to attribute extension.
203 * We could add new attributes through this method.
204 * NSInputServer examines the return value of this
205 * method & constructs appropriate attributed string.
206 */
207- (NSArray *)validAttributesForMarkedText
208{
209 return [NSArray array];
210}
211
212- (void)setPendingKey:(int)rawcode scancode:(SDL_Scancode)scancode timestamp:(Uint64)timestamp
213{
214 _pendingRawCode = rawcode;
215 _pendingScancode = scancode;
216 _pendingTimestamp = timestamp;
217}
218
219- (void)sendPendingKey
220{
221 if (_pendingRawCode < 0) {
222 return;
223 }
224
225 SDL_SendKeyboardKey(_pendingTimestamp, SDL_DEFAULT_KEYBOARD_ID, _pendingRawCode, _pendingScancode, true);
226 [self clearPendingKey];
227}
228
229- (void)clearPendingKey
230{
231 _pendingRawCode = -1;
232}
233
234@end
235
236static bool IsModifierKeyPressed(unsigned int flags,
237 unsigned int target_mask,
238 unsigned int other_mask,
239 unsigned int either_mask)
240{
241 bool target_pressed = (flags & target_mask) != 0;
242 bool other_pressed = (flags & other_mask) != 0;
243 bool either_pressed = (flags & either_mask) != 0;
244
245 if (either_pressed != (target_pressed || other_pressed))
246 return either_pressed;
247
248 return target_pressed;
249}
250
251static void HandleModifiers(SDL_VideoDevice *_this, SDL_Scancode code, unsigned int modifierFlags)
252{
253 bool pressed = false;
254
255 if (code == SDL_SCANCODE_LSHIFT) {
256 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELSHIFTKEYMASK,
257 NX_DEVICERSHIFTKEYMASK, NX_SHIFTMASK);
258 } else if (code == SDL_SCANCODE_LCTRL) {
259 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCTLKEYMASK,
260 NX_DEVICERCTLKEYMASK, NX_CONTROLMASK);
261 } else if (code == SDL_SCANCODE_LALT) {
262 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELALTKEYMASK,
263 NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK);
264 } else if (code == SDL_SCANCODE_LGUI) {
265 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCMDKEYMASK,
266 NX_DEVICERCMDKEYMASK, NX_COMMANDMASK);
267 } else if (code == SDL_SCANCODE_RSHIFT) {
268 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERSHIFTKEYMASK,
269 NX_DEVICELSHIFTKEYMASK, NX_SHIFTMASK);
270 } else if (code == SDL_SCANCODE_RCTRL) {
271 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCTLKEYMASK,
272 NX_DEVICELCTLKEYMASK, NX_CONTROLMASK);
273 } else if (code == SDL_SCANCODE_RALT) {
274 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERALTKEYMASK,
275 NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK);
276 } else if (code == SDL_SCANCODE_RGUI) {
277 pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCMDKEYMASK,
278 NX_DEVICELCMDKEYMASK, NX_COMMANDMASK);
279 } else {
280 return;
281 }
282
283 if (pressed) {
284 SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, code, true);
285 } else {
286 SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, code, false);
287 }
288}
289
290static void UpdateKeymap(SDL_CocoaVideoData *data, bool send_event)
291{
292 TISInputSourceRef key_layout;
293 UCKeyboardLayout *keyLayoutPtr = NULL;
294 CFDataRef uchrDataRef;
295
296 // See if the keymap needs to be updated
297 key_layout = TISCopyCurrentKeyboardLayoutInputSource();
298 if (key_layout == data.key_layout) {
299 return;
300 }
301 data.key_layout = key_layout;
302
303 // Try Unicode data first
304 uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
305 if (uchrDataRef) {
306 keyLayoutPtr = (UCKeyboardLayout *)CFDataGetBytePtr(uchrDataRef);
307 }
308
309 if (!keyLayoutPtr) {
310 CFRelease(key_layout);
311 return;
312 }
313
314 static struct {
315 int flags;
316 SDL_Keymod modstate;
317 } mods[] = {
318 { 0, SDL_KMOD_NONE },
319 { shiftKey, SDL_KMOD_SHIFT },
320 { alphaLock, SDL_KMOD_CAPS },
321 { (shiftKey | alphaLock), (SDL_KMOD_SHIFT | SDL_KMOD_CAPS) },
322 { optionKey, SDL_KMOD_ALT },
323 { (optionKey | shiftKey), (SDL_KMOD_ALT | SDL_KMOD_SHIFT) },
324 { (optionKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_CAPS) },
325 { (optionKey | shiftKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_SHIFT | SDL_KMOD_CAPS) }
326 };
327
328 UInt32 keyboard_type = LMGetKbdType();
329
330 SDL_Keymap *keymap = SDL_CreateKeymap();
331 for (int m = 0; m < SDL_arraysize(mods); ++m) {
332 for (int i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
333 OSStatus err;
334 UniChar s[8];
335 UniCharCount len;
336 UInt32 dead_key_state;
337
338 // Make sure this scancode is a valid character scancode
339 SDL_Scancode scancode = darwin_scancode_table[i];
340 if (scancode == SDL_SCANCODE_UNKNOWN ||
341 scancode == SDL_SCANCODE_DELETE ||
342 (SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) {
343 continue;
344 }
345
346 /*
347 * Swap the scancode for these two wrongly translated keys
348 * UCKeyTranslate() function does not do its job properly for ISO layout keyboards, where the key '@',
349 * which is located in the top left corner of the keyboard right under the Escape key, and the additional
350 * key '<', which is on the right of the Shift key, are inverted
351 */
352 if ((scancode == SDL_SCANCODE_NONUSBACKSLASH || scancode == SDL_SCANCODE_GRAVE) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
353 // see comments in scancodes_darwin.h
354 scancode = (SDL_Scancode)((SDL_SCANCODE_NONUSBACKSLASH + SDL_SCANCODE_GRAVE) - scancode);
355 }
356
357 dead_key_state = 0;
358 err = UCKeyTranslate(keyLayoutPtr, i, kUCKeyActionDown,
359 ((mods[m].flags >> 8) & 0xFF), keyboard_type,
360 kUCKeyTranslateNoDeadKeysMask,
361 &dead_key_state, 8, &len, s);
362 if (err != noErr) {
363 continue;
364 }
365
366 if (len > 0 && s[0] != 0x10) {
367 SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, s[0]);
368 } else {
369 // The default keymap doesn't have any SDL_KMOD_ALT entries, so we don't need to override them
370 if (!(mods[m].modstate & SDL_KMOD_ALT)) {
371 SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, SDLK_UNKNOWN);
372 }
373 }
374 }
375 }
376 SDL_SetKeymap(keymap, send_event);
377}
378
379static void SDLCALL SDL_MacOptionAsAltChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
380{
381 SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata;
382 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
383
384 if (hint && *hint) {
385 if (SDL_strcmp(hint, "none") == 0) {
386 data.option_as_alt = OptionAsAltNone;
387 } else if (SDL_strcmp(hint, "only_left") == 0) {
388 data.option_as_alt = OptionAsAltOnlyLeft;
389 } else if (SDL_strcmp(hint, "only_right") == 0) {
390 data.option_as_alt = OptionAsAltOnlyRight;
391 } else if (SDL_strcmp(hint, "both") == 0) {
392 data.option_as_alt = OptionAsAltBoth;
393 }
394 } else {
395 data.option_as_alt = OptionAsAltNone;
396 }
397}
398
399void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
400{
401 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
402
403 UpdateKeymap(data, false);
404
405 // Set our own names for the platform-dependent but layout-independent keys
406 // This key is NumLock on the MacBook keyboard. :)
407 // SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");
408 SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
409 SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
410 SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
411 SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
412
413 data.modifierFlags = (unsigned int)[NSEvent modifierFlags];
414 SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? true : false);
415
416 SDL_AddHintCallback(SDL_HINT_MAC_OPTION_AS_ALT, SDL_MacOptionAsAltChanged, _this);
417}
418
419bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
420{
421 @autoreleasepool {
422 NSView *parentView;
423 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
424 NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow;
425
426 parentView = [nswindow contentView];
427
428 /* We only keep one field editor per process, since only the front most
429 * window can receive text input events, so it make no sense to keep more
430 * than one copy. When we switched to another window and requesting for
431 * text input, simply remove the field editor from its superview then add
432 * it to the front most window's content view */
433 if (!data.fieldEdit) {
434 data.fieldEdit = [[SDL3TranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)];
435 }
436
437 if (![[data.fieldEdit superview] isEqual:parentView]) {
438 // DEBUG_IME(@"add fieldEdit to window contentView");
439 [data.fieldEdit removeFromSuperview];
440 [parentView addSubview:data.fieldEdit];
441 [nswindow makeFirstResponder:data.fieldEdit];
442 }
443 }
444 return Cocoa_UpdateTextInputArea(_this, window);
445}
446
447bool Cocoa_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
448{
449 @autoreleasepool {
450 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
451
452 if (data && data.fieldEdit) {
453 [data.fieldEdit removeFromSuperview];
454 data.fieldEdit = nil;
455 }
456 }
457 return true;
458}
459
460bool Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
461{
462 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
463 if (data.fieldEdit) {
464 [data.fieldEdit setInputRect:&window->text_input_rect];
465 }
466 return true;
467}
468
469static NSEvent *ReplaceEvent(NSEvent *event, OptionAsAlt option_as_alt)
470{
471 if (option_as_alt == OptionAsAltNone) {
472 return event;
473 }
474
475 const unsigned int modflags = (unsigned int)[event modifierFlags];
476
477 bool ignore_alt_characters = false;
478
479 bool lalt_pressed = IsModifierKeyPressed(modflags, NX_DEVICELALTKEYMASK,
480 NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK);
481 bool ralt_pressed = IsModifierKeyPressed(modflags, NX_DEVICERALTKEYMASK,
482 NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK);
483
484 if (option_as_alt == OptionAsAltOnlyLeft && lalt_pressed) {
485 ignore_alt_characters = true;
486 } else if (option_as_alt == OptionAsAltOnlyRight && ralt_pressed) {
487 ignore_alt_characters = true;
488 } else if (option_as_alt == OptionAsAltBoth && (lalt_pressed || ralt_pressed)) {
489 ignore_alt_characters = true;
490 }
491
492 bool cmd_pressed = modflags & NX_COMMANDMASK;
493 bool ctrl_pressed = modflags & NX_CONTROLMASK;
494
495 ignore_alt_characters = ignore_alt_characters && !cmd_pressed && !ctrl_pressed;
496
497 if (ignore_alt_characters) {
498 NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
499 return [NSEvent keyEventWithType:[event type]
500 location:[event locationInWindow]
501 modifierFlags:modflags
502 timestamp:[event timestamp]
503 windowNumber:[event windowNumber]
504 context:nil
505 characters:charactersIgnoringModifiers
506 charactersIgnoringModifiers:charactersIgnoringModifiers
507 isARepeat:[event isARepeat]
508 keyCode:[event keyCode]];
509 }
510
511 return event;
512}
513
514void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event)
515{
516 unsigned short scancode;
517 SDL_Scancode code;
518 SDL_CocoaVideoData *data = _this ? ((__bridge SDL_CocoaVideoData *)_this->internal) : nil;
519 if (!data) {
520 return; // can happen when returning from fullscreen Space on shutdown
521 }
522
523 if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp) {
524 event = ReplaceEvent(event, data.option_as_alt);
525 }
526
527 scancode = [event keyCode];
528
529 if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
530 // see comments in scancodes_darwin.h
531 scancode = 60 - scancode;
532 }
533
534 if (scancode < SDL_arraysize(darwin_scancode_table)) {
535 code = darwin_scancode_table[scancode];
536 } else {
537 // Hmm, does this ever happen? If so, need to extend the keymap...
538 code = SDL_SCANCODE_UNKNOWN;
539 }
540
541 switch ([event type]) {
542 case NSEventTypeKeyDown:
543 if (![event isARepeat]) {
544 // See if we need to rebuild the keyboard layout
545 UpdateKeymap(data, true);
546 }
547
548#ifdef DEBUG_SCANCODES
549 if (code == SDL_SCANCODE_UNKNOWN) {
550 SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list <https://discourse.libsdl.org/> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.", scancode);
551 }
552#endif
553 if (SDL_TextInputActive(SDL_GetKeyboardFocus())) {
554 [data.fieldEdit setPendingKey:scancode scancode:code timestamp:Cocoa_GetEventTimestamp([event timestamp])];
555 [data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
556 [data.fieldEdit sendPendingKey];
557 } else if (SDL_GetKeyboardFocus()) {
558 SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_DEFAULT_KEYBOARD_ID, scancode, code, true);
559 }
560 break;
561 case NSEventTypeKeyUp:
562 SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_DEFAULT_KEYBOARD_ID, scancode, code, false);
563 break;
564 case NSEventTypeFlagsChanged: {
565 // see if the new modifierFlags mean any existing keys should be pressed/released...
566 const unsigned int modflags = (unsigned int)[event modifierFlags];
567 HandleModifiers(_this, SDL_SCANCODE_LSHIFT, modflags);
568 HandleModifiers(_this, SDL_SCANCODE_LCTRL, modflags);
569 HandleModifiers(_this, SDL_SCANCODE_LALT, modflags);
570 HandleModifiers(_this, SDL_SCANCODE_LGUI, modflags);
571 HandleModifiers(_this, SDL_SCANCODE_RSHIFT, modflags);
572 HandleModifiers(_this, SDL_SCANCODE_RCTRL, modflags);
573 HandleModifiers(_this, SDL_SCANCODE_RALT, modflags);
574 HandleModifiers(_this, SDL_SCANCODE_RGUI, modflags);
575 break;
576 }
577 default: // just to avoid compiler warnings
578 break;
579 }
580}
581
582void Cocoa_QuitKeyboard(SDL_VideoDevice *_this)
583{
584}
585
586typedef int CGSConnection;
587typedef enum
588{
589 CGSGlobalHotKeyEnable = 0,
590 CGSGlobalHotKeyDisable = 1,
591} CGSGlobalHotKeyOperatingMode;
592
593extern CGSConnection _CGSDefaultConnection(void);
594extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode);
595
596bool Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed)
597{
598#ifdef SDL_MAC_NO_SANDBOX
599 CGSSetGlobalHotKeyOperatingMode(_CGSDefaultConnection(), grabbed ? CGSGlobalHotKeyDisable : CGSGlobalHotKeyEnable);
600#endif
601 return true;
602}
603
604#endif // SDL_VIDEO_DRIVER_COCOA