OLD | NEW |
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 #import "base/mac/sdk_forward_declarations.h" | 10 #import "base/mac/sdk_forward_declarations.h" |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 // This is a special case for which the complete string should should be | 193 // This is a special case for which the complete string should should be |
194 // returned. NSTextView also follows this, though the same is not mentioned in | 194 // returned. NSTextView also follows this, though the same is not mentioned in |
195 // NSTextInputClient documentation. | 195 // NSTextInputClient documentation. |
196 if (!requested_range.IsValid()) | 196 if (!requested_range.IsValid()) |
197 *actual_range = text_range; | 197 *actual_range = text_range; |
198 | 198 |
199 client->GetTextFromRange(*actual_range, &substring); | 199 client->GetTextFromRange(*actual_range, &substring); |
200 return substring; | 200 return substring; |
201 } | 201 } |
202 | 202 |
203 // Returns a character event corresponding to |event|. |event| must be a | |
204 // character event itself. | |
205 ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) { | |
206 DCHECK([event type] == NSKeyDown || [event type] == NSKeyUp); | |
207 DCHECK_EQ(1u, [[event characters] length]); | |
208 | |
209 // [NSEvent characters] already considers the pressed key modifiers. Hence | |
210 // send ui::EF_NONE as the key modifier to the KeyEvent constructor. | |
211 // E.g. For Alt+S, [NSEvent characters] is 'ß' and not 'S'. | |
212 return ui::KeyEvent([[event characters] characterAtIndex:0], | |
213 ui::KeyboardCodeFromNSEvent(event), ui::EF_NONE); | |
214 } | |
215 | |
216 NSAttributedString* GetAttributedString( | 203 NSAttributedString* GetAttributedString( |
217 const gfx::DecoratedText& decorated_text) { | 204 const gfx::DecoratedText& decorated_text) { |
218 base::scoped_nsobject<NSMutableAttributedString> str( | 205 base::scoped_nsobject<NSMutableAttributedString> str( |
219 [[NSMutableAttributedString alloc] | 206 [[NSMutableAttributedString alloc] |
220 initWithString:base::SysUTF16ToNSString(decorated_text.text)]); | 207 initWithString:base::SysUTF16ToNSString(decorated_text.text)]); |
221 [str beginEditing]; | 208 [str beginEditing]; |
222 | 209 |
223 NSValue* const line_style = | 210 NSValue* const line_style = |
224 @(NSUnderlineStyleSingle | NSUnderlinePatternSolid); | 211 @(NSUnderlineStyleSingle | NSUnderlinePatternSolid); |
225 | 212 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 return; | 442 return; |
456 | 443 |
457 DCHECK(event); | 444 DCHECK(event); |
458 if (DispatchEventToMenu([self activeMenuController], event)) | 445 if (DispatchEventToMenu([self activeMenuController], event)) |
459 return; | 446 return; |
460 | 447 |
461 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event); | 448 hostedView_->GetWidget()->GetInputMethod()->DispatchKeyEvent(event); |
462 } | 449 } |
463 | 450 |
464 - (BOOL)handleUnhandledKeyDownAsKeyEvent { | 451 - (BOOL)handleUnhandledKeyDownAsKeyEvent { |
465 if (!keyDownEvent_) | 452 if (!hasUnhandledKeyDownEvent_) |
466 return NO; | 453 return NO; |
467 | 454 |
468 ui::KeyEvent event(keyDownEvent_); | 455 ui::KeyEvent event(keyDownEvent_); |
469 [self handleKeyEvent:&event]; | 456 [self handleKeyEvent:&event]; |
470 keyDownEvent_ = nil; | 457 hasUnhandledKeyDownEvent_ = NO; |
471 return event.handled(); | 458 return event.handled(); |
472 } | 459 } |
473 | 460 |
474 - (void)handleAction:(ui::TextEditCommand)command | 461 - (void)handleAction:(ui::TextEditCommand)command |
475 keyCode:(ui::KeyboardCode)keyCode | 462 keyCode:(ui::KeyboardCode)keyCode |
476 domCode:(ui::DomCode)domCode | 463 domCode:(ui::DomCode)domCode |
477 eventFlags:(int)eventFlags { | 464 eventFlags:(int)eventFlags { |
478 if (!hostedView_) | 465 if (!hostedView_) |
479 return; | 466 return; |
480 | 467 |
(...skipping 18 matching lines...) Expand all Loading... |
499 } | 486 } |
500 | 487 |
501 - (void)insertTextInternal:(id)text { | 488 - (void)insertTextInternal:(id)text { |
502 if (!hostedView_) | 489 if (!hostedView_) |
503 return; | 490 return; |
504 | 491 |
505 if ([text isKindOfClass:[NSAttributedString class]]) | 492 if ([text isKindOfClass:[NSAttributedString class]]) |
506 text = [text string]; | 493 text = [text string]; |
507 | 494 |
508 bool isCharacterEvent = keyDownEvent_ && [text length] == 1; | 495 bool isCharacterEvent = keyDownEvent_ && [text length] == 1; |
| 496 // Pass the character event to the View hierarchy. Cases this handles (non- |
| 497 // exhaustive)- |
| 498 // - Space key press on controls. Unlike Tab and newline which have |
| 499 // corresponding action messages, an insertText: message is generated for |
| 500 // the Space key (insertText:replacementRange: when there's an active |
| 501 // input context). |
| 502 // - Menu mnemonic selection. |
| 503 // Note we create a custom character ui::KeyEvent (and not use the |
| 504 // ui::KeyEvent(NSEvent*) constructor) since we can't just rely on the event |
| 505 // key code to get the actual characters from the ui::KeyEvent. This for |
| 506 // example is necessary for menu mnemonic selection of non-latin text. |
| 507 |
| 508 // Don't generate a key event when there is active composition text. These key |
| 509 // down events should be consumed by the IME and not reach the Views layer. |
| 510 // For example, on pressing Return to commit composition text, if we passed a |
| 511 // synthetic key event to the View hierarchy, it will have the effect of |
| 512 // performing the default action on the current dialog. We do not want this. |
| 513 |
| 514 // Also note that a single key down event can cause multiple |
| 515 // insertText:replacementRange: action messages. Example, on pressing Alt+e, |
| 516 // the accent (´) character is composed via setMarkedText:. Now on pressing |
| 517 // the character 'r', two insertText:replacementRange: action messages are |
| 518 // generated with the text value of accent (´) and 'r' respectively. The key |
| 519 // down event will have characters field of length 2. The first of these |
| 520 // insertText messages won't generate a KeyEvent since there'll be active |
| 521 // marked text. However, a KeyEvent will be generated corresponding to 'r'. |
| 522 |
| 523 // Currently there seems to be no use case to pass non-character events routed |
| 524 // from insertText: handlers to the View hierarchy. |
| 525 if (isCharacterEvent && ![self hasMarkedText]) { |
| 526 ui::KeyEvent charEvent([text characterAtIndex:0], |
| 527 ui::KeyboardCodeFromNSEvent(keyDownEvent_), |
| 528 ui::EF_NONE); |
| 529 [self handleKeyEvent:&charEvent]; |
| 530 hasUnhandledKeyDownEvent_ = NO; |
| 531 } |
509 | 532 |
510 // Forward the |text| to |textInputClient_| if no menu is active. | 533 // Forward the |text| to |textInputClient_| if no menu is active. |
511 if (textInputClient_ && ![self activeMenuController]) { | 534 if (textInputClient_ && ![self activeMenuController]) { |
512 // If a single character is inserted by keyDown's call to | 535 // If a single character is inserted by keyDown's call to |
513 // interpretKeyEvents: then use InsertChar() to allow editing events to be | 536 // interpretKeyEvents: then use InsertChar() to allow editing events to be |
514 // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible | 537 // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible |
515 // to determine the correct key code for each unicode character. Also a | 538 // to determine the correct key code for each unicode character. Also a |
516 // correct keycode is not needed in the current context. Send ui::EF_NONE as | 539 // correct keycode is not needed in the current context. Send ui::EF_NONE as |
517 // the key modifier since |text| already accounts for the pressed key | 540 // the key modifier since |text| already accounts for the pressed key |
518 // modifiers. | 541 // modifiers. |
519 | 542 |
520 // Also, note we don't use |keyDownEvent_| to generate the synthetic | 543 // Also, note we don't use |keyDownEvent_| to generate the synthetic |
521 // ui::KeyEvent since for text inserted using an IME, [keyDownEvent_ | 544 // ui::KeyEvent since for composed text, [keyDownEvent_ characters] might |
522 // characters] might not be the same as |text|. This is because | 545 // not be the same as |text|. This is because |keyDownEvent_| will |
523 // |keyDownEvent_| will correspond to the event that caused the composition | 546 // correspond to the event that caused the composition text to be confirmed, |
524 // text to be confirmed, say, Return key press. | 547 // say, Return key press. |
525 if (isCharacterEvent) { | 548 if (isCharacterEvent) { |
526 textInputClient_->InsertChar(ui::KeyEvent([text characterAtIndex:0], | 549 textInputClient_->InsertChar(ui::KeyEvent([text characterAtIndex:0], |
527 ui::VKEY_UNKNOWN, ui::EF_NONE)); | 550 ui::VKEY_UNKNOWN, ui::EF_NONE)); |
528 } else { | 551 } else { |
529 textInputClient_->InsertText(base::SysNSStringToUTF16(text)); | 552 textInputClient_->InsertText(base::SysNSStringToUTF16(text)); |
530 } | 553 } |
531 | 554 hasUnhandledKeyDownEvent_ = NO; |
532 keyDownEvent_ = nil; // Handled. | |
533 return; | |
534 } | |
535 | |
536 // Only handle the case where no. of characters is 1. Cases not handled (not | |
537 // an exhaustive list): | |
538 // - |text| contains a unicode surrogate pair, i.e. a single grapheme which | |
539 // requires two 16 bit characters. Currently Views menu only supports | |
540 // mnemonics using a single 16 bit character, so it is ok to ignore this | |
541 // case. | |
542 // - Programmatically created events. | |
543 // - Input from IME. But this case should not occur since inputContext is | |
544 // nil. | |
545 if (isCharacterEvent) { | |
546 ui::KeyEvent charEvent = GetCharacterEventFromNSEvent(keyDownEvent_); | |
547 [self handleKeyEvent:&charEvent]; | |
548 keyDownEvent_ = nil; // Handled. | |
549 } | 555 } |
550 } | 556 } |
551 | 557 |
552 - (views::DragDropClientMac*)dragDropClient { | 558 - (views::DragDropClientMac*)dragDropClient { |
553 views::BridgedNativeWidget* bridge = | 559 views::BridgedNativeWidget* bridge = |
554 views::NativeWidgetMac::GetBridgeForNativeWindow([self window]); | 560 views::NativeWidgetMac::GetBridgeForNativeWindow([self window]); |
555 return bridge ? bridge->drag_drop_client() : nullptr; | 561 return bridge ? bridge->drag_drop_client() : nullptr; |
556 } | 562 } |
557 | 563 |
558 - (void)undo:(id)sender { | 564 - (void)undo:(id)sender { |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 // correctly, etc. | 803 // correctly, etc. |
798 // (However, there are still some keys that Cocoa swallows, e.g. the key | 804 // (However, there are still some keys that Cocoa swallows, e.g. the key |
799 // equivalent that Cocoa uses for toggling the input language. In this case, | 805 // equivalent that Cocoa uses for toggling the input language. In this case, |
800 // that's actually a good thing, though -- see http://crbug.com/26115 .) | 806 // that's actually a good thing, though -- see http://crbug.com/26115 .) |
801 return YES; | 807 return YES; |
802 } | 808 } |
803 | 809 |
804 - (void)keyDown:(NSEvent*)theEvent { | 810 - (void)keyDown:(NSEvent*)theEvent { |
805 // Convert the event into an action message, according to OSX key mappings. | 811 // Convert the event into an action message, according to OSX key mappings. |
806 keyDownEvent_ = theEvent; | 812 keyDownEvent_ = theEvent; |
| 813 hasUnhandledKeyDownEvent_ = YES; |
807 [self interpretKeyEvents:@[ theEvent ]]; | 814 [self interpretKeyEvents:@[ theEvent ]]; |
808 | 815 |
809 // If |keyDownEvent_| wasn't cleared during -interpretKeyEvents:, it wasn't | 816 // If |keyDownEvent_| wasn't cleared during -interpretKeyEvents:, it wasn't |
810 // handled. Give Widget accelerators a chance to handle it. | 817 // handled. Give Widget accelerators a chance to handle it. |
811 [self handleUnhandledKeyDownAsKeyEvent]; | 818 [self handleUnhandledKeyDownAsKeyEvent]; |
812 DCHECK(!keyDownEvent_); | 819 DCHECK(!hasUnhandledKeyDownEvent_); |
| 820 keyDownEvent_ = nil; |
813 } | 821 } |
814 | 822 |
815 - (void)keyUp:(NSEvent*)theEvent { | 823 - (void)keyUp:(NSEvent*)theEvent { |
816 ui::KeyEvent event(theEvent); | 824 ui::KeyEvent event(theEvent); |
817 [self handleKeyEvent:&event]; | 825 [self handleKeyEvent:&event]; |
818 } | 826 } |
819 | 827 |
820 - (void)scrollWheel:(NSEvent*)theEvent { | 828 - (void)scrollWheel:(NSEvent*)theEvent { |
821 if (!hostedView_) | 829 if (!hostedView_) |
822 return; | 830 return; |
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1326 } | 1334 } |
1327 | 1335 |
1328 - (void)doCommandBySelector:(SEL)selector { | 1336 - (void)doCommandBySelector:(SEL)selector { |
1329 // Like the renderer, handle insert action messages as a regular key dispatch. | 1337 // Like the renderer, handle insert action messages as a regular key dispatch. |
1330 // This ensures, e.g., insertTab correctly changes focus between fields. | 1338 // This ensures, e.g., insertTab correctly changes focus between fields. |
1331 if (keyDownEvent_ && [NSStringFromSelector(selector) hasPrefix:@"insert"]) | 1339 if (keyDownEvent_ && [NSStringFromSelector(selector) hasPrefix:@"insert"]) |
1332 return; // Handle in -keyDown:. | 1340 return; // Handle in -keyDown:. |
1333 | 1341 |
1334 if ([self respondsToSelector:selector]) { | 1342 if ([self respondsToSelector:selector]) { |
1335 [self performSelector:selector withObject:nil]; | 1343 [self performSelector:selector withObject:nil]; |
1336 keyDownEvent_ = nil; | 1344 hasUnhandledKeyDownEvent_ = NO; |
1337 return; | 1345 return; |
1338 } | 1346 } |
1339 | 1347 |
1340 // For events that AppKit sends via doCommandBySelector:, first attempt to | 1348 // For events that AppKit sends via doCommandBySelector:, first attempt to |
1341 // handle as a Widget accelerator. Forward along the responder chain only if | 1349 // handle as a Widget accelerator. Forward along the responder chain only if |
1342 // the Widget doesn't handle it. | 1350 // the Widget doesn't handle it. |
1343 if (![self handleUnhandledKeyDownAsKeyEvent]) | 1351 if (![self handleUnhandledKeyDownAsKeyEvent]) |
1344 [[self nextResponder] doCommandBySelector:selector]; | 1352 [[self nextResponder] doCommandBySelector:selector]; |
1345 } | 1353 } |
1346 | 1354 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1405 // Add a black underline with a transparent background to the composition | 1413 // Add a black underline with a transparent background to the composition |
1406 // text. TODO(karandeepb): On Cocoa textfields, the target clause of the | 1414 // text. TODO(karandeepb): On Cocoa textfields, the target clause of the |
1407 // composition has a thick underlines. The composition text also has | 1415 // composition has a thick underlines. The composition text also has |
1408 // discontinous underlines for different clauses. This is also supported in | 1416 // discontinous underlines for different clauses. This is also supported in |
1409 // the Chrome renderer. Add code to extract underlines from |text| once our | 1417 // the Chrome renderer. Add code to extract underlines from |text| once our |
1410 // render text implementation supports thick underlines and discontinous | 1418 // render text implementation supports thick underlines and discontinous |
1411 // underlines for consecutive characters. See http://crbug.com/612675. | 1419 // underlines for consecutive characters. See http://crbug.com/612675. |
1412 composition.underlines.push_back(ui::CompositionUnderline( | 1420 composition.underlines.push_back(ui::CompositionUnderline( |
1413 0, [text length], SK_ColorBLACK, false, SK_ColorTRANSPARENT)); | 1421 0, [text length], SK_ColorBLACK, false, SK_ColorTRANSPARENT)); |
1414 textInputClient_->SetCompositionText(composition); | 1422 textInputClient_->SetCompositionText(composition); |
1415 keyDownEvent_ = nil; // Handled. | 1423 hasUnhandledKeyDownEvent_ = NO; |
1416 } | 1424 } |
1417 | 1425 |
1418 - (void)unmarkText { | 1426 - (void)unmarkText { |
1419 if (!textInputClient_) | 1427 if (!textInputClient_) |
1420 return; | 1428 return; |
1421 | 1429 |
1422 textInputClient_->ConfirmCompositionText(); | 1430 textInputClient_->ConfirmCompositionText(); |
1423 keyDownEvent_ = nil; // Handled. | 1431 hasUnhandledKeyDownEvent_ = NO; |
1424 } | 1432 } |
1425 | 1433 |
1426 - (NSArray*)validAttributesForMarkedText { | 1434 - (NSArray*)validAttributesForMarkedText { |
1427 return @[]; | 1435 return @[]; |
1428 } | 1436 } |
1429 | 1437 |
1430 // NSUserInterfaceValidations protocol implementation. | 1438 // NSUserInterfaceValidations protocol implementation. |
1431 | 1439 |
1432 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { | 1440 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { |
1433 ui::TextEditCommand command = GetTextEditCommandForMenuAction([item action]); | 1441 ui::TextEditCommand command = GetTextEditCommandForMenuAction([item action]); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1480 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point]; | 1488 return [hostedView_->GetNativeViewAccessible() accessibilityHitTest:point]; |
1481 } | 1489 } |
1482 | 1490 |
1483 - (id)accessibilityFocusedUIElement { | 1491 - (id)accessibilityFocusedUIElement { |
1484 if (!hostedView_) | 1492 if (!hostedView_) |
1485 return nil; | 1493 return nil; |
1486 return [hostedView_->GetNativeViewAccessible() accessibilityFocusedUIElement]; | 1494 return [hostedView_->GetNativeViewAccessible() accessibilityFocusedUIElement]; |
1487 } | 1495 } |
1488 | 1496 |
1489 @end | 1497 @end |
OLD | NEW |