Index: content/browser/renderer_host/render_widget_host.cc |
=================================================================== |
--- content/browser/renderer_host/render_widget_host.cc (revision 111709) |
+++ content/browser/renderer_host/render_widget_host.cc (working copy) |
@@ -101,7 +101,8 @@ |
text_direction_updated_(false), |
text_direction_(WebKit::WebTextDirectionLeftToRight), |
text_direction_canceled_(false), |
- suppress_next_char_events_(false), |
+ suppress_incoming_char_events_(false), |
+ suppress_outgoing_char_events_(false), |
pending_mouse_lock_request_(false), |
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
if (routing_id_ == MSG_ROUTING_NONE) |
@@ -574,7 +575,7 @@ |
OnUserGesture(); |
} |
- ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false); |
+ ForwardInputEvent(mouse_event, sizeof(WebMouseEvent)); |
} |
void RenderWidgetHost::OnMouseActivate() { |
@@ -612,7 +613,7 @@ |
HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize", |
coalesced_mouse_wheel_events_.size()); |
- ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); |
+ ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent)); |
} |
void RenderWidgetHost::ForwardGestureEvent( |
@@ -621,7 +622,7 @@ |
if (ignore_input_events_ || process_->IgnoreInputEvents()) |
return; |
- ForwardInputEvent(gesture_event, sizeof(WebGestureEvent), false); |
+ ForwardInputEvent(gesture_event, sizeof(WebGestureEvent)); |
} |
void RenderWidgetHost::ForwardKeyboardEvent( |
@@ -630,64 +631,84 @@ |
if (ignore_input_events_ || process_->IgnoreInputEvents()) |
return; |
+ // Double check the type to make sure caller hasn't sent us nonsense that |
+ // will mess up our key queue. |
+ if (!WebInputEvent::isKeyboardEventType(key_event.type)) |
+ return; |
+ |
if (key_event.type == WebKeyboardEvent::Char && |
(key_event.windowsKeyCode == ui::VKEY_RETURN || |
key_event.windowsKeyCode == ui::VKEY_SPACE)) { |
OnUserGesture(); |
} |
- // Double check the type to make sure caller hasn't sent us nonsense that |
- // will mess up our key queue. |
- if (WebInputEvent::isKeyboardEventType(key_event.type)) { |
- if (suppress_next_char_events_) { |
- // If preceding RawKeyDown event was handled by the browser, then we need |
- // suppress all Char events generated by it. Please note that, one |
- // RawKeyDown event may generate multiple Char events, so we can't reset |
- // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. |
- if (key_event.type == WebKeyboardEvent::Char) |
- return; |
- // We get a KeyUp or a RawKeyDown event. |
- suppress_next_char_events_ = false; |
- } |
+ if (suppress_incoming_char_events_) { |
+ // If the preceding RawKeyDown event was handled by the browser, then we |
+ // need to suppress all Char events generated by it. Please note that, one |
+ // RawKeyDown event may generate multiple Char events, so we can't reset |
+ // |suppress_incoming_char_events_| until we get a KeyUp or a RawKeyDown. |
+ if (key_event.type == WebKeyboardEvent::Char) |
+ return; |
+ // We get a KeyUp or a RawKeyDown event. |
+ suppress_incoming_char_events_ = false; |
+ } |
- bool is_keyboard_shortcut = false; |
- // Only pre-handle the key event if it's not handled by the input method. |
- if (!key_event.skip_in_browser) { |
- // We need to set |suppress_next_char_events_| to true if |
- // PreHandleKeyboardEvent() returns true, but |this| may already be |
- // destroyed at that time. So set |suppress_next_char_events_| true here, |
- // then revert it afterwards when necessary. |
- if (key_event.type == WebKeyboardEvent::RawKeyDown) |
- suppress_next_char_events_ = true; |
+ bool is_keyboard_shortcut = false; |
+ // Only pre-handle the key event if it's not handled by the input method. |
+ if (!key_event.skip_in_browser) { |
+ // We need to set |suppress_incoming_char_events_| to true if |
+ // PreHandleKeyboardEvent() returns true, but |this| may already be |
+ // destroyed at that time. So set |suppress_incoming_char_events_| true |
+ // here, then revert it afterwards when necessary. |
+ if (key_event.type == WebKeyboardEvent::RawKeyDown) |
+ suppress_incoming_char_events_ = true; |
- // Tab switching/closing accelerators aren't sent to the renderer to avoid |
- // a hung/malicious renderer from interfering. |
- if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) |
- return; |
+ // Tab switching/closing accelerators aren't sent to the renderer to avoid |
+ // a hung/malicious renderer from interfering. |
+ if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) |
+ return; |
- if (key_event.type == WebKeyboardEvent::RawKeyDown) |
- suppress_next_char_events_ = false; |
- } |
+ if (key_event.type == WebKeyboardEvent::RawKeyDown) |
+ suppress_incoming_char_events_ = false; |
+ } |
- // Don't add this key to the queue if we have no way to send the message... |
- if (!process_->HasConnection()) |
- return; |
+ // Don't add this key to the queue if we have no way to send the message... |
+ if (!process_->HasConnection()) |
+ return; |
- // Put all WebKeyboardEvent objects in a queue since we can't trust the |
- // renderer and we need to give something to the UnhandledInputEvent |
- // handler. |
- key_queue_.push_back(key_event); |
- HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
+ bool has_pending_key = !key_queue_.empty(); |
- // Only forward the non-native portions of our event. |
- ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), |
- is_keyboard_shortcut); |
+ // We keep track of all pending keyboard events so that if any are not |
+ // processed by the renderer, we have the ability to process them in the |
+ // browser (via UnhandledKeyboardEvent). We also delay sending the next |
+ // keyboard event until the previous has been ACK'd by the renderer. |
+ key_queue_.push_back(Key(key_event, is_keyboard_shortcut)); |
+ HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
+ |
+ if (!has_pending_key) |
+ ForwardNextKeyboardEvent(); |
+} |
+ |
+void RenderWidgetHost::ForwardNextKeyboardEvent() { |
+ while (!key_queue_.empty()) { |
+ const Key& front_item = key_queue_.front(); |
+ |
+ if (suppress_outgoing_char_events_) { |
+ if (front_item.event.type == WebInputEvent::Char) { |
+ key_queue_.pop_front(); |
+ continue; |
+ } |
+ suppress_outgoing_char_events_ = false; |
+ } |
+ |
+ // The renderer only cares about the platform-independent event data. |
+ ForwardInputEvent(front_item.event, sizeof(WebKeyboardEvent)); |
+ break; |
} |
} |
void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, |
- int event_size, |
- bool is_keyboard_shortcut) { |
+ int event_size) { |
TRACE_EVENT0("renderer_host", "RenderWidgetHost::ForwardInputEvent"); |
if (!process_->HasConnection()) |
@@ -698,9 +719,6 @@ |
IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); |
message->WriteData( |
reinterpret_cast<const char*>(&input_event), event_size); |
- // |is_keyboard_shortcut| only makes sense for RawKeyDown events. |
- if (input_event.type == WebInputEvent::RawKeyDown) |
- message->WriteBool(is_keyboard_shortcut); |
input_event_start_time_ = TimeTicks::Now(); |
Send(message); |
@@ -733,7 +751,7 @@ |
touch_move_pending_ = true; |
else |
touch_move_pending_ = false; |
- ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false); |
+ ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent)); |
} |
void RenderWidgetHost::RendererExited(base::TerminationStatus status, |
@@ -753,7 +771,8 @@ |
// Must reset these to ensure that keyboard events work with a new renderer. |
key_queue_.clear(); |
- suppress_next_char_events_ = false; |
+ suppress_incoming_char_events_ = false; |
+ suppress_outgoing_char_events_ = false; |
// Reset some fields in preparation for recovering from a crash. |
resize_ack_pending_ = false; |
@@ -1323,29 +1342,40 @@ |
if (key_queue_.empty()) { |
LOG(ERROR) << "Got a KeyEvent back from the renderer but we " |
<< "don't seem to have sent it to the renderer!"; |
- } else if (key_queue_.front().type != type) { |
+ } else if (key_queue_.front().event.type != type) { |
LOG(ERROR) << "We seem to have a different key type sent from " |
- << "the renderer. (" << key_queue_.front().type << " vs. " |
+ << "the renderer. (" << key_queue_.front().event.type << " vs. " |
<< type << "). Ignoring event."; |
// Something must be wrong. Clear the |key_queue_| and |
- // |suppress_next_char_events_| so that we can resume from the error. |
+ // |suppress_incoming_char_events_| so that we can resume from the error. |
key_queue_.clear(); |
- suppress_next_char_events_ = false; |
+ suppress_incoming_char_events_ = false; |
+ suppress_outgoing_char_events_ = false; |
} else { |
- NativeWebKeyboardEvent front_item = key_queue_.front(); |
+ Key front_item = key_queue_.front(); |
key_queue_.pop_front(); |
#if defined(OS_MACOSX) |
- if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) |
+ if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item.event)) |
return; |
#endif |
+ // If this RawKeyDown event corresponds to a browser keyboard shortcut and |
+ // it's not processed by the renderer, then we need to suppress the |
+ // upcoming Char event. |
+ if (!processed && front_item.is_shortcut) { |
+ DCHECK(front_item.event.type == WebInputEvent::RawKeyDown); |
+ suppress_outgoing_char_events_ = true; |
+ } |
+ |
+ ForwardNextKeyboardEvent(); |
+ |
// We only send unprocessed key event upwards if we are not hidden, |
// because the user has moved away from us and no longer expect any effect |
// of this key event. |
- if (!processed && !is_hidden_ && !front_item.skip_in_browser) { |
- UnhandledKeyboardEvent(front_item); |
+ if (!processed && !is_hidden_ && !front_item.event.skip_in_browser) { |
+ UnhandledKeyboardEvent(front_item.event); |
// WARNING: This RenderWidgetHost can be deallocated at this point |
// (i.e. in the case of Ctrl+W, where the call to |