Home | History | Annotate | Download | only in plugin
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "remoting/client/plugin/pepper_input_handler.h"
      6 
      7 #include "base/logging.h"
      8 #include "ppapi/c/dev/ppb_keyboard_input_event_dev.h"
      9 #include "ppapi/cpp/input_event.h"
     10 #include "ppapi/cpp/module_impl.h"
     11 #include "ppapi/cpp/point.h"
     12 #include "remoting/proto/event.pb.h"
     13 
     14 namespace remoting {
     15 
     16 PepperInputHandler::PepperInputHandler(protocol::InputStub* input_stub)
     17     : input_stub_(input_stub),
     18       wheel_delta_x_(0),
     19       wheel_delta_y_(0),
     20       wheel_ticks_x_(0),
     21       wheel_ticks_y_(0) {
     22 }
     23 
     24 PepperInputHandler::~PepperInputHandler() {
     25 }
     26 
     27 // Helper function to get the USB key code using the Dev InputEvent interface.
     28 uint32_t GetUsbKeyCode(pp::KeyboardInputEvent pp_key_event) {
     29   const PPB_KeyboardInputEvent_Dev* key_event_interface =
     30       reinterpret_cast<const PPB_KeyboardInputEvent_Dev*>(
     31           pp::Module::Get()->GetBrowserInterface(
     32               PPB_KEYBOARD_INPUT_EVENT_DEV_INTERFACE));
     33   if (!key_event_interface)
     34     return 0;
     35   return key_event_interface->GetUsbKeyCode(pp_key_event.pp_resource());
     36 }
     37 
     38 bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) {
     39   switch (event.GetType()) {
     40     case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
     41       // We need to return true here or else we'll get a local (plugin) context
     42       // menu instead of the mouseup event for the right click.
     43       return true;
     44     }
     45 
     46     case PP_INPUTEVENT_TYPE_KEYDOWN:
     47     case PP_INPUTEVENT_TYPE_KEYUP: {
     48       pp::KeyboardInputEvent pp_key_event(event);
     49       uint32_t modifiers = event.GetModifiers();
     50       uint32_t lock_states = 0;
     51 
     52       if (modifiers & PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY)
     53         lock_states |= protocol::KeyEvent::LOCK_STATES_CAPSLOCK;
     54 
     55       if (modifiers & PP_INPUTEVENT_MODIFIER_NUMLOCKKEY)
     56         lock_states |= protocol::KeyEvent::LOCK_STATES_NUMLOCK;
     57 
     58       protocol::KeyEvent key_event;
     59       key_event.set_usb_keycode(GetUsbKeyCode(pp_key_event));
     60       key_event.set_pressed(event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN);
     61       key_event.set_lock_states(lock_states);
     62 
     63       input_stub_->InjectKeyEvent(key_event);
     64       return true;
     65     }
     66 
     67     case PP_INPUTEVENT_TYPE_MOUSEDOWN:
     68     case PP_INPUTEVENT_TYPE_MOUSEUP: {
     69       pp::MouseInputEvent pp_mouse_event(event);
     70       protocol::MouseEvent mouse_event;
     71       switch (pp_mouse_event.GetButton()) {
     72         case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
     73           mouse_event.set_button(protocol::MouseEvent::BUTTON_LEFT);
     74           break;
     75         case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
     76           mouse_event.set_button(protocol::MouseEvent::BUTTON_MIDDLE);
     77           break;
     78         case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
     79           mouse_event.set_button(protocol::MouseEvent::BUTTON_RIGHT);
     80           break;
     81         case PP_INPUTEVENT_MOUSEBUTTON_NONE:
     82           break;
     83       }
     84       if (mouse_event.has_button()) {
     85         bool is_down = (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN);
     86         mouse_event.set_button_down(is_down);
     87         mouse_event.set_x(pp_mouse_event.GetPosition().x());
     88         mouse_event.set_y(pp_mouse_event.GetPosition().y());
     89         input_stub_->InjectMouseEvent(mouse_event);
     90       }
     91       return true;
     92     }
     93 
     94     case PP_INPUTEVENT_TYPE_MOUSEMOVE:
     95     case PP_INPUTEVENT_TYPE_MOUSEENTER:
     96     case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
     97       pp::MouseInputEvent pp_mouse_event(event);
     98       protocol::MouseEvent mouse_event;
     99       mouse_event.set_x(pp_mouse_event.GetPosition().x());
    100       mouse_event.set_y(pp_mouse_event.GetPosition().y());
    101       input_stub_->InjectMouseEvent(mouse_event);
    102       return true;
    103     }
    104 
    105     case PP_INPUTEVENT_TYPE_WHEEL: {
    106       pp::WheelInputEvent pp_wheel_event(event);
    107 
    108       // Don't handle scroll-by-page events, for now.
    109       if (pp_wheel_event.GetScrollByPage())
    110         return false;
    111 
    112       // Add this event to our accumulated sub-pixel deltas and clicks.
    113       pp::FloatPoint delta = pp_wheel_event.GetDelta();
    114       wheel_delta_x_ += delta.x();
    115       wheel_delta_y_ += delta.y();
    116       pp::FloatPoint ticks = pp_wheel_event.GetTicks();
    117       wheel_ticks_x_ += ticks.x();
    118       wheel_ticks_y_ += ticks.y();
    119 
    120       // If there is at least a pixel's movement, emit an event. We don't
    121       // ever expect to accumulate one tick's worth of scrolling without
    122       // accumulating a pixel's worth at the same time, so this is safe.
    123       int delta_x = static_cast<int>(wheel_delta_x_);
    124       int delta_y = static_cast<int>(wheel_delta_y_);
    125       if (delta_x != 0 || delta_y != 0) {
    126         wheel_delta_x_ -= delta_x;
    127         wheel_delta_y_ -= delta_y;
    128         protocol::MouseEvent mouse_event;
    129         mouse_event.set_wheel_delta_x(delta_x);
    130         mouse_event.set_wheel_delta_y(delta_y);
    131 
    132         // Always include the ticks in the event, even if insufficient pixel
    133         // scrolling has accumulated for a single tick. This informs hosts
    134         // that can't inject pixel-based scroll events that the client will
    135         // accumulate them into tick-based scrolling, which gives a better
    136         // overall experience than trying to do this host-side.
    137         int ticks_x = static_cast<int>(wheel_ticks_x_);
    138         int ticks_y = static_cast<int>(wheel_ticks_y_);
    139         wheel_ticks_x_ -= ticks_x;
    140         wheel_ticks_y_ -= ticks_y;
    141         mouse_event.set_wheel_ticks_x(ticks_x);
    142         mouse_event.set_wheel_ticks_y(ticks_y);
    143 
    144         input_stub_->InjectMouseEvent(mouse_event);
    145       }
    146       return true;
    147     }
    148 
    149     case PP_INPUTEVENT_TYPE_CHAR:
    150       // Consume but ignore character input events.
    151       return true;
    152 
    153     default: {
    154       LOG(INFO) << "Unhandled input event: " << event.GetType();
    155       break;
    156     }
    157   }
    158 
    159   return false;
    160 }
    161 
    162 }  // namespace remoting
    163