| 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
|
|
|