Atlas - SDL_cocoakeyboard.m

Home / ext / SDL / src / video / cocoa Lines: 1 | Size: 21804 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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(true); 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 <[email protected]>. 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 605
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.