• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/normalizing_input_filter_mac.h"
6 
7 #include <map>
8 #include <vector>
9 
10 #include "base/logging.h"
11 #include "remoting/proto/event.pb.h"
12 
13 namespace remoting {
14 
15 namespace {
16 
17 const unsigned int kUsbCapsLock     = 0x070039;
18 const unsigned int kUsbLeftControl  = 0x0700e0;
19 const unsigned int kUsbLeftShift    = 0x0700e1;
20 const unsigned int kUsbLeftOption   = 0x0700e2;
21 const unsigned int kUsbLeftCmd      = 0x0700e3;
22 const unsigned int kUsbRightControl = 0x0700e4;
23 const unsigned int kUsbRightShift   = 0x0700e5;
24 const unsigned int kUsbRightOption  = 0x0700e6;
25 const unsigned int kUsbRightCmd     = 0x0700e7;
26 const unsigned int kUsbTab          = 0x07002b;
27 
28 }  // namespace
29 
NormalizingInputFilterMac(protocol::InputStub * input_stub)30 NormalizingInputFilterMac::NormalizingInputFilterMac(
31     protocol::InputStub* input_stub)
32     : protocol::InputFilter(input_stub) {
33 }
34 
~NormalizingInputFilterMac()35 NormalizingInputFilterMac::~NormalizingInputFilterMac() {}
36 
InjectKeyEvent(const protocol::KeyEvent & event)37 void NormalizingInputFilterMac::InjectKeyEvent(const protocol::KeyEvent& event)
38 {
39   DCHECK(event.has_usb_keycode());
40 
41   bool is_special_key = event.usb_keycode() == kUsbLeftControl ||
42       event.usb_keycode() == kUsbLeftShift ||
43       event.usb_keycode() == kUsbLeftOption ||
44       event.usb_keycode() == kUsbRightControl ||
45       event.usb_keycode() == kUsbRightShift ||
46       event.usb_keycode() == kUsbRightOption ||
47       event.usb_keycode() == kUsbTab;
48 
49   bool is_cmd_key = event.usb_keycode() == kUsbLeftCmd ||
50       event.usb_keycode() == kUsbRightCmd;
51 
52   if (event.usb_keycode() == kUsbCapsLock) {
53     // Mac OS X generates keydown/keyup on lock-state transitions, rather than
54     // when the key is pressed & released, so fake keydown/keyup on each event.
55     protocol::KeyEvent newEvent(event);
56 
57     newEvent.set_pressed(true);
58     InputFilter::InjectKeyEvent(newEvent);
59     newEvent.set_pressed(false);
60     InputFilter::InjectKeyEvent(newEvent);
61 
62     return;
63   } else if (!is_cmd_key && !is_special_key) {
64     // Track keydown/keyup events for non-modifiers, so we can release them if
65     // necessary (see below).
66     if (event.pressed()) {
67       key_pressed_map_[event.usb_keycode()] = event;
68     } else {
69       key_pressed_map_.erase(event.usb_keycode());
70     }
71   }
72 
73   if (is_cmd_key && !event.pressed()) {
74     // Mac OS X will not generate release events for keys pressed while Cmd is
75     // pressed, so release all pressed keys when Cmd is released.
76     GenerateKeyupEvents();
77   }
78 
79   InputFilter::InjectKeyEvent(event);
80 }
81 
GenerateKeyupEvents()82 void NormalizingInputFilterMac::GenerateKeyupEvents() {
83   for (KeyPressedMap::iterator i = key_pressed_map_.begin();
84        i != key_pressed_map_.end(); ++i) {
85     // The generated key up event will have the same key code and lock states
86     // as the original key down event.
87     protocol::KeyEvent event = i->second;
88     event.set_pressed(false);
89     InputFilter::InjectKeyEvent(event);
90   }
91 
92   // Clearing the map now that we have released all the pressed keys.
93   key_pressed_map_.clear();
94 }
95 
96 }  // namespace remoting
97