| 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 (isKeyDownEventHandled_) |
| 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 isKeyDownEventHandled_ = YES; |
| 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 isKeyDownEventHandled_ = YES; |
| 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 isKeyDownEventHandled_ = YES; |
| 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 isKeyDownEventHandled_ = NO; |
| 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(isKeyDownEventHandled_); |
| 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 isKeyDownEventHandled_ = YES; |
| 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 isKeyDownEventHandled_ = YES; |
| 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 isKeyDownEventHandled_ = YES; |
| 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 |