blob: 1cab662afa856bf8258991ac8c1894a8bcc0270e [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2003 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#define WIN32_LEAN_AND_MEAN
20#include <windows.h>
21
22#include <rfb/LogWriter.h>
23#include <rfb_win32/CPointer.h>
24
25using namespace rfb;
26using namespace win32;
27
28static LogWriter vlog("CPointer");
29
30
31CPointer::CPointer() : currButtonMask(0), intervalQueued(false), threeEmulating(false) {
32}
33
34CPointer::~CPointer() {
35 intervalTimer.stop();
36 threeTimer.stop();
37}
38
39
40void CPointer::pointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
41 //
42 // - Duplicate Event Filtering
43 //
44
45 bool maskChanged = buttonMask != currButtonMask;
46 bool posChanged = !Point(x, y).equals(currPos);
47 if (!(posChanged || maskChanged))
48 return;
49
50 // Pass on the event to the event-interval handler
51 threePointerEvent(writer, x, y, buttonMask);
52
53 // Save the position and mask
54 currPos = Point(x, y);
55 currButtonMask = buttonMask;
56}
57
58
59inline abs(int x) {return x>0 ? x : 0;}
60
61int emulate3Mask(int buttonMask) {
62 // - Release left & right and press middle
63 vlog.debug("emulate3: active");
64 buttonMask &= ~5;
65 buttonMask |= 2;
66 return buttonMask;
67}
68
69void CPointer::threePointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
70 //
71 // - 3-Button Mouse Emulation
72 //
73
74 if (emulate3) {
75
76 bool leftChanged = (buttonMask & 1) != (currButtonMask & 1);
77 bool rightChanged = (buttonMask & 4) != (currButtonMask & 4);
78
79 if (leftChanged || rightChanged) {
80 // - One of left or right have changed
81
82 if ((buttonMask & 5) == 1 || (buttonMask & 5) == 4) {
83 // - One is up, one is down. Start a timer, so that if it
84 // expires then we know we should actually send this event
85 vlog.debug("emulate3: start timer");
86 threeTimer.start(100);
87 threePos = Point(x, y);
88 threeMask = buttonMask;
89 return;
90
91 } else if (threeTimer.isActive()) {
92 // - Both are up or both are down, and we were timing for an emulation event
93 // Stop the timer and flush the stored event
94 vlog.debug("emulate3: stop timer (state)");
95 threeTimer.stop();
96 if (threeEmulating == ((buttonMask & 5) == 5))
97 intervalPointerEvent(writer, threePos.x, threePos.y, threeMask);
98 else
99 threeEmulating = ((buttonMask & 5) == 5);
100 }
101
102 } else {
103
104 if (threeTimer.isActive()) {
105 // - We are timing for an emulation event
106
107 if (abs(threePos.x - x) <= 4 || abs(threePos.y - y) <= 4) {
108 // If the mouse has moved too far since the button-change event then flush
109 vlog.debug("emulate3: stop timer (moved)");
110 threeTimer.stop();
111 intervalPointerEvent(writer, threePos.x, threePos.y, threeMask);
112
113 } else {
114 // Otherwise, we ignore the new event
115 return;
116 }
117 }
118
119 }
120
121 // - If neither left nor right are down, stop emulating
122 if ((buttonMask & 5) == 0)
123 threeEmulating = false;
124
125 // - If emulating, release left & right and press middle
126 if (threeEmulating)
127 buttonMask = emulate3Mask(buttonMask);
128
129 }
130
131 // - Let the event pass through to the next stage of processing
132 intervalPointerEvent(writer, x, y, buttonMask);
133}
134
135void CPointer::intervalPointerEvent(CMsgWriter* writer, int x, int y, int buttonMask) {
136 //
137 // - Pointer Event Interval
138 //
139 vlog.write(101, "ptrEvent: %d,%d (%lx)", x, y, buttonMask);
140
141 // Send the event immediately if we haven't sent one for a while
142 bool sendNow = !intervalTimer.isActive();
143
144 if (intervalMask != buttonMask) {
145 // If the buttons have changed then flush queued events and send now
146 sendNow = true;
147 if (intervalQueued)
148 writer->writePointerEvent(intervalPos.x, intervalPos.y, intervalMask);
149 intervalQueued = false;
150 }
151
152 if (!sendNow) {
153 // If we're not sending now then just queue the event
154 intervalQueued = true;
155 intervalPos = Point(x, y);
156 intervalMask = buttonMask;
157 } else {
158 // Start the interval timer if required, and send the event
159 intervalQueued = false;
160 intervalMask = buttonMask;
161 if (pointerEventInterval)
162 intervalTimer.start(pointerEventInterval);
163 writer->writePointerEvent(x, y, buttonMask);
164 }
165}
166
167void CPointer::handleTimer(CMsgWriter* writer, int timerId) {
168 if (timerId == intervalTimer.getId()) {
169 // Pointer interval has expired - send any queued events
170 if (intervalQueued) {
171 writer->writePointerEvent(intervalPos.x, intervalPos.y, intervalMask);
172 intervalQueued = false;
173 } else {
174 intervalTimer.stop();
175 }
176
177 } else if (timerId = threeTimer.getId()) {
178 // 3-Button emulation timer has expired - send what we've got
179 vlog.debug("emulate3: timeout");
180 threeTimer.stop();
181
182 // If emulating, release left & right and press middle
183 if (threeEmulating)
184 threeMask = emulate3Mask(threeMask);
185
186 intervalPointerEvent(writer, threePos.x, threePos.y, threeMask);
187 }
188}