[email protected] | c2b37440 | 2012-03-12 19:23:07 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 5 | #include "remoting/host/event_executor.h" |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 6 | |
| 7 | #include <windows.h> |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 8 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 9 | #include "base/bind.h" |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 10 | #include "base/compiler_specific.h" |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 11 | #include "base/message_loop.h" |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 12 | #include "base/message_loop_proxy.h" |
[email protected] | 411fd1d3 | 2010-08-31 15:56:05 | [diff] [blame] | 13 | #include "remoting/host/capturer.h" |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 14 | #include "remoting/host/clipboard.h" |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 15 | #include "remoting/proto/event.pb.h" |
[email protected] | b6d8126 | 2011-01-13 17:36:09 | [diff] [blame] | 16 | #include "ui/base/keycodes/keyboard_codes.h" |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 17 | |
| 18 | namespace remoting { |
| 19 | |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 20 | namespace { |
| 21 | |
[email protected] | e265ad7 | 2012-03-16 17:28:03 | [diff] [blame] | 22 | using protocol::ClipboardEvent; |
[email protected] | 2c22968 | 2010-12-02 20:23:35 | [diff] [blame] | 23 | using protocol::KeyEvent; |
[email protected] | e265ad7 | 2012-03-16 17:28:03 | [diff] [blame] | 24 | using protocol::MouseEvent; |
[email protected] | 2c22968 | 2010-12-02 20:23:35 | [diff] [blame] | 25 | |
[email protected] | 1a6258f | 2012-03-15 21:16:47 | [diff] [blame] | 26 | // USB to XKB keycode map table. |
| 27 | #define USB_KEYMAP(usb, xkb, win, mac) {usb, win} |
[email protected] | 1a6258f | 2012-03-15 21:16:47 | [diff] [blame] | 28 | #include "remoting/host/usb_keycode_map.h" |
| 29 | #undef USB_KEYMAP |
| 30 | |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 31 | // A class to generate events on Windows. |
| 32 | class EventExecutorWin : public EventExecutor { |
| 33 | public: |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 34 | EventExecutorWin(MessageLoop* message_loop, |
| 35 | base::MessageLoopProxy* ui_loop, |
| 36 | Capturer* capturer); |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 37 | virtual ~EventExecutorWin() {} |
| 38 | |
[email protected] | e265ad7 | 2012-03-16 17:28:03 | [diff] [blame] | 39 | // ClipboardStub interface. |
| 40 | virtual void InjectClipboardEvent(const ClipboardEvent& event) OVERRIDE; |
| 41 | |
| 42 | // InputStub interface. |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 43 | virtual void InjectKeyEvent(const KeyEvent& event) OVERRIDE; |
| 44 | virtual void InjectMouseEvent(const MouseEvent& event) OVERRIDE; |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 45 | |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 46 | // EventExecutor interface. |
| 47 | virtual void OnSessionStarted() OVERRIDE; |
| 48 | virtual void OnSessionFinished() OVERRIDE; |
| 49 | |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 50 | private: |
[email protected] | eb8d92e | 2012-04-04 03:33:43 | [diff] [blame] | 51 | HKL GetForegroundKeyboardLayout(); |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 52 | void HandleKey(const KeyEvent& event); |
| 53 | void HandleMouse(const MouseEvent& event); |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 54 | |
[email protected] | 1a6cdf4 | 2011-05-18 07:41:01 | [diff] [blame] | 55 | MessageLoop* message_loop_; |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 56 | base::MessageLoopProxy* ui_loop_; |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 57 | Capturer* capturer_; |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 58 | scoped_ptr<Clipboard> clipboard_; |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 59 | |
| 60 | DISALLOW_COPY_AND_ASSIGN(EventExecutorWin); |
| 61 | }; |
| 62 | |
[email protected] | 1a6cdf4 | 2011-05-18 07:41:01 | [diff] [blame] | 63 | EventExecutorWin::EventExecutorWin(MessageLoop* message_loop, |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 64 | base::MessageLoopProxy* ui_loop, |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 65 | Capturer* capturer) |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 66 | : message_loop_(message_loop), |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 67 | ui_loop_(ui_loop), |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 68 | capturer_(capturer), |
| 69 | clipboard_(Clipboard::Create()) { |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 70 | } |
| 71 | |
[email protected] | e265ad7 | 2012-03-16 17:28:03 | [diff] [blame] | 72 | void EventExecutorWin::InjectClipboardEvent(const ClipboardEvent& event) { |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 73 | if (!ui_loop_->BelongsToCurrentThread()) { |
| 74 | ui_loop_->PostTask( |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 75 | FROM_HERE, |
| 76 | base::Bind(&EventExecutorWin::InjectClipboardEvent, |
| 77 | base::Unretained(this), |
| 78 | event)); |
| 79 | return; |
| 80 | } |
| 81 | |
| 82 | clipboard_->InjectClipboardEvent(event); |
[email protected] | e265ad7 | 2012-03-16 17:28:03 | [diff] [blame] | 83 | } |
| 84 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 85 | void EventExecutorWin::InjectKeyEvent(const KeyEvent& event) { |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 86 | if (MessageLoop::current() != message_loop_) { |
| 87 | message_loop_->PostTask( |
| 88 | FROM_HERE, |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 89 | base::Bind(&EventExecutorWin::InjectKeyEvent, base::Unretained(this), |
| 90 | event)); |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 91 | return; |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 92 | } |
[email protected] | 825c428 | 2011-04-21 23:46:57 | [diff] [blame] | 93 | |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 94 | HandleKey(event); |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 95 | } |
| 96 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 97 | void EventExecutorWin::InjectMouseEvent(const MouseEvent& event) { |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 98 | if (MessageLoop::current() != message_loop_) { |
| 99 | message_loop_->PostTask( |
| 100 | FROM_HERE, |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 101 | base::Bind(&EventExecutorWin::InjectMouseEvent, base::Unretained(this), |
| 102 | event)); |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 103 | return; |
| 104 | } |
[email protected] | 825c428 | 2011-04-21 23:46:57 | [diff] [blame] | 105 | |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 106 | HandleMouse(event); |
[email protected] | 6fd3d6a1 | 2010-11-16 19:53:35 | [diff] [blame] | 107 | } |
| 108 | |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 109 | void EventExecutorWin::OnSessionStarted() { |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 110 | if (!ui_loop_->BelongsToCurrentThread()) { |
| 111 | ui_loop_->PostTask( |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 112 | FROM_HERE, |
| 113 | base::Bind(&EventExecutorWin::OnSessionStarted, |
| 114 | base::Unretained(this))); |
| 115 | return; |
| 116 | } |
| 117 | |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 118 | clipboard_->Start(); |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | void EventExecutorWin::OnSessionFinished() { |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 122 | if (!ui_loop_->BelongsToCurrentThread()) { |
| 123 | ui_loop_->PostTask( |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 124 | FROM_HERE, |
| 125 | base::Bind(&EventExecutorWin::OnSessionFinished, |
| 126 | base::Unretained(this))); |
| 127 | return; |
| 128 | } |
| 129 | |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 130 | clipboard_->Stop(); |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 131 | } |
| 132 | |
[email protected] | eb8d92e | 2012-04-04 03:33:43 | [diff] [blame] | 133 | HKL EventExecutorWin::GetForegroundKeyboardLayout() { |
| 134 | HKL layout = 0; |
| 135 | |
| 136 | // Can return NULL if a window is losing focus. |
| 137 | HWND foreground = GetForegroundWindow(); |
| 138 | if (foreground) { |
| 139 | // Can return 0 if the window no longer exists. |
| 140 | DWORD thread_id = GetWindowThreadProcessId(foreground, 0); |
| 141 | if (thread_id) { |
| 142 | // Can return 0 if the thread no longer exists, or if we're |
| 143 | // running on Windows Vista and the window is a command-prompt. |
| 144 | layout = GetKeyboardLayout(thread_id); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | // If we couldn't determine a layout then use the system default. |
| 149 | if (!layout) { |
| 150 | SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, &layout, 0); |
| 151 | } |
| 152 | |
| 153 | return layout; |
| 154 | } |
| 155 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 156 | void EventExecutorWin::HandleKey(const KeyEvent& event) { |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 157 | // HostEventDispatcher should filter events missing the pressed field. |
| 158 | DCHECK(event.has_pressed()); |
| 159 | |
[email protected] | 6aaebcf | 2012-04-03 05:34:27 | [diff] [blame] | 160 | // Reset the system idle suspend timeout. |
| 161 | SetThreadExecutionState(ES_SYSTEM_REQUIRED); |
[email protected] | 3fb79318 | 2010-10-15 22:07:20 | [diff] [blame] | 162 | |
[email protected] | eb8d92e | 2012-04-04 03:33:43 | [diff] [blame] | 163 | // The mapping between scancodes and VKEY values depends on the foreground |
| 164 | // window's current keyboard layout. |
| 165 | HKL layout = GetForegroundKeyboardLayout(); |
| 166 | |
[email protected] | 6d42bdce | 2012-04-24 22:21:14 | [diff] [blame] | 167 | // Populate the a Windows INPUT structure for the event. |
| 168 | INPUT input; |
| 169 | memset(&input, 0, sizeof(input)); |
| 170 | input.type = INPUT_KEYBOARD; |
| 171 | input.ki.time = 0; |
| 172 | input.ki.dwFlags = event.pressed() ? 0 : KEYEVENTF_KEYUP; |
| 173 | |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 174 | int scancode = kInvalidKeycode; |
| 175 | if (event.has_usb_keycode()) { |
[email protected] | eb8d92e | 2012-04-04 03:33:43 | [diff] [blame] | 176 | // If the event contains a USB-style code, map to a Windows scancode, and |
[email protected] | 6d42bdce | 2012-04-24 22:21:14 | [diff] [blame] | 177 | // set a flag to have Windows look up the corresponding VK code. |
| 178 | input.ki.dwFlags |= KEYEVENTF_SCANCODE; |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 179 | scancode = UsbKeycodeToNativeKeycode(event.usb_keycode()); |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 180 | VLOG(3) << "Converting USB keycode: " << std::hex << event.usb_keycode() |
[email protected] | 6d42bdce | 2012-04-24 22:21:14 | [diff] [blame] | 181 | << " to scancode: " << scancode << std::dec; |
[email protected] | 1a6258f | 2012-03-15 21:16:47 | [diff] [blame] | 182 | } else { |
[email protected] | 6d42bdce | 2012-04-24 22:21:14 | [diff] [blame] | 183 | // If the event provides only a VKEY then use it, and map to the scancode. |
| 184 | input.ki.wVk = event.keycode(); |
| 185 | scancode = MapVirtualKeyEx(event.keycode(), MAPVK_VK_TO_VSC_EX, layout); |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 186 | VLOG(3) << "Converting VKEY: " << std::hex << event.keycode() |
| 187 | << " to scancode: " << scancode << std::dec; |
[email protected] | 1a6258f | 2012-03-15 21:16:47 | [diff] [blame] | 188 | } |
| 189 | |
[email protected] | 1ab57f0 | 2012-04-05 20:17:53 | [diff] [blame] | 190 | // Ignore events with no VK- or USB-keycode, or which can't be mapped. |
| 191 | if (scancode == kInvalidKeycode) |
[email protected] | 1a6258f | 2012-03-15 21:16:47 | [diff] [blame] | 192 | return; |
[email protected] | 3fb79318 | 2010-10-15 22:07:20 | [diff] [blame] | 193 | |
[email protected] | 6d42bdce | 2012-04-24 22:21:14 | [diff] [blame] | 194 | // Windows scancodes are only 8-bit, so store the low-order byte into the |
| 195 | // event and set the extended flag if any high-order bits are set. The only |
| 196 | // high-order values we should see are 0xE0 or 0xE1. The extended bit usually |
| 197 | // distinguishes keys with the same meaning, e.g. left & right shift. |
| 198 | input.ki.wScan = scancode & 0xFF; |
| 199 | if ((scancode & 0xFF00) != 0x0000) { |
[email protected] | 3fb79318 | 2010-10-15 22:07:20 | [diff] [blame] | 200 | input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; |
| 201 | } |
| 202 | |
[email protected] | 5ae4da1 | 2012-03-17 20:03:57 | [diff] [blame] | 203 | if (SendInput(1, &input, sizeof(INPUT)) == 0) { |
| 204 | LOG_GETLASTERROR(ERROR) << "Failed to inject a key event"; |
| 205 | } |
[email protected] | e5b9fca9 | 2010-08-27 21:19:07 | [diff] [blame] | 206 | } |
| 207 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 208 | void EventExecutorWin::HandleMouse(const MouseEvent& event) { |
[email protected] | 6aaebcf | 2012-04-03 05:34:27 | [diff] [blame] | 209 | // Reset the system idle suspend timeout. |
| 210 | SetThreadExecutionState(ES_SYSTEM_REQUIRED); |
| 211 | |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 212 | // TODO(garykac) Collapse mouse (x,y) and button events into a single |
| 213 | // input event when possible. |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 214 | if (event.has_x() && event.has_y()) { |
| 215 | int x = event.x(); |
| 216 | int y = event.y(); |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 217 | |
| 218 | INPUT input; |
| 219 | input.type = INPUT_MOUSE; |
| 220 | input.mi.time = 0; |
[email protected] | bcad268 | 2011-09-30 20:35:26 | [diff] [blame] | 221 | SkISize screen_size = capturer_->size_most_recent(); |
[email protected] | b691a10 | 2011-10-12 08:54:56 | [diff] [blame] | 222 | if ((screen_size.width() > 1) && (screen_size.height() > 1)) { |
| 223 | input.mi.dx = static_cast<int>((x * 65535) / (screen_size.width() - 1)); |
| 224 | input.mi.dy = static_cast<int>((y * 65535) / (screen_size.height() - 1)); |
[email protected] | e1a6c46 | 2011-03-04 12:15:31 | [diff] [blame] | 225 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; |
[email protected] | 5ae4da1 | 2012-03-17 20:03:57 | [diff] [blame] | 226 | if (SendInput(1, &input, sizeof(INPUT)) == 0) { |
| 227 | LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse move event"; |
| 228 | } |
[email protected] | e1a6c46 | 2011-03-04 12:15:31 | [diff] [blame] | 229 | } |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 230 | } |
| 231 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 232 | if (event.has_wheel_offset_x() && event.has_wheel_offset_y()) { |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 233 | INPUT wheel; |
| 234 | wheel.type = INPUT_MOUSE; |
| 235 | wheel.mi.time = 0; |
| 236 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 237 | int dx = event.wheel_offset_x(); |
| 238 | int dy = event.wheel_offset_y(); |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 239 | |
| 240 | if (dx != 0) { |
[email protected] | cd009921 | 2011-10-17 06:37:25 | [diff] [blame] | 241 | wheel.mi.mouseData = dx * WHEEL_DELTA; |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 242 | wheel.mi.dwFlags = MOUSEEVENTF_HWHEEL; |
[email protected] | 5ae4da1 | 2012-03-17 20:03:57 | [diff] [blame] | 243 | if (SendInput(1, &wheel, sizeof(INPUT)) == 0) { |
| 244 | LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse wheel(x) event"; |
| 245 | } |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 246 | } |
| 247 | if (dy != 0) { |
[email protected] | cd009921 | 2011-10-17 06:37:25 | [diff] [blame] | 248 | wheel.mi.mouseData = dy * WHEEL_DELTA; |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 249 | wheel.mi.dwFlags = MOUSEEVENTF_WHEEL; |
[email protected] | 5ae4da1 | 2012-03-17 20:03:57 | [diff] [blame] | 250 | if (SendInput(1, &wheel, sizeof(INPUT)) == 0) { |
| 251 | LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse wheel(y) event"; |
| 252 | } |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 256 | if (event.has_button() && event.has_button_down()) { |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 257 | INPUT button_event; |
| 258 | button_event.type = INPUT_MOUSE; |
| 259 | button_event.mi.time = 0; |
| 260 | button_event.mi.dx = 0; |
| 261 | button_event.mi.dy = 0; |
| 262 | |
[email protected] | b25ff3b | 2011-09-13 18:17:30 | [diff] [blame] | 263 | MouseEvent::MouseButton button = event.button(); |
| 264 | bool down = event.button_down(); |
[email protected] | 2c22968 | 2010-12-02 20:23:35 | [diff] [blame] | 265 | if (button == MouseEvent::BUTTON_LEFT) { |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 266 | button_event.mi.dwFlags = |
| 267 | down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; |
[email protected] | 2c22968 | 2010-12-02 20:23:35 | [diff] [blame] | 268 | } else if (button == MouseEvent::BUTTON_MIDDLE) { |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 269 | button_event.mi.dwFlags = |
| 270 | down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; |
[email protected] | 2c22968 | 2010-12-02 20:23:35 | [diff] [blame] | 271 | } else if (button == MouseEvent::BUTTON_RIGHT) { |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 272 | button_event.mi.dwFlags = |
| 273 | down ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; |
| 274 | } else { |
| 275 | button_event.mi.dwFlags = |
| 276 | down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; |
| 277 | } |
| 278 | |
[email protected] | 5ae4da1 | 2012-03-17 20:03:57 | [diff] [blame] | 279 | if (SendInput(1, &button_event, sizeof(INPUT)) == 0) { |
| 280 | LOG_GETLASTERROR(ERROR) << "Failed to inject a mouse button event"; |
| 281 | } |
[email protected] | 65f8687 | 2010-11-29 21:56:12 | [diff] [blame] | 282 | } |
| 283 | } |
| 284 | |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 285 | } // namespace |
| 286 | |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 287 | scoped_ptr<EventExecutor> EventExecutor::Create(MessageLoop* message_loop, |
| 288 | base::MessageLoopProxy* ui_loop, |
| 289 | Capturer* capturer) { |
[email protected] | 6d17db9 | 2012-05-11 17:03:14 | [diff] [blame] | 290 | return scoped_ptr<EventExecutor>( |
[email protected] | 98f99a0 | 2012-05-16 18:03:32 | [diff] [blame] | 291 | new EventExecutorWin(message_loop, ui_loop, capturer)); |
[email protected] | 0b7e428 | 2011-04-04 22:44:11 | [diff] [blame] | 292 | } |
| 293 | |
[email protected] | cb3b1f931 | 2010-06-07 19:58:23 | [diff] [blame] | 294 | } // namespace remoting |