diff options
4 files changed, 67 insertions, 11 deletions
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index d5ed7e3..47bdfac 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -484,8 +484,8 @@ bool BrowserWindowCocoa::HandleKeyboardEventInternal(NSEvent* event) { // Send the event to the menu before sending it to the browser/window // shortcut handling, so that if a user configures cmd-left to mean // "previous tab", it takes precedence over the built-in "history back" - // binding. Other than that, the |redispatchEvent| call would take care of - // invoking the original menu item shortcut as well. + // binding. Other than that, the |-redispatchKeyEvent:| call would take care + // of invoking the original menu item shortcut as well. if ([[NSApp mainMenu] performKeyEquivalent:event]) return true; @@ -500,7 +500,7 @@ bool BrowserWindowCocoa::HandleKeyboardEventInternal(NSEvent* event) { return true; } - return [event_window redispatchEvent:event]; + return [event_window redispatchKeyEvent:event]; } void BrowserWindowCocoa::ShowCreateShortcutsDialog(TabContents* tab_contents) { diff --git a/chrome/browser/cocoa/chrome_event_processing_window.h b/chrome/browser/cocoa/chrome_event_processing_window.h index 0d9cfbb..4159be7 100644 --- a/chrome/browser/cocoa/chrome_event_processing_window.h +++ b/chrome/browser/cocoa/chrome_event_processing_window.h @@ -18,12 +18,13 @@ BOOL eventHandled_; } -// Sends an event to |NSApp sendEvent:|, but also makes sure that it's not +// Sends a key event to |NSApp sendEvent:|, but also makes sure that it's not // short-circuited to the RWHV. This is used to send keyboard events to the menu // and the cmd-` handler if a keyboard event comes back unhandled from the -// renderer. +// renderer. The event must be of type |NSKeyDown|, |NSKeyUp|, or +// |NSFlagsChanged|. // Returns |YES| if |event| has been handled. -- (BOOL)redispatchEvent:(NSEvent*)event; +- (BOOL)redispatchKeyEvent:(NSEvent*)event; // See global_keyboard_shortcuts_mac.h for details on the next two functions. diff --git a/chrome/browser/cocoa/chrome_event_processing_window.mm b/chrome/browser/cocoa/chrome_event_processing_window.mm index 36fea38..c4bee5b 100644 --- a/chrome/browser/cocoa/chrome_event_processing_window.mm +++ b/chrome/browser/cocoa/chrome_event_processing_window.mm @@ -13,6 +13,11 @@ typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar); +@interface ChromeEventProcessingWindow () +// Duplicate the given key event, but changing the associated window. +- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event; +@end + @implementation ChromeEventProcessingWindow - (BOOL)handleExtraKeyboardShortcut:(NSEvent*)event fromTable: @@ -79,9 +84,26 @@ typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar); return [self handleDelayedWindowKeyboardShortcut:event]; } -- (BOOL)redispatchEvent:(NSEvent*)event { +- (BOOL)redispatchKeyEvent:(NSEvent*)event { DCHECK(event); - DCHECK_EQ([event window], self); + NSEventType eventType = [event type]; + if (eventType != NSKeyDown && + eventType != NSKeyUp && + eventType != NSFlagsChanged) { + NOTREACHED(); + return YES; // Pretend it's been handled in an effort to limit damage. + } + + // Ordinarily, the event's window should be this window. However, when + // switching between normal and fullscreen mode, we switch out the window, and + // the event's window might be the previous window (or even an earlier one if + // the renderer is running slowly and several mode switches occur). In this + // rare case, we synthesize a new key event so that its associate window + // (number) is our own. + if ([event window] != self) + event = [self keyEventForWindow:self fromKeyEvent:event]; + + // Redispatch the event. eventHandled_ = YES; redispatchingEvent_ = YES; [NSApp sendEvent:event]; @@ -100,5 +122,38 @@ typedef int (*KeyToCommandMapper)(bool, bool, bool, bool, int, unichar); eventHandled_ = NO; } -@end // ChromeEventProcessingWindow +- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event { + NSEventType eventType = [event type]; + + // Convert the event's location from the original window's coordinates into + // our own. + NSPoint eventLoc = [event locationInWindow]; + eventLoc = [[event window] convertBaseToScreen:eventLoc]; + eventLoc = [self convertScreenToBase:eventLoc]; + + // Various things *only* apply to key down/up. + BOOL eventIsARepeat = NO; + NSString* eventCharacters = nil; + NSString* eventUnmodCharacters = nil; + if (eventType == NSKeyDown || eventType == NSKeyUp) { + eventIsARepeat = [event isARepeat]; + eventCharacters = [event characters]; + eventUnmodCharacters = [event charactersIgnoringModifiers]; + } + + // This synthesis may be slightly imperfect: we provide nil for the context, + // since I (viettrungluu) am sceptical that putting in the original context + // (if one is given) is valid. + return [NSEvent keyEventWithType:eventType + location:eventLoc + modifierFlags:[event modifierFlags] + timestamp:[event timestamp] + windowNumber:[window windowNumber] + context:nil + characters:eventCharacters + charactersIgnoringModifiers:eventUnmodCharacters + isARepeat:eventIsARepeat + keyCode:[event keyCode]]; +} +@end // ChromeEventProcessingWindow diff --git a/chrome/browser/cocoa/html_dialog_window_controller.mm b/chrome/browser/cocoa/html_dialog_window_controller.mm index c07d0c0..9287a1a9 100644 --- a/chrome/browser/cocoa/html_dialog_window_controller.mm +++ b/chrome/browser/cocoa/html_dialog_window_controller.mm @@ -200,8 +200,8 @@ void HtmlDialogWindowDelegateBridge::HandleKeyboardEvent( ChromeEventProcessingWindow* event_window = static_cast<ChromeEventProcessingWindow*>([controller_ window]); - - [event_window redispatchEvent:event.os_event]; + DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]); + [event_window redispatchKeyEvent:event.os_event]; } @implementation HtmlDialogWindowController (InternalAPI) |