Index: chrome/browser/cocoa/nsmenuitem_additions.mm |
diff --git a/chrome/browser/cocoa/nsmenuitem_additions.mm b/chrome/browser/cocoa/nsmenuitem_additions.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2a4ccde59cbfc8a6067b96b7abc2e9626adf276d |
--- /dev/null |
+++ b/chrome/browser/cocoa/nsmenuitem_additions.mm |
@@ -0,0 +1,100 @@ |
+#import "chrome/browser/cocoa/nsmenuitem_additions.h" |
+ |
+#include <Carbon/Carbon.h> |
+ |
+#include "base/logging.h" |
+ |
+@implementation NSMenuItem(ChromeAdditions) |
+ |
+- (BOOL)cr_firesForKeyEvent:(NSEvent*)event { |
+ DCHECK([event type] == NSKeyDown); |
+ if (![self isEnabled]) |
+ return NO; |
+ |
+ // In System Preferences->Keyboard->Keyboard Shortcuts, it is possible to add |
+ // arbitrary keyboard shortcuts to applications. It is not documented how this |
+ // works in detail, but |NSMenuItem| has a method |userKeyEquivalent| that |
+ // sounds related. |
+ // However, it looks like |userKeyEquivalent| is equal to |keyEquivalent| when |
+ // a user shortcut is set in system preferences, i.e. Cocoa automatically |
+ // sets/overwrites |keyEquivalent| as well. Hence, this method can ignore |
+ // |userKeyEquivalent| and check |keyEquivalent| only. |
+ |
+ // Menu item key equivalents are nearly all stored without modifiers. The |
+ // exception is shift, which is included in the key and not in the modifiers |
+ // for printable characters (but not for stuff like arrow keys etc). |
+ NSString* eventString = [event charactersIgnoringModifiers]; |
+ NSUInteger eventModifiers = |
+ [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; |
+ |
+ if ([eventString length] == 0 || [[self keyEquivalent] length] == 0) |
+ return NO; |
+ |
+ // Turns out esc never fires unless cmd or ctrl is down. |
+ if ([event keyCode] == kVK_Escape && |
+ (eventModifiers & (NSControlKeyMask | NSCommandKeyMask)) == 0) |
+ return NO; |
+ |
+ // From the |NSMenuItem setKeyEquivalent:| documentation: |
+ // |
+ // If you want to specify the Backspace key as the key equivalent for a menu |
+ // item, use a single character string with NSBackspaceCharacter (defined in |
+ // NSText.h as 0x08) and for the Forward Delete key, use NSDeleteCharacter |
+ // (defined in NSText.h as 0x7F). Note that these are not the same characters |
+ // you get from an NSEvent key-down event when pressing those keys. |
+ if ([[self keyEquivalent] characterAtIndex:0] == NSBackspaceCharacter |
+ && [eventString characterAtIndex:0] == NSDeleteCharacter) { |
+ unichar chr = NSBackspaceCharacter; |
+ eventString = [NSString stringWithCharacters:&chr length:1]; |
+ |
+ // Make sure "shift" is not removed from modifiers below. |
+ eventModifiers |= NSFunctionKeyMask; |
+ } |
+ if ([[self keyEquivalent] characterAtIndex:0] == NSDeleteCharacter && |
+ [eventString characterAtIndex:0] == NSDeleteFunctionKey) { |
+ unichar chr = NSDeleteCharacter; |
+ eventString = [NSString stringWithCharacters:&chr length:1]; |
+ |
+ // Make sure "shift" is not removed from modifiers below. |
+ eventModifiers |= NSFunctionKeyMask; |
+ } |
+ |
+ // cmd-opt-a gives some weird char as characters and "a" as |
+ // charactersWithoutModifiers with an US layout, but an "a" as characters and |
+ // a weird char as "charactersWithoutModifiers" with a cyrillic layout. Oh, |
+ // Cocoa! Instead of getting the current layout from Text Input Services, |
+ // and then requesting the kTISPropertyUnicodeKeyLayoutData and looking in |
+ // there, let's try a pragmatic hack. |
+ if ([eventString characterAtIndex:0] > 0x7f && |
+ [[event characters] length] > 0 && |
+ [[event characters] characterAtIndex:0] <= 0x7f) |
+ eventString = [event characters]; |
+ |
+ // When both |characters| and |charactersIgnoringModifiers| are ascii, we |
+ // want to use |characters| if it's a character and |
+ // |charactersIgnoringModifiers| else (on dvorak, cmd-shift-z should fire |
+ // "cmd-:" instead of "cmd-;", but on dvorak-qwerty, cmd-shift-z should fire |
+ // cmd-shift-z instead of cmd-:). |
+ if ([eventString characterAtIndex:0] <= 0x7f && |
+ [[event characters] length] > 0 && |
+ [[event characters] characterAtIndex:0] <= 0x7f && |
+ isalpha([[event characters] characterAtIndex:0])) |
+ eventString = [event characters]; |
James Su
2009/10/26 03:10:13
Is it possible to make above two if statements eas
Nico
2009/10/26 03:22:14
No, on the dvorak-qwertycmd layout, cmd-z will sen
|
+ |
+ // Clear shift key for printable characters. |
+ if ((eventModifiers & (NSNumericPadKeyMask | NSFunctionKeyMask)) == 0 && |
+ [[self keyEquivalent] characterAtIndex:0] != '\r') |
+ eventModifiers &= ~NSShiftKeyMask; |
+ |
+ // Clear all non-interesting modifiers |
+ eventModifiers &= NSCommandKeyMask | |
+ NSControlKeyMask | |
+ NSAlternateKeyMask | |
+ NSShiftKeyMask; |
+ |
+ return [eventString isEqualToString:[self keyEquivalent]] |
+ && eventModifiers == [self keyEquivalentModifierMask]; |
+} |
+ |
+@end |
+ |