/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include #include #include using namespace rfb; using namespace win32; static LogWriter vlog("CPointer"); CPointer::CPointer() : currButtonMask(0), intervalQueued(false), threeEmulating(false) { } CPointer::~CPointer() { intervalTimer.stop(); threeTimer.stop(); } void CPointer::pointerEvent(InputHandler* writer, const Point& pos, int buttonMask) { // // - Duplicate Event Filtering // bool maskChanged = buttonMask != currButtonMask; bool posChanged = !pos.equals(currPos); if (!(posChanged || maskChanged)) return; // Pass on the event to the event-interval handler threePointerEvent(writer, pos, buttonMask); // Save the position and mask currPos = pos; currButtonMask = buttonMask; } inline int _abs(int x) {return x>0 ? x : -x;} int emulate3Mask(int buttonMask) { // - Release left & right and press middle vlog.debug("emulate3: active"); buttonMask &= ~5; buttonMask |= 2; return buttonMask; } void CPointer::threePointerEvent(InputHandler* writer, const Point& pos, int buttonMask) { // // - 3-Button Mouse Emulation // if (emulate3) { bool leftChanged = (buttonMask & 1) != (currButtonMask & 1); bool rightChanged = (buttonMask & 4) != (currButtonMask & 4); if (leftChanged || rightChanged) { // - One of left or right have changed if ((buttonMask & 5) == 1 || (buttonMask & 5) == 4) { // - One is up, one is down. Start a timer, so that if it // expires then we know we should actually send this event vlog.debug("emulate3: start timer"); threeTimer.start(100); threePos = pos; threeMask = buttonMask; return; } else if (threeTimer.isActive()) { // - Both are up or both are down, and we were timing for an emulation event // Stop the timer and flush the stored event vlog.debug("emulate3: stop timer (state)"); threeTimer.stop(); if (threeEmulating == ((buttonMask & 5) == 5)) intervalPointerEvent(writer, threePos, threeMask); else threeEmulating = ((buttonMask & 5) == 5); } } else { if (threeTimer.isActive()) { // - We are timing for an emulation event if (_abs(threePos.x - pos.x) > 4 || _abs(threePos.y - pos.y) > 4) { // If the mouse has moved too far since the button-change event then flush vlog.debug("emulate3: stop timer (moved)"); threeTimer.stop(); intervalPointerEvent(writer, threePos, threeMask); } else { // Otherwise, we ignore the new event return; } } } // - If neither left nor right are down, stop emulating if ((buttonMask & 5) == 0) threeEmulating = false; // - If emulating, release left & right and press middle if (threeEmulating) buttonMask = emulate3Mask(buttonMask); } // - Let the event pass through to the next stage of processing intervalPointerEvent(writer, pos, buttonMask); } void CPointer::intervalPointerEvent(InputHandler* writer, const Point& pos, int buttonMask) { // // - Pointer Event Interval // vlog.write(101, "ptrEvent: %d,%d (%lx)", pos.x, pos.y, buttonMask); // Send the event immediately if we haven't sent one for a while bool sendNow = !intervalTimer.isActive(); if (intervalMask != buttonMask) { // If the buttons have changed then flush queued events and send now sendNow = true; if (intervalQueued) writer->pointerEvent(intervalPos, intervalMask); intervalQueued = false; } if (!sendNow) { // If we're not sending now then just queue the event intervalQueued = true; intervalPos = pos; intervalMask = buttonMask; } else { // Start the interval timer if required, and send the event intervalQueued = false; intervalMask = buttonMask; if (pointerEventInterval) intervalTimer.start(pointerEventInterval); writer->pointerEvent(pos, buttonMask); } } void CPointer::handleTimer(InputHandler* writer, int timerId) { if (timerId == intervalTimer.getId()) { // Pointer interval has expired - send any queued events if (intervalQueued) { writer->pointerEvent(intervalPos, intervalMask); intervalQueued = false; } else { intervalTimer.stop(); } } else if (timerId == threeTimer.getId()) { // 3-Button emulation timer has expired - send what we've got vlog.debug("emulate3: timeout"); threeTimer.stop(); // If emulating, release left & right and press middle if (threeEmulating) threeMask = emulate3Mask(threeMask); intervalPointerEvent(writer, threePos, threeMask); } }