1 /*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2012-2016 Symless Ltd.
4 * Copyright (C) 2004 Chris Schoeneman
5 *
6 * This package is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * found in the file LICENSE that should have accompanied this file.
9 *
10 * This package is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "platform/MSWindowsEventQueueBuffer.h"
20
21 #include "arch/win32/ArchMiscWindows.h"
22 #include "mt/Thread.h"
23 #include "base/IEventQueue.h"
24
25 //
26 // EventQueueTimer
27 //
28
29 class EventQueueTimer { };
30
31
32 //
33 // MSWindowsEventQueueBuffer
34 //
35
MSWindowsEventQueueBuffer(IEventQueue * events)36 MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) :
37 m_events(events)
38 {
39 // remember thread. we'll be posting messages to it.
40 m_thread = GetCurrentThreadId();
41
42 // create a message type for custom events
43 m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT");
44
45 // get message type for daemon quit
46 m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage();
47
48 // make sure this thread has a message queue
49 MSG dummy;
50 PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
51 }
52
~MSWindowsEventQueueBuffer()53 MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer()
54 {
55 // do nothing
56 }
57
58 void
waitForEvent(double timeout)59 MSWindowsEventQueueBuffer::waitForEvent(double timeout)
60 {
61 // check if messages are available first. if we don't do this then
62 // MsgWaitForMultipleObjects() will block even if the queue isn't
63 // empty if the messages in the queue were there before the last
64 // call to GetMessage()/PeekMessage().
65 if (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) != 0) {
66 return;
67 }
68
69 // convert timeout
70 DWORD t;
71 if (timeout < 0.0) {
72 t = INFINITE;
73 }
74 else {
75 t = (DWORD)(1000.0 * timeout);
76 }
77
78 // wait for a message. we cannot be interrupted by thread
79 // cancellation but that's okay because we're run in the main
80 // thread and we never cancel that thread.
81 HANDLE dummy[1];
82 MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLPOSTMESSAGE);
83 }
84
85 IEventQueueBuffer::Type
getEvent(Event & event,UInt32 & dataID)86 MSWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID)
87 {
88 // NOTE: QS_ALLINPUT was replaced with QS_ALLPOSTMESSAGE.
89 //
90 // peek at messages first. waiting for QS_ALLINPUT will return
91 // if a message has been sent to our window but GetMessage will
92 // dispatch that message behind our backs and block. PeekMessage
93 // will also dispatch behind our backs but won't block.
94 if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) &&
95 !PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) {
96 return kNone;
97 }
98
99 // BOOL. yeah, right.
100 BOOL result = GetMessage(&m_event, NULL, 0, 0);
101 if (result == -1) {
102 return kNone;
103 }
104 else if (result == 0) {
105 event = Event(Event::kQuit);
106 return kSystem;
107 }
108 else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) {
109 event = Event(Event::kQuit);
110 return kSystem;
111 }
112 else if (m_event.message == m_userEvent) {
113 dataID = static_cast<UInt32>(m_event.wParam);
114 return kUser;
115 }
116 else {
117 event = Event(Event::kSystem,
118 m_events->getSystemTarget(), &m_event);
119 return kSystem;
120 }
121 }
122
123 bool
addEvent(UInt32 dataID)124 MSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
125 {
126 return (PostThreadMessage(m_thread, m_userEvent,
127 static_cast<WPARAM>(dataID), 0) != 0);
128 }
129
130 bool
isEmpty() const131 MSWindowsEventQueueBuffer::isEmpty() const
132 {
133 return (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) == 0);
134 }
135
136 EventQueueTimer*
newTimer(double,bool) const137 MSWindowsEventQueueBuffer::newTimer(double, bool) const
138 {
139 return new EventQueueTimer;
140 }
141
142 void
deleteTimer(EventQueueTimer * timer) const143 MSWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const
144 {
145 delete timer;
146 }
147