summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-21 17:08:55 +0000
committerthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-21 17:08:55 +0000
commit9d61b3b27d9151d0856d42f95a06c82b9dbc1187 (patch)
tree18f7665d2b15d5bd68999563efa16c1e66e979d5 /chrome
parentf1f73abc4122e51c7c3c74f58c9f62d43cdc7171 (diff)
downloadchromium_src-9d61b3b27d9151d0856d42f95a06c82b9dbc1187.zip
chromium_src-9d61b3b27d9151d0856d42f95a06c82b9dbc1187.tar.gz
chromium_src-9d61b3b27d9151d0856d42f95a06c82b9dbc1187.tar.bz2
Forward edit commands to be executed for shortcuts which aren't handled by
javascript. As a result, cocoa keybindings work. The approach: We instantiate a vanilla NSResponder, call interpretKeyEvents on it, and record all of the selectors passed into doCommandBySelector while interpreting the key event. The selectors are converted into edit commands which can be passed to the render process. Caveats: - Shortcuts involving a sequence of key combinations (chords) don't work, because we instantiate a new responder for each event. - We ignore key combinations that don't include a modifier (ctrl, cmd, alt) because this was causing strange behavior (e.g. tab always inserted a tab rather than moving to the next field on the page). BUG=12538 TEST=go to a page with a text field. make sure that ctrl-a moves cursor to beginning of line, ctrl-e goes to the end, ctrl-d deletes to the right, ctrl-h to the left, etc Review URL: http://codereview.chromium.org/209046 Patch from matt@tolton.com. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26694 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.h4
-rw-r--r--chrome/browser/cocoa/rwhvm_editcommand_helper.mm62
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm71
3 files changed, 103 insertions, 34 deletions
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.h b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
index 25a8a73..458b58c 100644
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper.h
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.h
@@ -51,6 +51,10 @@ class RWHVMEditCommandHelper {
bool IsMenuItemEnabled(SEL item_action,
id<RenderWidgetHostViewMacOwner> owner);
+ // Converts an editing selector into a command name that can be sent to
+ // webkit.
+ static NSString* CommandNameForSelector(SEL selector);
+
protected:
// Gets a list of all the selectors that AddEditingSelectorsToClass adds to
// the aforementioned class.
diff --git a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
index c4b1efd..fe02a88 100644
--- a/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
+++ b/chrome/browser/cocoa/rwhvm_editcommand_helper.mm
@@ -105,35 +105,6 @@ const char* kEditCommands[] = {
"yank",
"yankAndSelect"};
-// Maps an objc-selector to a core command name.
-//
-// Returns the core command name (which is the selector name with the trailing
-// ':' stripped in most cases).
-//
-// Adapted from a function by the same name in
-// WebKit/mac/WebView/WebHTMLView.mm .
-// Capitalized names are returned from this function, but that's simply
-// matching WebHTMLView.mm.
-NSString* CommandNameForSelector(SEL selector) {
- if (selector == @selector(insertParagraphSeparator:) ||
- selector == @selector(insertNewlineIgnoringFieldEditor:))
- return @"InsertNewline";
- if (selector == @selector(insertTabIgnoringFieldEditor:))
- return @"InsertTab";
- if (selector == @selector(pageDown:))
- return @"MovePageDown";
- if (selector == @selector(pageDownAndModifySelection:))
- return @"MovePageDownAndModifySelection";
- if (selector == @selector(pageUp:))
- return @"MovePageUp";
- if (selector == @selector(pageUpAndModifySelection:))
- return @"MovePageUpAndModifySelection";
-
- // Remove the trailing colon.
- NSString* selector_str = NSStringFromSelector(selector);
- int selector_len = [selector_str length];
- return [selector_str substringToIndex:selector_len - 1];
-}
// This function is installed via the objc runtime as the implementation of all
// the various editing selectors.
@@ -157,7 +128,8 @@ void EditCommandImp(id self, SEL _cmd, id sender) {
DCHECK([self conformsToProtocol:@protocol(RenderWidgetHostViewMacOwner)]);
// SEL -> command name string.
- NSString* command_name_ns = CommandNameForSelector(_cmd);
+ NSString* command_name_ns =
+ RWHVMEditCommandHelper::CommandNameForSelector(_cmd);
std::string edit_command([command_name_ns UTF8String]);
// Forward the edit command string down the pipeline.
@@ -171,6 +143,36 @@ void EditCommandImp(id self, SEL _cmd, id sender) {
} // namespace
+// Maps an objc-selector to a core command name.
+//
+// Returns the core command name (which is the selector name with the trailing
+// ':' stripped in most cases).
+//
+// Adapted from a function by the same name in
+// WebKit/mac/WebView/WebHTMLView.mm .
+// Capitalized names are returned from this function, but that's simply
+// matching WebHTMLView.mm.
+NSString* RWHVMEditCommandHelper::CommandNameForSelector(SEL selector) {
+ if (selector == @selector(insertParagraphSeparator:) ||
+ selector == @selector(insertNewlineIgnoringFieldEditor:))
+ return @"InsertNewline";
+ if (selector == @selector(insertTabIgnoringFieldEditor:))
+ return @"InsertTab";
+ if (selector == @selector(pageDown:))
+ return @"MovePageDown";
+ if (selector == @selector(pageDownAndModifySelection:))
+ return @"MovePageDownAndModifySelection";
+ if (selector == @selector(pageUp:))
+ return @"MovePageUp";
+ if (selector == @selector(pageUpAndModifySelection:))
+ return @"MovePageUpAndModifySelection";
+
+ // Remove the trailing colon.
+ NSString* selector_str = NSStringFromSelector(selector);
+ int selector_len = [selector_str length];
+ return [selector_str substringToIndex:selector_len - 1];
+}
+
RWHVMEditCommandHelper::RWHVMEditCommandHelper() {
for (size_t i = 0; i < arraysize(kEditCommands); ++i) {
edit_command_set_.insert(kEditCommands[i]);
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index 21fce5f..82145d0 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -5,6 +5,7 @@
#include "chrome/browser/renderer_host/render_widget_host_view_mac.h"
#include "base/histogram.h"
+#include "base/scoped_nsobject.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser_trial.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/spellchecker_platform_engine.h"
#include "chrome/common/native_web_keyboard_event.h"
+#include "chrome/common/edit_command.h"
#include "chrome/common/render_messages.h"
#include "skia/ext/platform_canvas.h"
#include "webkit/api/public/mac/WebInputEventFactory.h"
@@ -430,6 +432,60 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
render_widget_host_->routing_id(), background));
}
+// EditCommandMatcher ---------------------------------------------------------
+
+// This class is used to capture the shortcuts that a given key event maps to.
+// We instantiate a vanilla NSResponder, call interpretKeyEvents on it, and
+// record all of the selectors passed into doCommandBySelector while
+// interpreting the key event. The selectors are converted into edit commands
+// which can be passed to the render process.
+//
+// Caveats:
+// - Shortcuts involving a sequence of key combinations (chords) don't work,
+// because we instantiate a new responder for each event.
+// - We ignore key combinations that don't include a modifier (ctrl, cmd, alt)
+// because this was causing strange behavior (e.g. tab always inserted a tab
+// rather than moving to the next field on the page).
+
+@interface EditCommandMatcher : NSResponder {
+ EditCommands* edit_commands_;
+}
+@end
+
+@implementation EditCommandMatcher
+
+- (id)initWithEditCommands:(EditCommands*)edit_commands {
+ if ((self = [super init]) != nil) {
+ edit_commands_ = edit_commands;
+ }
+ return self;
+}
+
+- (void)doCommandBySelector:(SEL)selector {
+ NSString* editCommand =
+ RWHVMEditCommandHelper::CommandNameForSelector(selector);
+ edit_commands_->push_back(
+ EditCommand(base::SysNSStringToUTF8(editCommand), ""));
+}
+
+- (void)insertText:(id)string {
+ // If we don't ignore this, then sometimes we get a bell.
+}
+
++ (void)matchEditCommands:(EditCommands*)edit_commands
+ forEvent:(NSEvent*)theEvent {
+ if ([theEvent type] != NSKeyDown) return;
+ // Don't interpret plain key presses. This screws up things like <Tab>.
+ NSUInteger flags = [theEvent modifierFlags];
+ flags &= (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask);
+ if (flags == 0) return;
+ scoped_nsobject<EditCommandMatcher> matcher(
+ [[EditCommandMatcher alloc] initWithEditCommands:edit_commands]);
+ [matcher.get() interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+}
+
+@end
+
// RenderWidgetHostViewCocoa ---------------------------------------------------
@implementation RenderWidgetHostViewCocoa
@@ -465,7 +521,7 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
closeOnDeactivate_ = b;
}
-- (void)mouseEvent:(NSEvent *)theEvent {
+- (void)mouseEvent:(NSEvent*)theEvent {
// Don't cancel child popups; killing them on a mouse click would prevent the
// user from positioning the insertion point in the text field spawning the
// popup. A click outside the text field would cause the text field to drop
@@ -478,7 +534,7 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
renderWidgetHostView_->render_widget_host_->ForwardMouseEvent(event);
}
-- (void)keyEvent:(NSEvent *)theEvent {
+- (void)keyEvent:(NSEvent*)theEvent {
// TODO(avi): Possibly kill self? See RenderWidgetHostViewWin::OnKeyEvent and
// http://b/issue?id=1192881 .
@@ -499,8 +555,15 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
event.windowsKeyCode = 0xE5;
// Dispatch this keyboard event to the renderer.
- if (renderWidgetHostView_->render_widget_host_)
- renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event);
+ if (renderWidgetHostView_->render_widget_host_) {
+ RenderWidgetHost* widgetHost = renderWidgetHostView_->render_widget_host_;
+ // Look up shortcut, if any, for this key combination.
+ EditCommands editCommands;
+ [EditCommandMatcher matchEditCommands:&editCommands forEvent:theEvent];
+ if (!editCommands.empty())
+ widgetHost->ForwardEditCommandsForNextKeyEvent(editCommands);
+ widgetHost->ForwardKeyboardEvent(event);
+ }
// Dispatch a NSKeyDown event to an input method.
// To send an onkeydown() event before an onkeypress() event, we should