15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/client/plugin/pepper_input_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/dev/ppb_keyboard_input_event_dev.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/input_event.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module_impl.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/point.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/event.pb.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PepperInputHandler::PepperInputHandler(protocol::InputStub* input_stub)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : input_stub_(input_stub),
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wheel_delta_x_(0),
19558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      wheel_delta_y_(0),
20558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      wheel_ticks_x_(0),
21558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      wheel_ticks_y_(0) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PepperInputHandler::~PepperInputHandler() {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function to get the USB key code using the Dev InputEvent interface.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint32_t GetUsbKeyCode(pp::KeyboardInputEvent pp_key_event) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PPB_KeyboardInputEvent_Dev* key_event_interface =
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const PPB_KeyboardInputEvent_Dev*>(
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pp::Module::Get()->GetBrowserInterface(
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              PPB_KEYBOARD_INPUT_EVENT_DEV_INTERFACE));
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!key_event_interface)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return key_event_interface->GetUsbKeyCode(pp_key_event.pp_resource());
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (event.GetType()) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We need to return true here or else we'll get a local (plugin) context
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // menu instead of the mouseup event for the right click.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_KEYDOWN:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_KEYUP: {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pp::KeyboardInputEvent pp_key_event(event);
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uint32_t modifiers = event.GetModifiers();
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uint32_t lock_states = 0;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (modifiers & PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY)
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        lock_states |= protocol::KeyEvent::LOCK_STATES_CAPSLOCK;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (modifiers & PP_INPUTEVENT_MODIFIER_NUMLOCKKEY)
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        lock_states |= protocol::KeyEvent::LOCK_STATES_NUMLOCK;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol::KeyEvent key_event;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_event.set_usb_keycode(GetUsbKeyCode(pp_key_event));
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_event.set_pressed(event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN);
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      key_event.set_lock_states(lock_states);
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_stub_->InjectKeyEvent(key_event);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEUP: {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pp::MouseInputEvent pp_mouse_event(event);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      protocol::MouseEvent mouse_event;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (pp_mouse_event.GetButton()) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mouse_event.set_button(protocol::MouseEvent::BUTTON_LEFT);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mouse_event.set_button(protocol::MouseEvent::BUTTON_MIDDLE);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mouse_event.set_button(protocol::MouseEvent::BUTTON_RIGHT);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case PP_INPUTEVENT_MOUSEBUTTON_NONE:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (mouse_event.has_button()) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool is_down = (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mouse_event.set_button_down(is_down);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mouse_event.set_x(pp_mouse_event.GetPosition().x());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mouse_event.set_y(pp_mouse_event.GetPosition().y());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        input_stub_->InjectMouseEvent(mouse_event);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEENTER:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pp::MouseInputEvent pp_mouse_event(event);
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      protocol::MouseEvent mouse_event;
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      mouse_event.set_x(pp_mouse_event.GetPosition().x());
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      mouse_event.set_y(pp_mouse_event.GetPosition().y());
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      input_stub_->InjectMouseEvent(mouse_event);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_WHEEL: {
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pp::WheelInputEvent pp_wheel_event(event);
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Don't handle scroll-by-page events, for now.
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (pp_wheel_event.GetScrollByPage())
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return false;
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
112558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // Add this event to our accumulated sub-pixel deltas and clicks.
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      pp::FloatPoint delta = pp_wheel_event.GetDelta();
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      wheel_delta_x_ += delta.x();
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      wheel_delta_y_ += delta.y();
116558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      pp::FloatPoint ticks = pp_wheel_event.GetTicks();
117558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      wheel_ticks_x_ += ticks.x();
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      wheel_ticks_y_ += ticks.y();
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
120558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // If there is at least a pixel's movement, emit an event. We don't
121558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // ever expect to accumulate one tick's worth of scrolling without
122558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      // accumulating a pixel's worth at the same time, so this is safe.
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int delta_x = static_cast<int>(wheel_delta_x_);
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int delta_y = static_cast<int>(wheel_delta_y_);
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (delta_x != 0 || delta_y != 0) {
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        wheel_delta_x_ -= delta_x;
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        wheel_delta_y_ -= delta_y;
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        protocol::MouseEvent mouse_event;
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mouse_event.set_wheel_delta_x(delta_x);
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mouse_event.set_wheel_delta_y(delta_y);
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
132558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // Always include the ticks in the event, even if insufficient pixel
133558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // scrolling has accumulated for a single tick. This informs hosts
134558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // that can't inject pixel-based scroll events that the client will
135558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // accumulate them into tick-based scrolling, which gives a better
136558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        // overall experience than trying to do this host-side.
137558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        int ticks_x = static_cast<int>(wheel_ticks_x_);
138558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        int ticks_y = static_cast<int>(wheel_ticks_y_);
139558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        wheel_ticks_x_ -= ticks_x;
140558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        wheel_ticks_y_ -= ticks_y;
141558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        mouse_event.set_wheel_ticks_x(ticks_x);
142558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        mouse_event.set_wheel_ticks_y(ticks_y);
143558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        input_stub_->InjectMouseEvent(mouse_event);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case PP_INPUTEVENT_TYPE_CHAR:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Consume but ignore character input events.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(INFO) << "Unhandled input event: " << event.GetType();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
163