blob: 3d0d9342540dedeecd5d85cb1a6a3cf6bb13af0b [file] [log] [blame]
Constantin Kaplinsky729598c2006-05-25 05:12:25 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <windows.h>
20#include <rfb/LogWriter.h>
21#include <rfb_win32/CPointer.h>
22
23using namespace rfb;
24using namespace win32;
25
26static LogWriter vlog("CPointer");
27
28
29CPointer::CPointer() : currButtonMask(0), intervalQueued(false), threeEmulating(false) {
30}
31
32CPointer::~CPointer() {
33 intervalTimer.stop();
34 threeTimer.stop();
35}
36
37
38void CPointer::pointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
39 //
40 // - Duplicate Event Filtering
41 //
42
43 bool maskChanged = buttonMask != currButtonMask;
44 bool posChanged = !pos.equals(currPos);
45 if (!(posChanged || maskChanged))
46 return;
47
48 // Pass on the event to the event-interval handler
49 threePointerEvent(writer, pos, buttonMask);
50
51 // Save the position and mask
52 currPos = pos;
53 currButtonMask = buttonMask;
54}
55
56
57inline abs(int x) {return x>0 ? x : 0;}
58
59int emulate3Mask(int buttonMask) {
60 // - Release left & right and press middle
61 vlog.debug("emulate3: active");
62 buttonMask &= ~5;
63 buttonMask |= 2;
64 return buttonMask;
65}
66
67void CPointer::threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
68 //
69 // - 3-Button Mouse Emulation
70 //
71
72 if (emulate3) {
73
74 bool leftChanged = (buttonMask & 1) != (currButtonMask & 1);
75 bool rightChanged = (buttonMask & 4) != (currButtonMask & 4);
76
77 if (leftChanged || rightChanged) {
78 // - One of left or right have changed
79
80 if ((buttonMask & 5) == 1 || (buttonMask & 5) == 4) {
81 // - One is up, one is down. Start a timer, so that if it
82 // expires then we know we should actually send this event
83 vlog.debug("emulate3: start timer");
84 threeTimer.start(100);
85 threePos = pos;
86 threeMask = buttonMask;
87 return;
88
89 } else if (threeTimer.isActive()) {
90 // - Both are up or both are down, and we were timing for an emulation event
91 // Stop the timer and flush the stored event
92 vlog.debug("emulate3: stop timer (state)");
93 threeTimer.stop();
94 if (threeEmulating == ((buttonMask & 5) == 5))
95 intervalPointerEvent(writer, threePos, threeMask);
96 else
97 threeEmulating = ((buttonMask & 5) == 5);
98 }
99
100 } else {
101
102 if (threeTimer.isActive()) {
103 // - We are timing for an emulation event
104
105 if (abs(threePos.x - pos.x) <= 4 || abs(threePos.y - pos.y) <= 4) {
106 // If the mouse has moved too far since the button-change event then flush
107 vlog.debug("emulate3: stop timer (moved)");
108 threeTimer.stop();
109 intervalPointerEvent(writer, threePos, threeMask);
110
111 } else {
112 // Otherwise, we ignore the new event
113 return;
114 }
115 }
116
117 }
118
119 // - If neither left nor right are down, stop emulating
120 if ((buttonMask & 5) == 0)
121 threeEmulating = false;
122
123 // - If emulating, release left & right and press middle
124 if (threeEmulating)
125 buttonMask = emulate3Mask(buttonMask);
126
127 }
128
129 // - Let the event pass through to the next stage of processing
130 intervalPointerEvent(writer, pos, buttonMask);
131}
132
133void CPointer::intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask) {
134 //
135 // - Pointer Event Interval
136 //
137 vlog.write(101, "ptrEvent: %d,%d (%lx)", pos.x, pos.y, buttonMask);
138
139 // Send the event immediately if we haven't sent one for a while
140 bool sendNow = !intervalTimer.isActive();
141
142 if (intervalMask != buttonMask) {
143 // If the buttons have changed then flush queued events and send now
144 sendNow = true;
145 if (intervalQueued)
146 writer->pointerEvent(intervalPos, intervalMask);
147 intervalQueued = false;
148 }
149
150 if (!sendNow) {
151 // If we're not sending now then just queue the event
152 intervalQueued = true;
153 intervalPos = pos;
154 intervalMask = buttonMask;
155 } else {
156 // Start the interval timer if required, and send the event
157 intervalQueued = false;
158 intervalMask = buttonMask;
159 if (pointerEventInterval)
160 intervalTimer.start(pointerEventInterval);
161 writer->pointerEvent(pos, buttonMask);
162 }
163}
164
165void CPointer::handleTimer(InputHandler* writer, int timerId) {
166 if (timerId == intervalTimer.getId()) {
167 // Pointer interval has expired - send any queued events
168 if (intervalQueued) {
169 writer->pointerEvent(intervalPos, intervalMask);
170 intervalQueued = false;
171 } else {
172 intervalTimer.stop();
173 }
174
175 } else if (timerId = threeTimer.getId()) {
176 // 3-Button emulation timer has expired - send what we've got
177 vlog.debug("emulate3: timeout");
178 threeTimer.stop();
179
180 // If emulating, release left & right and press middle
181 if (threeEmulating)
182 threeMask = emulate3Mask(threeMask);
183
184 intervalPointerEvent(writer, threePos, threeMask);
185 }
186}