Browse Source

Steal ChromeEventProcessingWindow from chrome.

Chromium has done quite a lot of low level works for us, steal them to
ease our lives.
Cheng Zhao 12 years ago
parent
commit
3391370857
4 changed files with 142 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 2 0
      atom.gyp
  3. 33 0
      browser/atom_event_processing_window.h
  4. 106 0
      browser/atom_event_processing_window.mm

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 .DS_Store
 build/
 *.xcodeproj
+*.swp

+ 2 - 0
atom.gyp

@@ -13,6 +13,8 @@
       'browser/atom_browser_main_parts.cc',
       'browser/atom_browser_main_parts.h',
       'browser/atom_browser_main_parts_mac.mm',
+      'browser/atom_event_processing_window.h',
+      'browser/atom_event_processing_window.mm',
       'browser/native_window.cc',
       'browser/native_window.h',
       'browser/native_window_mac.h',

+ 33 - 0
browser/atom_event_processing_window.h

@@ -0,0 +1,33 @@
+// Copyright (c) 2013 GitHub, Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
+#define ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/memory/scoped_nsobject.h"
+#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
+
+// Override NSWindow to access unhandled keyboard events (for command
+// processing); subclassing NSWindow is the only method to do
+// this.
+@interface AtomEventProcessingWindow : UnderlayOpenGLHostingWindow {
+ @private
+  BOOL redispatchingEvent_;
+  BOOL eventHandled_;
+}
+
+// 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. The event must be of type |NSKeyDown|, |NSKeyUp|, or
+// |NSFlagsChanged|.
+// Returns |YES| if |event| has been handled.
+- (BOOL)redispatchKeyEvent:(NSEvent*)event;
+
+- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
+@end
+
+#endif  // ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_

+ 106 - 0
browser/atom_event_processing_window.mm

@@ -0,0 +1,106 @@
+// Copyright (c) 2013 GitHub, Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "browser/atom_event_processing_window.h"
+
+#include "base/logging.h"
+#import "content/public/browser/render_widget_host_view_mac_base.h"
+
+@interface AtomEventProcessingWindow ()
+// Duplicate the given key event, but changing the associated window.
+- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event;
+@end
+
+@implementation AtomEventProcessingWindow
+
+- (BOOL)redispatchKeyEvent:(NSEvent*)event {
+  DCHECK(event);
+  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];
+  redispatchingEvent_ = NO;
+
+  // If the event was not handled by [NSApp sendEvent:], the sendEvent:
+  // method below will be called, and because |redispatchingEvent_| is YES,
+  // |eventHandled_| will be set to NO.
+  return eventHandled_;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  if (!redispatchingEvent_)
+    [super sendEvent:event];
+  else
+    eventHandled_ = NO;
+}
+
+- (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]];
+}
+
+
+- (BOOL)performKeyEquivalent:(NSEvent*)event {
+  if (redispatchingEvent_)
+    return NO;
+
+  // Give the web site a chance to handle the event. If it doesn't want to
+  // handle it, it will call us back with one of the |handle*| methods above.
+  NSResponder* r = [self firstResponder];
+  if ([r conformsToProtocol:@protocol(RenderWidgetHostViewMacBase)])
+    return [r performKeyEquivalent:event];
+
+  if ([super performKeyEquivalent:event])
+    return YES;
+
+  return NO;
+}
+
+@end  // AtomEventProcessingWindow