1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #import "content/browser/cocoa/system_hotkey_map.h" 6 7 #pragma mark - NSDictionary Helper Functions 8 9 namespace { 10 11 // All 4 following functions return nil if the object doesn't exist, or isn't of 12 // the right class. 13 id ObjectForKey(NSDictionary* dict, NSString* key, Class aClass) { 14 id object = [dict objectForKey:key]; 15 if (![object isKindOfClass:aClass]) 16 return nil; 17 return object; 18 } 19 20 NSDictionary* DictionaryForKey(NSDictionary* dict, NSString* key) { 21 return ObjectForKey(dict, key, [NSDictionary class]); 22 } 23 24 NSArray* ArrayForKey(NSDictionary* dict, NSString* key) { 25 return ObjectForKey(dict, key, [NSArray class]); 26 } 27 28 NSNumber* NumberForKey(NSDictionary* dict, NSString* key) { 29 return ObjectForKey(dict, key, [NSNumber class]); 30 } 31 32 NSString* StringForKey(NSDictionary* dict, NSString* key) { 33 return ObjectForKey(dict, key, [NSString class]); 34 } 35 36 } // namespace 37 38 #pragma mark - SystemHotkey 39 40 namespace content { 41 42 struct SystemHotkey { 43 unsigned short key_code; 44 NSUInteger modifiers; 45 }; 46 47 #pragma mark - SystemHotkeyMap 48 49 SystemHotkeyMap::SystemHotkeyMap() { 50 } 51 SystemHotkeyMap::~SystemHotkeyMap() { 52 } 53 54 NSDictionary* SystemHotkeyMap::DictionaryFromData(NSData* data) { 55 if (!data) 56 return nil; 57 58 NSError* error = nil; 59 NSPropertyListFormat format; 60 NSDictionary* dictionary = 61 [NSPropertyListSerialization propertyListWithData:data 62 options:0 63 format:&format 64 error:&error]; 65 66 if (![dictionary isKindOfClass:[NSDictionary class]]) 67 return nil; 68 69 return dictionary; 70 } 71 72 bool SystemHotkeyMap::ParseDictionary(NSDictionary* dictionary) { 73 system_hotkeys_.clear(); 74 75 if (!dictionary) 76 return false; 77 78 NSDictionary* hotkey_dictionaries = 79 DictionaryForKey(dictionary, @"AppleSymbolicHotKeys"); 80 if (!hotkey_dictionaries) 81 return false; 82 83 for (NSString* hotkey_system_effect in [hotkey_dictionaries allKeys]) { 84 if (![hotkey_system_effect isKindOfClass:[NSString class]]) 85 continue; 86 87 NSDictionary* hotkey_dictionary = 88 [hotkey_dictionaries objectForKey:hotkey_system_effect]; 89 if (![hotkey_dictionary isKindOfClass:[NSDictionary class]]) 90 continue; 91 92 NSNumber* enabled = NumberForKey(hotkey_dictionary, @"enabled"); 93 if (!enabled || enabled.boolValue == NO) 94 continue; 95 96 NSDictionary* value = DictionaryForKey(hotkey_dictionary, @"value"); 97 if (!value) 98 continue; 99 100 NSString* type = StringForKey(value, @"type"); 101 if (!type || ![type isEqualToString:@"standard"]) 102 continue; 103 104 NSArray* parameters = ArrayForKey(value, @"parameters"); 105 if (!parameters || [parameters count] != 3) 106 continue; 107 108 NSNumber* key_code = [parameters objectAtIndex:1]; 109 if (![key_code isKindOfClass:[NSNumber class]]) 110 continue; 111 112 NSNumber* modifiers = [parameters objectAtIndex:2]; 113 if (![modifiers isKindOfClass:[NSNumber class]]) 114 continue; 115 116 ReserveHotkey(key_code.unsignedShortValue, 117 modifiers.unsignedIntegerValue, 118 hotkey_system_effect); 119 } 120 121 return true; 122 } 123 124 bool SystemHotkeyMap::IsEventReserved(NSEvent* event) const { 125 return IsHotkeyReserved(event.keyCode, event.modifierFlags); 126 } 127 128 bool SystemHotkeyMap::IsHotkeyReserved(unsigned short key_code, 129 NSUInteger modifiers) const { 130 modifiers &= NSDeviceIndependentModifierFlagsMask; 131 std::vector<SystemHotkey>::const_iterator it; 132 for (it = system_hotkeys_.begin(); it != system_hotkeys_.end(); ++it) { 133 if (it->key_code == key_code && it->modifiers == modifiers) 134 return true; 135 } 136 return false; 137 } 138 139 void SystemHotkeyMap::ReserveHotkey(unsigned short key_code, 140 NSUInteger modifiers, 141 NSString* system_effect) { 142 ReserveHotkey(key_code, modifiers); 143 144 // If a hotkey exists for toggling through the windows of an application, then 145 // adding shift to that hotkey toggles through the windows backwards. 146 if ([system_effect isEqualToString:@"27"]) 147 ReserveHotkey(key_code, modifiers | NSShiftKeyMask); 148 } 149 150 void SystemHotkeyMap::ReserveHotkey(unsigned short key_code, 151 NSUInteger modifiers) { 152 // Hotkeys require at least one of control, command, or alternate keys to be 153 // down. 154 NSUInteger required_modifiers = 155 NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask; 156 if ((modifiers & required_modifiers) == 0) 157 return; 158 159 SystemHotkey hotkey; 160 hotkey.key_code = key_code; 161 hotkey.modifiers = modifiers; 162 system_hotkeys_.push_back(hotkey); 163 } 164 165 } // namespace content 166