summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host
diff options
context:
space:
mode:
authorsuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-10 20:53:37 +0000
committersuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-10 20:53:37 +0000
commit3178644d2f45a74fc5afbf23666289daccb17b9b (patch)
tree5eea50b8186c1e5d1fb53f0a9f3c9bee0c4fd851 /chrome/browser/renderer_host
parent0978322504c4790361057864968a3f202b19e166 (diff)
downloadchromium_src-3178644d2f45a74fc5afbf23666289daccb17b9b.zip
chromium_src-3178644d2f45a74fc5afbf23666289daccb17b9b.tar.gz
chromium_src-3178644d2f45a74fc5afbf23666289daccb17b9b.tar.bz2
[Mac]Refactor input method related code.
BUG=30670 Cannot input any characters after typing CTRL+H on IME BUG=33824 Shortcut key Ctrl+K in Japanese IME reset cursor position to end of the string BUG=42690 first ime keydown has the wrong keycode on Mac BUG=43087 1st time type CJK character with IME in any text input field of websites,1st character is always deleted. BUG=43454 When converting a Hangul to Chinese character, a new line is inserted before the character to convert. TEST=See bug reports. Review URL: http://codereview.chromium.org/1908006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46856 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h102
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm282
2 files changed, 200 insertions, 184 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h
index 5fa2d68..d79b0f1 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -45,21 +45,62 @@ class RWHVMEditCommandHelper;
NSTrackingRectTag lastToolTipTag_;
scoped_nsobject<NSString> toolTip_;
- // Set to YES if insertText: or insertNewline: get called.
- BOOL textInserted_;
-
// Is YES if there was a mouse-down as yet unbalanced with a mouse-up.
BOOL hasOpenMouseDown_;
- // Keep current key event when keyEvent: gets called. It's used in
- // insertText: and insertNewline: to synthesize the corresponding Char event.
- scoped_nsobject<NSEvent> currentKeyEvent_;
NSWindow* lastWindow_; // weak
// The Core Animation layer, if any, hosting the accelerated plugins' output.
scoped_nsobject<CALayer> acceleratedPluginLayer_;
+
+ // Variables used by our implementaion of the NSTextInput protocol.
+ // An input method of Mac calls the methods of this protocol not only to
+ // notify an application of its status, but also to retrieve the status of
+ // the application. That is, an application cannot control an input method
+ // directly.
+ // This object keeps the status of a composition of the renderer and returns
+ // it when an input method asks for it.
+ // We need to implement Objective-C methods for the NSTextInput protocol. On
+ // the other hand, we need to implement a C++ method for an IPC-message
+ // handler which receives input-method events from the renderer.
+
+ // Represents the input-method attributes supported by this object.
+ scoped_nsobject<NSArray> validAttributesForMarkedText_;
+
+ // Represents the cursor position in this view coordinate.
+ // The renderer sends the cursor position through an IPC message.
+ // We save the latest cursor position here and return it when an input
+ // methods needs it.
+ NSRect caretRect_;
+
+ // Indicates if we are currently handling a key down event.
+ BOOL handlingKeyDown_;
+
+ // Indicates if there is any marked text.
+ BOOL hasMarkedText_;
+
+ // The range of current marked text inside the whole content of the DOM node
+ // being edited.
+ // TODO(suzhe): This is currently a fake value, as we do not support accessing
+ // the whole content yet.
+ NSRange markedRange_;
+
+ // The selected range inside current marked text.
+ // TODO(suzhe): Currently it's only valid when there is any marked text.
+ // In the future, we may need to support accessing the whole content of the
+ // DOM node being edited, then this should be the selected range inside the
+ // DOM node.
+ NSRange selectedRange_;
+
+ // Text to be inserted which was generated by handling a key down event.
+ string16 textToBeInserted_;
+
+ // New marked text which was generated by handling a key down event.
+ string16 newMarkedText_;
}
+@property(assign, nonatomic) NSRect caretRect;
+
- (void)setCanBeKeyView:(BOOL)can;
- (void)setCloseOnDeactivate:(BOOL)b;
- (void)setToolTipAtMousePoint:(NSString *)string;
@@ -76,6 +117,8 @@ class RWHVMEditCommandHelper;
// Notify the RenderWidgetHost that the frame was updated so it can resize
// its contents.
- (void)renderWidgetHostWasResized;
+// Cancel ongoing composition (abandon the marked text).
+- (void)cancelComposition;
@end
@@ -169,11 +212,6 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
void set_parent_view(BaseView* parent_view) { parent_view_ = parent_view; }
- // Cancels the ongoing composition and cleans up all input-method resources.
- // This function dispatches a cancelation request from a renderer to
- // NSInputManager to synchronize the input-method status with it.
- void IMECleanupComposition();
-
// These member variables should be private, but the associated ObjC class
// needs access to them and can't be made a friend.
@@ -203,48 +241,6 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
// The time it took after this view was selected for it to be fully painted.
base::TimeTicks tab_switch_paint_time_;
- // Variables used by our implementaion of the NSTextInput protocol.
- // An input method of Mac calls the methods of this protocol not only to
- // notify an application of its status, but also to retrieve the status of
- // the application. That is, an application cannot control an input method
- // directly.
- // This object keeps the status of a composition of the renderer and returns
- // it when an input method asks for it.
- // We need to implement Objective-C methods for the NSTextInput protocol. On
- // the other hand, we need to implement a C++ method for an IPC-message
- // handler which receives input-method events from the renderer.
- // To avoid fragmentation of variables used by our input-method
- // implementation, we define all variables as public member variables of
- // this C++ class so both the C++ methods and the Objective-C methods can
- // access them.
-
- // Represents the input-method attributes supported by this object.
- NSArray* im_attributes_;
-
- // Represents whether or not an input method is composing a text.
- bool im_composing_;
-
- // Represents the composition string (i.e. a text being composed by an input
- // method), its range, and the range of the selected text in the composition
- // string.
- string16 im_text_;
- NSRange im_marked_range_;
- NSRange im_selected_range_;
-
- // Represents the state of modifier keys.
- // An input method doesn't notify the state of modifier keys. On the other
- // hand, the state of modifier keys are required by Char events because they
- // are dispatched to onkeypress() event handlers of JavaScript.
- // To create a Char event in NSTextInput methods, we save the latest state
- // of modifier keys when we receive it.
- int im_modifiers_;
-
- // Represents the cursor position in this view coordinate.
- // The renderer sends the cursor position through an IPC message.
- // We save the latest cursor position here and return it when an input
- // methods needs it.
- NSRect im_caret_rect_;
-
private:
// Updates the display cursor to the current cursor if the cursor is over this
// render view.
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 18ffb5f..104b346 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -131,8 +131,6 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
: render_widget_host_(widget),
about_to_validate_and_paint_(false),
call_set_needs_display_in_rect_pending_(false),
- im_attributes_(nil),
- im_composing_(false),
is_loading_(false),
is_hidden_(false),
is_popup_menu_(false),
@@ -147,7 +145,6 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
}
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
- [im_attributes_ release];
}
///////////////////////////////////////////////////////////////////////////////
@@ -321,18 +318,14 @@ void RenderWidgetHostViewMac::IMEUpdateStatus(int control,
const gfx::Rect& caret_rect) {
// Reset the IME state and finish an ongoing composition in the renderer.
if (control == IME_DISABLE || control == IME_COMPLETE_COMPOSITION)
- IMECleanupComposition();
+ [cocoa_view_ cancelComposition];
// We need to convert the coordinate of the cursor rectangle sent from the
// renderer and save it. Our IME backend uses a coordinate system whose
// origin is the upper-left corner of this view. On the other hand, Cocoa
// uses a coordinate system whose origin is the lower-left corner of this
// view. So, we convert the cursor rectangle and save it.
- NSRect view_rect = [cocoa_view_ bounds];
- const int y_offset = static_cast<int>(view_rect.size.height);
- im_caret_rect_ = NSMakeRect(caret_rect.x(),
- y_offset - caret_rect.y() - caret_rect.height(),
- caret_rect.width(), caret_rect.height());
+ [cocoa_view_ setCaretRect:[cocoa_view_ RectToNSRect:caret_rect]];
}
void RenderWidgetHostViewMac::DidPaintBackingStoreRects(
@@ -544,22 +537,6 @@ void RenderWidgetHostViewMac::KillSelf() {
}
}
-void RenderWidgetHostViewMac::IMECleanupComposition() {
- if (!im_composing_)
- return;
-
- // Cancel the ongoing composition. [NSInputManager markedTextAbandoned:]
- // doesn't call any NSTextInput functions, such as setMarkedText or
- // insertText. So, we need to send an IPC message to a renderer so it can
- // delete the composition node.
- NSInputManager *currentInputManager = [NSInputManager currentInputManager];
- [currentInputManager markedTextAbandoned:[cocoa_view_ self]];
-
- render_widget_host_->ImeCancelComposition();
- im_text_.clear();
- im_composing_ = false;
-}
-
gfx::PluginWindowHandle
RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque) {
// Make sure we have a layer for the plugin to draw into.
@@ -780,6 +757,8 @@ bool RenderWidgetHostViewMac::ContainsNativeView(
@implementation RenderWidgetHostViewCocoa
+@synthesize caretRect = caretRect_;
+
- (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
self = [super initWithFrame:NSZeroRect];
if (self != nil) {
@@ -814,7 +793,7 @@ bool RenderWidgetHostViewMac::ContainsNativeView(
renderWidgetHostView_->render_widget_host_->ForwardMouseEvent(event);
if ([theEvent type] == NSLeftMouseDown) {
- renderWidgetHostView_->IMECleanupComposition();
+ [self cancelComposition];
hasOpenMouseDown_ = YES;
}
@@ -881,74 +860,125 @@ bool RenderWidgetHostViewMac::ContainsNativeView(
return;
}
- scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]);
-
// Don't cancel child popups; the key events are probably what's triggering
// the popup in the first place.
+ RenderWidgetHost* widgetHost = renderWidgetHostView_->render_widget_host_;
+ DCHECK(widgetHost);
+
NativeWebKeyboardEvent event(theEvent);
- // Save the modifier keys so the insertText method can use it when it sends
- // a Char event, which is dispatched as an onkeypress() event of JavaScript.
- renderWidgetHostView_->im_modifiers_ = event.modifiers;
+ // We only handle key down events and just simply forward other events.
+ if ([theEvent type] != NSKeyDown) {
+ widgetHost->ForwardKeyboardEvent(event);
+
+ // Possibly autohide the cursor.
+ if ([RenderWidgetHostViewCocoa shouldAutohideCursorForEvent:theEvent])
+ [NSCursor setHiddenUntilMouseMoves:YES];
+
+ return;
+ }
+
+ scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]);
+
+ // Records the current marked text state, so that we can know if the marked
+ // text was deleted or not after handling the key down event.
+ BOOL oldHasMarkedText = hasMarkedText_;
+
+ // This method should not be called recursively.
+ DCHECK(!handlingKeyDown_);
+
+ // Tells insertText: and doCommandBySelector: that we are handling a key
+ // down event.
+ handlingKeyDown_ = YES;
+
+ // These two variables might be set when handling the keyboard event.
+ // Clear them here so that we can know whether they have changed afterwards.
+ textToBeInserted_.clear();
+ newMarkedText_.clear();
+
+ // Sends key down events to input method first, then we can decide what should
+ // be done according to input method's feedback.
+ [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+
+ handlingKeyDown_ = NO;
// To emulate Windows, over-write |event.windowsKeyCode| to VK_PROCESSKEY
- // while an input method is composing a text.
+ // while an input method is composing or inserting a text.
// Gmail checks this code in its onkeydown handler to stop auto-completing
// e-mail addresses while composing a CJK text.
- if ([theEvent type] == NSKeyDown && renderWidgetHostView_->im_composing_) {
+ // If the text to be inserted has only one character, then we don't need this
+ // trick, because we'll send the text as a key press event instead.
+ if (hasMarkedText_ || oldHasMarkedText || textToBeInserted_.length() > 1) {
event.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY
event.setKeyIdentifierFromWindowsKeyCode();
event.skip_in_browser = true;
- }
-
- // Dispatch this keyboard event to the renderer.
- if (renderWidgetHostView_->render_widget_host_) {
- RenderWidgetHost* widgetHost = renderWidgetHostView_->render_widget_host_;
+ } else {
// 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);
}
- currentKeyEvent_.reset([theEvent retain]);
- textInserted_ = NO;
-
- // Dispatch a NSKeyDown event to an input method.
- // To send an onkeydown() event before an onkeypress() event, we should
- // dispatch this NSKeyDown event AFTER sending it to the renderer.
- // (See <https://bugs.webkit.org/show_bug.cgi?id=25119>).
- //
- // If this object's retainCount is 1, the only reference is the one held by
- // keepSelfAlive. All other references may have been destroyed in the
- // RenderWidgetHost::ForwardKeyboardEvent call above if it resulted in tab
- // closure. Were it not for that single reference, this object would
- // already be deallocated. In that case, there's no point in calling
- // -interpretKeyEvents:.
- if ([self retainCount] > 1 && [theEvent type] == NSKeyDown) {
- [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ // Forward the key down event first.
+ widgetHost->ForwardKeyboardEvent(event);
+ // Calling ForwardKeyboardEvent() could have destroyed the widget. When the
+ // widget was destroyed, |renderWidgetHostView_->render_widget_host_| will
+ // be set to NULL. So we check it here and return immediately if it's NULL.
+ if (!renderWidgetHostView_->render_widget_host_)
+ return;
+
+ // Then send keypress and/or composition related events.
+ // If there was a marked text or the text to be inserted is longer than 1
+ // character, then we send the text by calling ImeConfirmComposition().
+ // Otherwise, if the text to be inserted only contains 1 character, then we
+ // can just send a keypress event which is fabricated by changing the type of
+ // the keydown event, so that we can retain all necessary informations, such
+ // as unmodifiedText, etc. And we need to set event.skip_in_browser to true to
+ // prevent the browser from handling it again.
+ // Note that, |textToBeInserted_| is a UTF-16 string, but it's fine to only
+ // handle BMP characters here, as we can always insert non-BMP characters as
+ // text.
+ const NSUInteger kCtrlCmdKeyMask = NSControlKeyMask | NSCommandKeyMask;
+ BOOL textInserted = NO;
+ if (textToBeInserted_.length() > (oldHasMarkedText ? 0 : 1)) {
+ widgetHost->ImeConfirmComposition(textToBeInserted_);
+ textInserted = YES;
+ } else if (textToBeInserted_.length() == 1) {
+ event.type = WebKit::WebInputEvent::Char;
+ event.text[0] = textToBeInserted_[0];
+ event.text[1] = 0;
+ event.skip_in_browser = true;
+ widgetHost->ForwardKeyboardEvent(event);
+ } else if (([theEvent modifierFlags] & kCtrlCmdKeyMask) &&
+ [[theEvent characters] length] > 0) {
// We don't get insertText: calls if ctrl is down and not even a keyDown:
// call if cmd is down, so synthesize a keypress event for these cases.
// Note that this makes our behavior deviate from the windows and linux
// versions of chrome (however, see http://crbug.com/13891 ), but it makes
// us behave similar to how Safari behaves.
- if ([theEvent modifierFlags] & (NSControlKeyMask | NSCommandKeyMask) &&
- !textInserted_ && [[theEvent characters] length] > 0 &&
- renderWidgetHostView_->render_widget_host_) {
- // Just fabricate a Char event by changing the type of the RawKeyDown
- // event, to retain all necessary informations, such as unmodifiedText.
- event.type = WebKit::WebInputEvent::Char;
- // We fire menu items on keydown, we don't want to activate menu items
- // twice.
- event.skip_in_browser = true;
- renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event);
- }
+ event.type = WebKit::WebInputEvent::Char;
+ event.skip_in_browser = true;
+ widgetHost->ForwardKeyboardEvent(event);
}
- currentKeyEvent_.reset();
+ // Updates or cancels the composition. If some text has been inserted, then
+ // we don't need to cancel the composition explicitly.
+ if (hasMarkedText_ && newMarkedText_.length()) {
+ // Sends the updated marked text to the renderer so it can update the
+ // composition node in WebKit.
+ // When marked text is available, |selectedRange_| will be the range being
+ // selected inside the marked text. We put the cursor at the beginning of
+ // the selected range.
+ widgetHost->ImeSetComposition(newMarkedText_,
+ selectedRange_.location,
+ selectedRange_.location,
+ NSMaxRange(selectedRange_));
+ } else if (oldHasMarkedText && !hasMarkedText_ && !textInserted) {
+ widgetHost->ImeCancelComposition();
+ }
// Possibly autohide the cursor.
if ([RenderWidgetHostViewCocoa shouldAutohideCursorForEvent:theEvent])
@@ -1148,6 +1178,7 @@ bool RenderWidgetHostViewMac::ContainsNativeView(
return NO;
renderWidgetHostView_->render_widget_host_->Focus();
+ renderWidgetHostView_->render_widget_host_->ImeSetInputMode(true);
return YES;
}
@@ -1158,8 +1189,8 @@ bool RenderWidgetHostViewMac::ContainsNativeView(
if (closeOnDeactivate_)
renderWidgetHostView_->KillSelf();
+ renderWidgetHostView_->render_widget_host_->ImeSetInputMode(false);
renderWidgetHostView_->render_widget_host_->Blur();
-
return YES;
}
@@ -1494,15 +1525,15 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
- (NSArray *)validAttributesForMarkedText {
// This code is just copied from WebKit except renaming variables.
- if (!renderWidgetHostView_->im_attributes_) {
- renderWidgetHostView_->im_attributes_ = [[NSArray alloc] initWithObjects:
+ if (!validAttributesForMarkedText_) {
+ validAttributesForMarkedText_.reset([[NSArray alloc] initWithObjects:
NSUnderlineStyleAttributeName,
NSUnderlineColorAttributeName,
NSMarkedClauseSegmentAttributeName,
NSTextInputReplacementRangeAttributeName,
- nil];
+ nil]);
}
- return renderWidgetHostView_->im_attributes_;
+ return validAttributesForMarkedText_.get();
}
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
@@ -1518,8 +1549,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// Since this window may be moved since we receive the cursor rectangle last
// time we sent the cursor rectangle to the IME, so we should map from the
// view coordinate to the screen coordinate every time when an IME need it.
- NSRect resultRect = renderWidgetHostView_->im_caret_rect_;
- resultRect = [self convertRect:resultRect toView:nil];
+ NSRect resultRect = [self convertRect:caretRect_ toView:nil];
NSWindow* window = [self window];
if (window)
resultRect.origin = [window convertBaseToScreen:resultRect.origin];
@@ -1528,7 +1558,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
- (NSRange)selectedRange {
// Return the selected range saved in the setMarkedText method.
- return renderWidgetHostView_->im_selected_range_;
+ return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0);
}
- (NSRange)markedRange {
@@ -1538,7 +1568,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// calls the setMarkedText method and we can update the composition node
// there. (When this method returns an empty range, the input method doesn't
// call the setMarkedText method.)
- return renderWidgetHostView_->im_marked_range_;
+ return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
}
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange {
@@ -1556,11 +1586,11 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
- (BOOL)hasMarkedText {
// An input method calls this function to figure out whether or not an
// application is really composing a text. If it is composing, it calls
- // the markedRange method, and maybe calls the setMarkedTest method.
+ // the markedRange method, and maybe calls the setMarkedText method.
// It seems an input method usually calls this function when it is about to
// cancel an ongoing composition. If an application has a non-empty marked
// range, it calls the setMarkedText method to delete the range.
- return renderWidgetHostView_->im_composing_ ? YES : NO;
+ return hasMarkedText_;
}
- (void)unmarkText {
@@ -1569,8 +1599,12 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// It seems an input method calls the setMarkedText method and set an empty
// text when it cancels an ongoing composition, i.e. I have never seen an
// input method calls this method.
- renderWidgetHostView_->render_widget_host_->ImeCancelComposition();
- renderWidgetHostView_->im_composing_ = false;
+ hasMarkedText_ = NO;
+
+ // If we are handling a key down event, then ImeCancelComposition() will be
+ // called in keyEvent: method.
+ if (!handlingKeyDown_)
+ renderWidgetHostView_->render_widget_host_->ImeCancelComposition();
}
- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange {
@@ -1580,39 +1614,24 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
NSString* im_text = isAttributedString ? [string string] : string;
int length = [im_text length];
- int cursor = newSelRange.location;
-
- int target_start;
- int target_end;
- if (!newSelRange.length) {
- // The given text doesn't have any range to be highlighted. Clear the
- // selection range.
- target_start = 0;
- target_end = 0;
- } else {
- // The given text has a range to be highlighted.
- // Set the selection range to the given one and put the cursor at the
- // beginning of the selection range.
- target_start = newSelRange.location;
- target_end = NSMaxRange(newSelRange);
- }
- // Dispatch this IME event to the renderer and update the IME state of this
- // object.
+ markedRange_ = NSMakeRange(0, length);
+ selectedRange_ = newSelRange;
+ newMarkedText_ = base::SysNSStringToUTF16(im_text);
+ hasMarkedText_ = (length > 0);
+
+ // If we are handling a key down event, then ImeSetComposition() will be
+ // called in keyEvent: method.
// Input methods of Mac use setMarkedText calls with an empty text to cancel
// an ongoing composition. So, we should check whether or not the given text
// is empty to update the IME state. (Our IME backend can automatically
// cancels an ongoing composition when we send an empty text. So, it is OK
// to send an empty text to the renderer.)
- renderWidgetHostView_->im_text_ = UTF8ToUTF16([im_text UTF8String]);
- renderWidgetHostView_->render_widget_host_->ImeSetComposition(
- renderWidgetHostView_->im_text_, cursor, target_start, target_end);
- renderWidgetHostView_->GetRenderWidgetHost()->ImeSetInputMode(true);
- renderWidgetHostView_->im_composing_ = length > 0;
- renderWidgetHostView_->im_marked_range_.location = 0;
- renderWidgetHostView_->im_marked_range_.length = length;
- renderWidgetHostView_->im_selected_range_.location = newSelRange.location;
- renderWidgetHostView_->im_selected_range_.length = newSelRange.length;
+ if (!handlingKeyDown_) {
+ renderWidgetHostView_->render_widget_host_->ImeSetComposition(
+ newMarkedText_, newSelRange.location, newSelRange.location,
+ NSMaxRange(newSelRange));
+ }
}
- (void)doCommandBySelector:(SEL)selector {
@@ -1624,22 +1643,17 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// character to onkeypress() event handlers.
// TODO(hbono): need to handle more commands?
if (selector == @selector(insertNewline:)) {
- if (currentKeyEvent_.get()) {
- // Create the Char event from the NSEvent object, so that we can retain
- // necessary informations, especially unmodifiedText.
- NativeWebKeyboardEvent event(currentKeyEvent_.get());
- event.type = WebKit::WebInputEvent::Char;
- event.text[0] = '\r';
- event.text[1] = 0;
- event.skip_in_browser = true;
- renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event);
+ if (handlingKeyDown_) {
+ // If we are handling a key down event, then we just need to append a '\r'
+ // character to |textToBeInserted_| which will then be handled by
+ // keyEvent: method.
+ textToBeInserted_.push_back('\r');
} else {
// This call is not initiated by a key event, so just executed the
// corresponding editor command.
renderWidgetHostView_->render_widget_host_->ForwardEditCommand(
"InsertNewline", "");
}
- textInserted_ = YES;
}
}
@@ -1659,23 +1673,15 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
// sent as an IME event as well.
BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
NSString* im_text = isAttributedString ? [string string] : string;
- if (!renderWidgetHostView_->im_composing_ && [im_text length] == 1 &&
- currentKeyEvent_.get()) {
- // Create the Char event from the NSEvent object, so that we can retain
- // necessary informations, especially unmodifiedText.
- NativeWebKeyboardEvent event(currentKeyEvent_.get());
- event.type = WebKit::WebInputEvent::Char;
- event.text[0] = [im_text characterAtIndex:0];
- event.text[1] = 0;
- event.skip_in_browser = true;
- renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event);
+ if (handlingKeyDown_) {
+ textToBeInserted_.append(base::SysNSStringToUTF16(im_text));
} else {
renderWidgetHostView_->render_widget_host_->ImeConfirmComposition(
- UTF8ToUTF16([im_text UTF8String]));
+ base::SysNSStringToUTF16(im_text));
}
- renderWidgetHostView_->im_text_.clear();
- renderWidgetHostView_->im_composing_ = false;
- textInserted_ = YES;
+
+ // Inserting text will delete all marked text automatically.
+ hasMarkedText_ = NO;
}
- (void)viewDidMoveToWindow {
@@ -1801,4 +1807,18 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
[acceleratedPluginLayer_.get() setNeedsDisplay];
}
+- (void)cancelComposition {
+ if (!hasMarkedText_)
+ return;
+
+ // Cancel the ongoing composition. [NSInputManager markedTextAbandoned:]
+ // doesn't call any NSTextInput functions, such as setMarkedText or
+ // insertText. So, we need to send an IPC message to a renderer so it can
+ // delete the composition node.
+ NSInputManager *currentInputManager = [NSInputManager currentInputManager];
+ [currentInputManager markedTextAbandoned:self];
+
+ [self unmarkText];
+}
+
@end