From e4397a1c7389d28cc2e5ac3f5cb54456a8ce8997 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 10 Feb 2022 14:15:21 +0530 Subject: [PATCH] Framework for Apple's default global shortcuts --- glfw/cocoa_init.m | 61 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/glfw/cocoa_init.m b/glfw/cocoa_init.m index f526c21f4..f70a29749 100644 --- a/glfw/cocoa_init.m +++ b/glfw/cocoa_init.m @@ -265,6 +265,7 @@ display_reconfigured(CGDirectDisplayID display UNUSED, CGDisplayChangeSummaryFla } static NSDictionary *global_shortcuts = nil; +static NSDictionary *disabled_global_shortcuts = nil; @interface GLFWHelper : NSObject @end @@ -290,6 +291,10 @@ static NSDictionary *global_shortcuts = nil; [global_shortcuts release]; global_shortcuts = nil; } + if (disabled_global_shortcuts != nil) { + [disabled_global_shortcuts release]; + disabled_global_shortcuts = nil; + } } @end // GLFWHelper @@ -581,6 +586,7 @@ static void build_global_shortcuts_lookup(void) { // dump these in a terminal with: defaults read com.apple.symbolichotkeys NSMutableDictionary *temp = [NSMutableDictionary dictionaryWithCapacity:128]; // will be autoreleased + NSMutableDictionary *temp_disabled = [NSMutableDictionary dictionaryWithCapacity:128]; // will be autoreleased NSDictionary *apple_settings = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@"com.apple.symbolichotkeys"]; if (apple_settings) { NSDictionary *symbolic_hotkeys = [apple_settings objectForKey:@"AppleSymbolicHotKeys"]; @@ -591,7 +597,8 @@ build_global_shortcuts_lookup(void) { NSInteger sc = [key integerValue]; NSDictionary *sc_value = obj; id enabled = [sc_value objectForKey:@"enabled"]; - if (!enabled || ![enabled isKindOfClass:[NSNumber class]] || ![(NSNumber*)enabled boolValue]) continue; + if (!enabled || ![enabled isKindOfClass:[NSNumber class]] ) continue; + id v = [sc_value objectForKey:@"value"]; if (!v || ![v isKindOfClass:[NSDictionary class]]) continue; NSDictionary *value = v; @@ -607,31 +614,32 @@ build_global_shortcuts_lookup(void) { static char buf[64]; #define S(x, k) snprintf(buf, sizeof(buf) - 1, #x":%lx:%ld", (unsigned long)mods, (long)k) if (ch == 0xffff) { if (vk == 0xffff) continue; S(v, vk); } else S(c, ch); - temp[@(buf)] = @(sc); + NSMutableDictionary *dest = ([(NSNumber*)enabled boolValue]) ? temp : temp_disabled; + dest[@(buf)] = @(sc); // the move to next window shortcuts also respond to the same shortcut + shift if (is_shiftable_shortcut([key intValue]) && !(mods & NSEventModifierFlagShift)) { mods |= NSEventModifierFlagShift; if (ch == 0xffff) S(v, vk); else S(c, ch); - temp[@(buf)] = @(sc); + dest[@(buf)] = @(sc); } #undef S } } } global_shortcuts = [[NSDictionary dictionaryWithDictionary:temp] retain]; + disabled_global_shortcuts = [[NSDictionary dictionaryWithDictionary:temp_disabled] retain]; /* NSLog(@"global_shortcuts: %@", global_shortcuts); */ + /* NSLog(@"disabled_global_shortcuts: %@", disabled_global_shortcuts); */ } static int -is_active_apple_global_shortcut(NSEvent *event) { - if (global_shortcuts == nil) build_global_shortcuts_lookup(); +lookup_global_shortcut(NSEvent *event, NSDictionary *global_shortcuts) { NSEventModifierFlags modifierFlags = USEFUL_MODS([event modifierFlags]); static char lookup_key[64]; - #define LOOKUP(t, k) \ snprintf(lookup_key, sizeof(lookup_key) - 1, #t":%lx:%ld", (unsigned long)modifierFlags, (long)k); \ NSNumber *sc = global_shortcuts[@(lookup_key)]; \ - if (sc != nil) return [sc intValue]; + if (sc != nil) return [sc intValue]; \ if ([event.charactersIgnoringModifiers length] == 1) { if (modifierFlags & NSEventModifierFlagShift) { @@ -651,6 +659,44 @@ is_active_apple_global_shortcut(NSEvent *event) { return kSHKUnknown; } +static int +default_global_character_shortcut(uint32_t ch, NSEventModifierFlags mods) { + (void)ch; (void)mods; + return kSHKUnknown; +} + +static int +default_global_vk_shortcut(unsigned short vk, NSEventModifierFlags mods) { + (void)vk; (void)mods; + return kSHKUnknown; +} + + +static int +is_active_apple_global_shortcut(NSEvent *event) { + if (global_shortcuts == nil) build_global_shortcuts_lookup(); + int ans = lookup_global_shortcut(event, global_shortcuts); + if (ans != kSHKUnknown) return ans; + ans = lookup_global_shortcut(event, disabled_global_shortcuts); + if (ans != kSHKUnknown) return kSHKUnknown; // disabled shortcut + // look for known global shortcuts + NSEventModifierFlags modifierFlags = USEFUL_MODS([event modifierFlags]); + if ([event.charactersIgnoringModifiers length] == 1) { + if (modifierFlags & NSEventModifierFlagShift) { + const uint32_t ch_without_shift = vk_to_unicode_key_with_current_layout([event keyCode]); + if (ch_without_shift < GLFW_FKEY_FIRST || ch_without_shift > GLFW_FKEY_LAST) { + ans = default_global_character_shortcut(ch_without_shift, modifierFlags); + if (ans != kSHKUnknown) return ans; + } + const unichar ch = [event.charactersIgnoringModifiers characterAtIndex:0]; + ans = default_global_character_shortcut(ch, modifierFlags); + if (ans != kSHKUnknown) return ans; + } + } + unsigned short vk = [event keyCode]; + return default_global_vk_shortcut(vk, modifierFlags); +} + static bool is_useful_apple_global_shortcut(int sc) { switch(sc) { @@ -944,6 +990,7 @@ void _glfwPlatformTerminate(void) _glfwTerminateNSGL(); if (global_shortcuts != nil) { [global_shortcuts release]; global_shortcuts = nil; } + if (disabled_global_shortcuts != nil) { [disabled_global_shortcuts release]; disabled_global_shortcuts = nil; } } // autoreleasepool }