Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: ui/views/cocoa/bridged_content_view.mm

Issue 2096363002: MacViews: Fix text input for password textfields. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@password_text_fix
Patch Set: Rebase. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | ui/views/controls/textfield/textfield_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ui/views/cocoa/bridged_content_view.h" 5 #import "ui/views/cocoa/bridged_content_view.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #import "base/mac/mac_util.h" 8 #import "base/mac/mac_util.h"
9 #import "base/mac/scoped_nsobject.h" 9 #import "base/mac/scoped_nsobject.h"
10 #include "base/strings/sys_string_conversions.h" 10 #include "base/strings/sys_string_conversions.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 : point; 63 : point;
64 64
65 NSPoint point_in_window = 65 NSPoint point_in_window =
66 ui::ConvertPointFromScreenToWindow(target_window, point_in_screen); 66 ui::ConvertPointFromScreenToWindow(target_window, point_in_screen);
67 NSRect content_rect = 67 NSRect content_rect =
68 [target_window contentRectForFrameRect:[target_window frame]]; 68 [target_window contentRectForFrameRect:[target_window frame]];
69 return gfx::Point(point_in_window.x, 69 return gfx::Point(point_in_window.x,
70 NSHeight(content_rect) - point_in_window.y); 70 NSHeight(content_rect) - point_in_window.y);
71 } 71 }
72 72
73 // Checks if there's an active MenuController during key event dispatch. If 73 // Dispatch |event| to |menu_controller| and return true if |event| is
74 // there is one, it gets preference, and it will likely swallow the event. 74 // swallowed.
75 bool DispatchEventToMenu(views::Widget* widget, ui::KeyEvent* event) { 75 bool DispatchEventToMenu(MenuController* menu_controller, ui::KeyEvent* event) {
76 MenuController* menuController = MenuController::GetActiveInstance(); 76 return menu_controller &&
77 if (menuController && menuController->owner() == widget) { 77 menu_controller->OnWillDispatchKeyEvent(event) ==
78 if (menuController->OnWillDispatchKeyEvent(event) == ui::POST_DISPATCH_NONE) 78 ui::POST_DISPATCH_NONE;
79 return true;
80 }
81 return false;
82 } 79 }
83 80
84 // Returns true if |client| has RTL text. 81 // Returns true if |client| has RTL text.
85 bool IsTextRTL(const ui::TextInputClient* client) { 82 bool IsTextRTL(const ui::TextInputClient* client) {
86 return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT; 83 return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
87 } 84 }
88 85
89 // Returns the boundary rectangle for composition characters in the 86 // Returns the boundary rectangle for composition characters in the
90 // |requested_range|. Sets |actual_range| corresponding to the returned 87 // |requested_range|. Sets |actual_range| corresponding to the returned
91 // rectangle. For cases, where there is no composition text or the 88 // rectangle. For cases, where there is no composition text or the
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 // send ui::EF_NONE as the key modifier to the KeyEvent constructor. 204 // send ui::EF_NONE as the key modifier to the KeyEvent constructor.
208 // E.g. For Alt+S, [NSEvent characters] is 'ß' and not 'S'. 205 // E.g. For Alt+S, [NSEvent characters] is 'ß' and not 'S'.
209 return ui::KeyEvent([[event characters] characterAtIndex:0], 206 return ui::KeyEvent([[event characters] characterAtIndex:0],
210 ui::KeyboardCodeFromNSEvent(event), ui::EF_NONE); 207 ui::KeyboardCodeFromNSEvent(event), ui::EF_NONE);
211 } 208 }
212 209
213 } // namespace 210 } // namespace
214 211
215 @interface BridgedContentView () 212 @interface BridgedContentView ()
216 213
214 // Returns the active menu controller corresponding to |hostedView_|,
215 // nil otherwise.
216 - (MenuController*)activeMenuController;
217
217 // Passes |event| to the InputMethod for dispatch. 218 // Passes |event| to the InputMethod for dispatch.
218 - (void)handleKeyEvent:(ui::KeyEvent*)event; 219 - (void)handleKeyEvent:(ui::KeyEvent*)event;
219 220
220 // Handles an NSResponder Action Message by mapping it to a corresponding text 221 // Handles an NSResponder Action Message by mapping it to a corresponding text
221 // editing command from ui_strings.grd and, when not being sent to a 222 // editing command from ui_strings.grd and, when not being sent to a
222 // TextInputClient, the keyCode that toolkit-views expects internally. 223 // TextInputClient, the keyCode that toolkit-views expects internally.
223 // For example, moveToLeftEndOfLine: would pass ui::VKEY_HOME in non-RTL locales 224 // For example, moveToLeftEndOfLine: would pass ui::VKEY_HOME in non-RTL locales
224 // even though the Home key on Mac defaults to moveToBeginningOfDocument:. 225 // even though the Home key on Mac defaults to moveToBeginningOfDocument:.
225 // This approach also allows action messages a user 226 // This approach also allows action messages a user
226 // may have remapped in ~/Library/KeyBindings/DefaultKeyBinding.dict to be 227 // may have remapped in ~/Library/KeyBindings/DefaultKeyBinding.dict to be
227 // catered for. 228 // catered for.
228 // Note: default key bindings in Mac can be read from StandardKeyBinding.dict 229 // Note: default key bindings in Mac can be read from StandardKeyBinding.dict
229 // which lives in /System/Library/Frameworks/AppKit.framework/Resources. Do 230 // which lives in /System/Library/Frameworks/AppKit.framework/Resources. Do
230 // `plutil -convert xml1 -o StandardKeyBinding.xml StandardKeyBinding.dict` to 231 // `plutil -convert xml1 -o StandardKeyBinding.xml StandardKeyBinding.dict` to
231 // get something readable. 232 // get something readable.
232 - (void)handleAction:(ui::TextEditCommand)command 233 - (void)handleAction:(ui::TextEditCommand)command
233 keyCode:(ui::KeyboardCode)keyCode 234 keyCode:(ui::KeyboardCode)keyCode
234 domCode:(ui::DomCode)domCode 235 domCode:(ui::DomCode)domCode
235 eventFlags:(int)eventFlags; 236 eventFlags:(int)eventFlags;
236 237
237 // Notification handler invoked when the Full Keyboard Access mode is changed. 238 // Notification handler invoked when the Full Keyboard Access mode is changed.
238 - (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification; 239 - (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification;
239 240
241 // Helper method which forwards |text| to the active menu or |textInputClient_|.
242 - (void)insertTextInternal:(id)text;
243
240 // Returns the native Widget's drag drop client. Possibly null. 244 // Returns the native Widget's drag drop client. Possibly null.
241 - (views::DragDropClientMac*)dragDropClient; 245 - (views::DragDropClientMac*)dragDropClient;
242 246
243 // Menu action handlers. 247 // Menu action handlers.
244 - (void)undo:(id)sender; 248 - (void)undo:(id)sender;
245 - (void)redo:(id)sender; 249 - (void)redo:(id)sender;
246 - (void)cut:(id)sender; 250 - (void)cut:(id)sender;
247 - (void)copy:(id)sender; 251 - (void)copy:(id)sender;
248 - (void)paste:(id)sender; 252 - (void)paste:(id)sender;
249 - (void)selectAll:(id)sender; 253 - (void)selectAll:(id)sender;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 return; 371 return;
368 372
369 views::FocusManager* focusManager = 373 views::FocusManager* focusManager =
370 hostedView_->GetWidget()->GetFocusManager(); 374 hostedView_->GetWidget()->GetFocusManager();
371 if (focusManager) 375 if (focusManager)
372 focusManager->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]); 376 focusManager->SetKeyboardAccessible([NSApp isFullKeyboardAccessEnabled]);
373 } 377 }
374 378
375 // BridgedContentView private implementation. 379 // BridgedContentView private implementation.
376 380
381 - (MenuController*)activeMenuController {
382 MenuController* menuController = MenuController::GetActiveInstance();
383 return menuController && menuController->owner() == hostedView_->GetWidget()
384 ? menuController
385 : nullptr;
386 }
387
377 - (void)handleKeyEvent:(ui::KeyEvent*)event { 388 - (void)handleKeyEvent:(ui::KeyEvent*)event {
378 if (!hostedView_) 389 if (!hostedView_)
379 return; 390 return;
380 391
381 DCHECK(event); 392 DCHECK(event);
382 if (DispatchEventToMenu(hostedView_->GetWidget(), event)) 393 if (DispatchEventToMenu([self activeMenuController], event))
383 return; 394 return;
384 395
385 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event); 396 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event);
386 } 397 }
387 398
388 - (void)handleAction:(ui::TextEditCommand)command 399 - (void)handleAction:(ui::TextEditCommand)command
389 keyCode:(ui::KeyboardCode)keyCode 400 keyCode:(ui::KeyboardCode)keyCode
390 domCode:(ui::DomCode)domCode 401 domCode:(ui::DomCode)domCode
391 eventFlags:(int)eventFlags { 402 eventFlags:(int)eventFlags {
392 if (!hostedView_) 403 if (!hostedView_)
393 return; 404 return;
394 405
395 // Generate a synthetic event with the keycode toolkit-views expects. 406 // Generate a synthetic event with the keycode toolkit-views expects.
396 ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags); 407 ui::KeyEvent event(ui::ET_KEY_PRESSED, keyCode, domCode, eventFlags);
397 408
398 if (DispatchEventToMenu(hostedView_->GetWidget(), &event)) 409 if (DispatchEventToMenu([self activeMenuController], &event))
399 return; 410 return;
400 411
401 // If there's an active TextInputClient, schedule the editing command to be 412 // If there's an active TextInputClient, schedule the editing command to be
402 // performed. 413 // performed.
403 if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command)) 414 if (textInputClient_ && textInputClient_->IsTextEditCommandEnabled(command))
404 textInputClient_->SetTextEditCommandForNextKeyEvent(command); 415 textInputClient_->SetTextEditCommandForNextKeyEvent(command);
405 416
406 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event); 417 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(&event);
407 } 418 }
408 419
409 - (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification { 420 - (void)onFullKeyboardAccessModeChanged:(NSNotification*)notification {
410 DCHECK([[notification name] 421 DCHECK([[notification name]
411 isEqualToString:kFullKeyboardAccessChangedNotification]); 422 isEqualToString:kFullKeyboardAccessChangedNotification]);
412 [self updateFullKeyboardAccess]; 423 [self updateFullKeyboardAccess];
413 } 424 }
414 425
426 - (void)insertTextInternal:(id)text {
427 if (!hostedView_)
428 return;
429
430 if ([text isKindOfClass:[NSAttributedString class]])
431 text = [text string];
432
433 bool isCharacterEvent = keyDownEvent_ && [text length] == 1;
434
435 // Forward the |text| to |textInputClient_| if no menu is active.
436 if (textInputClient_ && ![self activeMenuController]) {
437 // If a single character is inserted by keyDown's call to
438 // interpretKeyEvents: then use InsertChar() to allow editing events to be
439 // merged.
440 if (isCharacterEvent)
441 textInputClient_->InsertChar(GetCharacterEventFromNSEvent(keyDownEvent_));
442 else
443 textInputClient_->InsertText(base::SysNSStringToUTF16(text));
444 return;
445 }
446
447 // Only handle the case where no. of characters is 1. Cases not handled (not
448 // an exhaustive list):
449 // - |text| contains a unicode surrogate pair, i.e. a single grapheme which
450 // requires two 16 bit characters. Currently Views menu only supports
451 // mnemonics using a single 16 bit character, so it is ok to ignore this
452 // case.
453 // - Programmatically created events.
454 // - Input from IME. But this case should not occur since inputContext is
455 // nil.
456 if (isCharacterEvent) {
457 ui::KeyEvent charEvent = GetCharacterEventFromNSEvent(keyDownEvent_);
458 [self handleKeyEvent:&charEvent];
459 }
460 }
461
415 - (views::DragDropClientMac*)dragDropClient { 462 - (views::DragDropClientMac*)dragDropClient {
416 views::BridgedNativeWidget* bridge = 463 views::BridgedNativeWidget* bridge =
417 views::NativeWidgetMac::GetBridgeForNativeWindow([self window]); 464 views::NativeWidgetMac::GetBridgeForNativeWindow([self window]);
418 return bridge ? bridge->drag_drop_client() : nullptr; 465 return bridge ? bridge->drag_drop_client() : nullptr;
419 } 466 }
420 467
421 - (void)undo:(id)sender { 468 - (void)undo:(id)sender {
422 // This DCHECK is more strict than a similar check in handleAction:. It can be 469 // This DCHECK is more strict than a similar check in handleAction:. It can be
423 // done here because the actors sending these actions should be calling 470 // done here because the actors sending these actions should be calling
424 // validateUserInterfaceItem: before enabling UI that allows these messages to 471 // validateUserInterfaceItem: before enabling UI that allows these messages to
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 674
628 - (NSTextInputContext*)inputContext { 675 - (NSTextInputContext*)inputContext {
629 // If the textInputClient_ does not exist, return nil since this view does not 676 // If the textInputClient_ does not exist, return nil since this view does not
630 // conform to NSTextInputClient protocol. 677 // conform to NSTextInputClient protocol.
631 if (!textInputClient_) 678 if (!textInputClient_)
632 return nil; 679 return nil;
633 680
634 // If a menu is active, and -[NSView interpretKeyEvents:] asks for the 681 // If a menu is active, and -[NSView interpretKeyEvents:] asks for the
635 // input context, return nil. This ensures the action message is sent to 682 // input context, return nil. This ensures the action message is sent to
636 // the view, rather than any NSTextInputClient a subview has installed. 683 // the view, rather than any NSTextInputClient a subview has installed.
637 MenuController* menuController = MenuController::GetActiveInstance(); 684 if ([self activeMenuController])
638 if (menuController && menuController->owner() == hostedView_->GetWidget())
639 return nil; 685 return nil;
640 686
641 // When not in an editable mode, or while entering passwords 687 // When not in an editable mode, or while entering passwords
642 // (http://crbug.com/23219), we don't want to show IME candidate windows. 688 // (http://crbug.com/23219), we don't want to show IME candidate windows.
643 // Returning nil prevents this view from getting messages defined as part of 689 // Returning nil prevents this view from getting messages defined as part of
644 // the NSTextInputClient protocol. 690 // the NSTextInputClient protocol.
645 switch (textInputClient_->GetTextInputType()) { 691 switch (textInputClient_->GetTextInputType()) {
646 case ui::TEXT_INPUT_TYPE_NONE: 692 case ui::TEXT_INPUT_TYPE_NONE:
647 case ui::TEXT_INPUT_TYPE_PASSWORD: 693 case ui::TEXT_INPUT_TYPE_PASSWORD:
648 return nil; 694 return nil;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 // views::Textfields are single-line only, map Paragraph and Document commands 729 // views::Textfields are single-line only, map Paragraph and Document commands
684 // to Line. Also, Up/Down commands correspond to beginning/end of line. 730 // to Line. Also, Up/Down commands correspond to beginning/end of line.
685 731
686 // The insertText action message forwards to the TextInputClient unless a menu 732 // The insertText action message forwards to the TextInputClient unless a menu
687 // is active. Note that NSResponder's interpretKeyEvents: implementation doesn't 733 // is active. Note that NSResponder's interpretKeyEvents: implementation doesn't
688 // direct insertText: through doCommandBySelector:, so this is still needed to 734 // direct insertText: through doCommandBySelector:, so this is still needed to
689 // handle the case when inputContext: is nil. When inputContext: returns non-nil 735 // handle the case when inputContext: is nil. When inputContext: returns non-nil
690 // text goes directly to insertText:replacementRange:. 736 // text goes directly to insertText:replacementRange:.
691 - (void)insertText:(id)text { 737 - (void)insertText:(id)text {
692 DCHECK_EQ(nil, [self inputContext]); 738 DCHECK_EQ(nil, [self inputContext]);
693 739 [self insertTextInternal:text];
694 // Only handle the case where no. of characters is 1. Cases not handled (not
695 // an exhaustive list):
696 // - |text| contains a unicode surrogate pair, i.e. a single grapheme which
697 // requires two 16 bit characters. Currently Views menu only supports
698 // mnemonics using a single 16 bit character, so it is ok to ignore this
699 // case.
700 // - Programmatically created events.
701 // - Input from IME. But this case should not occur since inputContext is nil.
702 if (keyDownEvent_ && [text length] == 1) {
703 ui::KeyEvent charEvent = GetCharacterEventFromNSEvent(keyDownEvent_);
704 [self handleKeyEvent:&charEvent];
705 }
706 } 740 }
707 741
708 // Selection movement and scrolling. 742 // Selection movement and scrolling.
709 743
710 - (void)moveForward:(id)sender { 744 - (void)moveForward:(id)sender {
711 IsTextRTL(textInputClient_) ? [self moveLeft:sender] 745 IsTextRTL(textInputClient_) ? [self moveLeft:sender]
712 : [self moveRight:sender]; 746 : [self moveRight:sender];
713 } 747 }
714 748
715 - (void)moveRight:(id)sender { 749 - (void)moveRight:(id)sender {
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 } 1163 }
1130 1164
1131 - (BOOL)hasMarkedText { 1165 - (BOOL)hasMarkedText {
1132 return textInputClient_ && textInputClient_->HasCompositionText(); 1166 return textInputClient_ && textInputClient_->HasCompositionText();
1133 } 1167 }
1134 1168
1135 - (void)insertText:(id)text replacementRange:(NSRange)replacementRange { 1169 - (void)insertText:(id)text replacementRange:(NSRange)replacementRange {
1136 if (!hostedView_) 1170 if (!hostedView_)
1137 return; 1171 return;
1138 1172
1139 if ([text isKindOfClass:[NSAttributedString class]])
1140 text = [text string];
1141
1142 // Verify inputContext is not nil, i.e. |textInputClient_| is valid and no 1173 // Verify inputContext is not nil, i.e. |textInputClient_| is valid and no
1143 // menu is active. 1174 // menu is active.
1144 DCHECK([self inputContext]); 1175 DCHECK([self inputContext]);
1145 1176
1146 textInputClient_->DeleteRange(gfx::Range(replacementRange)); 1177 textInputClient_->DeleteRange(gfx::Range(replacementRange));
1147 1178 [self insertTextInternal:text];
1148 // If a single character is inserted by keyDown's call to interpretKeyEvents:
1149 // then use InsertChar() to allow editing events to be merged.
1150 if (keyDownEvent_ && [text length] == 1)
1151 textInputClient_->InsertChar(GetCharacterEventFromNSEvent(keyDownEvent_));
1152 else
1153 textInputClient_->InsertText(base::SysNSStringToUTF16(text));
1154 } 1179 }
1155 1180
1156 - (NSRange)markedRange { 1181 - (NSRange)markedRange {
1157 if (!textInputClient_) 1182 if (!textInputClient_)
1158 return NSMakeRange(NSNotFound, 0); 1183 return NSMakeRange(NSNotFound, 0);
1159 1184
1160 gfx::Range range; 1185 gfx::Range range;
1161 textInputClient_->GetCompositionTextRange(&range); 1186 textInputClient_->GetCompositionTextRange(&range);
1162 return range.ToNSRange(); 1187 return range.ToNSRange();
1163 } 1188 }
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1246 } 1271 }
1247 1272
1248 return [super accessibilityAttributeValue:attribute]; 1273 return [super accessibilityAttributeValue:attribute];
1249 } 1274 }
1250 1275
1251 - (id)accessibilityHitTest:(NSPoint)point { 1276 - (id)accessibilityHitTest:(NSPoint)point {
1252 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point]; 1277 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point];
1253 } 1278 }
1254 1279
1255 @end 1280 @end
OLDNEW
« no previous file with comments | « no previous file | ui/views/controls/textfield/textfield_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698