1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/local_input_monitor_thread_win.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "remoting/host/mouse_move_observer.h"
#include "third_party/skia/include/core/SkPoint.h"
namespace remoting {
namespace {
LocalInputMonitorThread* g_local_input_monitor_thread = NULL;
base::LazyInstance<base::Lock>::Leaky g_thread_lock = LAZY_INSTANCE_INITIALIZER;
} // namespace
LocalInputMonitorThread::LocalInputMonitorThread()
: base::SimpleThread("LocalInputMonitor") {
}
LocalInputMonitorThread::~LocalInputMonitorThread() {
DCHECK(observers_.empty());
}
void LocalInputMonitorThread::AddObserver(
MouseMoveObserver* mouse_move_observer) {
base::AutoLock lock(lock_);
observers_.insert(mouse_move_observer);
}
bool LocalInputMonitorThread::RemoveObserver(
MouseMoveObserver* mouse_move_observer) {
base::AutoLock lock(lock_);
observers_.erase(mouse_move_observer);
return observers_.empty();
}
void LocalInputMonitorThread::Stop() {
CHECK(PostThreadMessage(tid(), WM_QUIT, 0, 0));
Join();
}
void LocalInputMonitorThread::Run() {
extern HMODULE g_hModule;
HHOOK win_event_hook = SetWindowsHookEx(WH_MOUSE_LL, HandleLowLevelMouseEvent,
g_hModule, 0);
if (!win_event_hook) {
DWORD err = GetLastError();
LOG(ERROR) << "SetWindowHookEx failed: " << err;
return;
}
MSG msg;
BOOL result;
while ((result = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (result == -1) {
DWORD err = GetLastError();
LOG(ERROR) << "GetMessage failed: " << err;
break;
} else {
DispatchMessage(&msg);
}
}
if (win_event_hook) {
CHECK(UnhookWindowsHookEx(win_event_hook));
}
}
void LocalInputMonitorThread::LocalMouseMoved(const SkIPoint& mouse_position) {
base::AutoLock lock(lock_);
for (MouseMoveObservers::const_iterator i = observers_.begin();
i != observers_.end(); ++i) {
(*i)->OnLocalMouseMoved(mouse_position);
}
}
LRESULT WINAPI LocalInputMonitorThread::HandleLowLevelMouseEvent(
int code, WPARAM event_type, LPARAM event_data) {
if (code == HC_ACTION) {
if (event_type == WM_MOUSEMOVE) {
PMSLLHOOKSTRUCT data = reinterpret_cast<PMSLLHOOKSTRUCT>(event_data);
if ((data->flags & LLMHF_INJECTED) == 0) {
SkIPoint mouse_position = SkIPoint::Make(data->pt.x, data->pt.y);
// |g_local_input_monitor_thread| cannot be NULL because this function
// is called from within the GetMessage call running on that thread.
DCHECK(g_local_input_monitor_thread);
g_local_input_monitor_thread->LocalMouseMoved(mouse_position);
}
}
}
return CallNextHookEx(NULL, code, event_type, event_data);
}
// static
void LocalInputMonitorThread::AddMouseMoveObserver(
MouseMoveObserver* mouse_move_observer) {
base::AutoLock lock(g_thread_lock.Get());
if (!g_local_input_monitor_thread) {
g_local_input_monitor_thread = new LocalInputMonitorThread;
g_local_input_monitor_thread->Start();
}
g_local_input_monitor_thread->AddObserver(mouse_move_observer);
}
// static
void LocalInputMonitorThread::RemoveMouseMoveObserver(
MouseMoveObserver* mouse_move_observer) {
DCHECK(g_local_input_monitor_thread);
base::AutoLock lock(g_thread_lock.Get());
if (g_local_input_monitor_thread->RemoveObserver(mouse_move_observer)) {
g_local_input_monitor_thread->Stop();
delete g_local_input_monitor_thread;
g_local_input_monitor_thread = NULL;
}
}
} // namespace remoting
|