Index: ui/views/cocoa/bridged_content_view.mm |
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm |
index b5ddb05057f64ac07965453a335f8ab73e090259..cc98f89457b87cff82e6ccdcbf968dc32a2f6672 100644 |
--- a/ui/views/cocoa/bridged_content_view.mm |
+++ b/ui/views/cocoa/bridged_content_view.mm |
@@ -65,6 +65,14 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
domCode:(ui::DomCode)domCode |
eventFlags:(int)eventFlags; |
+// Menu action handlers. |
+- (void)undo:(id)sender; |
+- (void)redo:(id)sender; |
+- (void)cut:(id)sender; |
+- (void)copy:(id)sender; |
+- (void)paste:(id)sender; |
+- (void)selectAll:(id)sender; |
+ |
@end |
@implementation BridgedContentView |
@@ -147,8 +155,13 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
return; |
} |
+ ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags); |
+ // If the text input's controller soaks up the event, bail. |
+ if (textInputClient_ && textInputClient_->HandleAsKeyEventOnly(event)) |
+ return; |
+ |
// If there's an active TextInputClient, it ignores the key and processes the |
- // logical editing action. |
+ // logical editing action. Ignores |event|. |
if (commandId && textInputClient_ && |
textInputClient_->IsEditingCommandEnabled(commandId)) { |
textInputClient_->ExecuteEditingCommand(commandId); |
@@ -156,10 +169,62 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
} |
// Otherwise, process the action as a regular key event. |
- ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags); |
hostedView_->GetWidget()->OnKeyEvent(&event); |
} |
+- (void)undo:(id)sender { |
+ // This DCHECK is more strict than a similar check in handleAction:. It can be |
+ // done here because the actors sending these actions should be calling |
+ // validateUserInterfaceItem: before enabling UI that allows these messages to |
+ // be sent. Checking it here would be too late to provide correct UI feedback |
+ // (e.g. there will be no "beep"). |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_UNDO)); |
+ [self handleAction:IDS_APP_UNDO |
+ keyCode:ui::VKEY_Z |
+ domCode:ui::DomCode::KEY_Z |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
+- (void)redo:(id)sender { |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_REDO)); |
+ [self handleAction:IDS_APP_REDO |
+ keyCode:ui::VKEY_Y |
+ domCode:ui::DomCode::KEY_Y |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
+- (void)cut:(id)sender { |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_CUT)); |
+ [self handleAction:IDS_APP_CUT |
+ keyCode:ui::VKEY_X |
+ domCode:ui::DomCode::KEY_X |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
+- (void)copy:(id)sender { |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_COPY)); |
+ [self handleAction:IDS_APP_COPY |
+ keyCode:ui::VKEY_C |
+ domCode:ui::DomCode::KEY_C |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
+- (void)paste:(id)sender { |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_PASTE)); |
+ [self handleAction:IDS_APP_PASTE |
+ keyCode:ui::VKEY_V |
+ domCode:ui::DomCode::KEY_V |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
+- (void)selectAll:(id)sender { |
+ DCHECK(textInputClient_->IsEditingCommandEnabled(IDS_APP_SELECT_ALL)); |
+ [self handleAction:IDS_APP_SELECT_ALL |
+ keyCode:ui::VKEY_A |
+ domCode:ui::DomCode::KEY_A |
+ eventFlags:ui::EF_CONTROL_DOWN]; |
+} |
+ |
// NSView implementation. |
- (BOOL)acceptsFirstResponder { |
@@ -206,7 +271,9 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
- (void)keyDown:(NSEvent*)theEvent { |
// Convert the event into an action message, according to OSX key mappings. |
+ inKeyDown_ = YES; |
[self interpretKeyEvents:@[ theEvent ]]; |
+ inKeyDown_= NO; |
} |
- (void)mouseDown:(NSEvent*)theEvent { |
@@ -485,8 +552,10 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
- (void)doCommandBySelector:(SEL)selector { |
if ([self respondsToSelector:selector]) |
[self performSelector:selector withObject:nil]; |
- else |
+ else { |
+ NSLog(@"Unhandled: %@\n", NSStringFromSelector(selector)); |
[[self nextResponder] doCommandBySelector:selector]; |
+ } |
} |
- (NSRect)firstRectForCharacterRange:(NSRange)range |
@@ -531,7 +600,16 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
return; |
textInputClient_->DeleteRange(gfx::Range(replacementRange)); |
- textInputClient_->InsertText(base::SysNSStringToUTF16(text)); |
+ |
+ // If a single character is inserted by keyDown's call to interpretKeyEvents: |
+ // then use InsertChar() to allow editing events to be merged. Never send the |
+ // key modifier flags to InsertChar since interpretKeyEvents: will filter out |
+ // things that are actually commands, and 'Alt' on Mac actually inserts |
+ // alternate characters (e.g. Alt+S is ß), so shouldn't be ignored. |
+ if (inKeyDown_ && [text length] == 1) |
+ textInputClient_->InsertChar([text characterAtIndex:0], 0); |
+ else |
+ textInputClient_->InsertText(base::SysNSStringToUTF16(text)); |
} |
- (NSRange)markedRange { |
@@ -575,6 +653,33 @@ gfx::Point MovePointToWindow(const NSPoint& point, |
return @[]; |
} |
+// NSUserInterfaceValidations protocol implementation. |
+ |
+- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { |
+ // TODO(tapted): A read-only views::Textfield currently returns null from |
+ // GetTextInputClient(), which means this incorrectly (in)validates menus for |
+ // read-only textfields (e.g. Copy gets disabled). |
+ if (!textInputClient_) |
+ return NO; |
+ |
+ SEL action = [item action]; |
+ |
+ if (action == @selector(undo:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_UNDO); |
+ if (action == @selector(redo:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_REDO); |
+ if (action == @selector(cut:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_CUT); |
+ if (action == @selector(copy:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_COPY); |
+ if (action == @selector(paste:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_PASTE); |
+ if (action == @selector(selectAll:)) |
+ return textInputClient_->IsEditingCommandEnabled(IDS_APP_SELECT_ALL); |
+ |
+ return NO; |
+} |
+ |
// NSAccessibility informal protocol implementation. |
- (id)accessibilityAttributeValue:(NSString*)attribute { |