Home | History | Annotate | Download | only in cocoa
      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