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