|
|
|
|
|
|
|
|
int action1, action2; |
|
|
int action1, action2; |
|
|
int lastState; |
|
|
int lastState; |
|
|
|
|
|
|
|
|
|
|
|
// Just pass through events if the emulate setting is disabled |
|
|
if (!emulateMiddleButton) { |
|
|
if (!emulateMiddleButton) { |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
throw rfb::Exception(_("Invalid state for 3 button emulation")); |
|
|
throw rfb::Exception(_("Invalid state for 3 button emulation")); |
|
|
|
|
|
|
|
|
action1 = stateTab[state][btstate][0]; |
|
|
action1 = stateTab[state][btstate][0]; |
|
|
if (action1 != 0) |
|
|
|
|
|
sendAction(pos, buttonMask, action1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (action1 != 0) { |
|
|
|
|
|
// Some presses are delayed, that means we have to check if that's |
|
|
|
|
|
// the case and send the position corresponding to where the event |
|
|
|
|
|
// first was initiated |
|
|
|
|
|
if ((stateTab[state][4][2] >= 0) && action1 > 0) |
|
|
|
|
|
// We have a timeout state and a button press (a delayed press), |
|
|
|
|
|
// always use the original position when leaving a timeout state, |
|
|
|
|
|
// whether the timeout was triggered or not |
|
|
|
|
|
sendAction(origPos, buttonMask, action1); |
|
|
|
|
|
else |
|
|
|
|
|
// Normal non-delayed event |
|
|
|
|
|
sendAction(pos, buttonMask, action1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
action2 = stateTab[state][btstate][1]; |
|
|
action2 = stateTab[state][btstate][1]; |
|
|
if (action2 != 0) |
|
|
|
|
|
sendAction(pos, buttonMask, action2); |
|
|
|
|
|
|
|
|
|
|
|
if ((action1 == 0) && (action2 == 0)) { |
|
|
|
|
|
buttonMask &= ~0x5; |
|
|
|
|
|
buttonMask |= emulatedButtonMask; |
|
|
|
|
|
|
|
|
// In our case with the state machine, action2 always occurs during a button |
|
|
|
|
|
// release but if this change we need handle action2 accordingly |
|
|
|
|
|
if (action2 != 0) { |
|
|
|
|
|
if ((stateTab[state][4][2] >= 0) && action2 > 0) |
|
|
|
|
|
sendAction(origPos, buttonMask, action2); |
|
|
|
|
|
else |
|
|
|
|
|
// Normal non-delayed event |
|
|
|
|
|
sendAction(pos, buttonMask, action2); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Still send a pointer move event even if there are no actions. |
|
|
|
|
|
// However if the timer is running then we are supressing _all_ |
|
|
|
|
|
// events, even movement. The pointer's actual position will be |
|
|
|
|
|
// sent once the timer fires or is abandoned. |
|
|
|
|
|
if ((action1 == 0) && (action2 == 0) && !timer.isStarted()) { |
|
|
|
|
|
buttonMask = createButtonMask(buttonMask); |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (lastState != state) { |
|
|
if (lastState != state) { |
|
|
timer.stop(); |
|
|
timer.stop(); |
|
|
|
|
|
|
|
|
if (stateTab[state][4][2] >= 0) |
|
|
|
|
|
|
|
|
if (stateTab[state][4][2] >= 0) { |
|
|
|
|
|
// We need to save the original position so that |
|
|
|
|
|
// drags start from the correct position |
|
|
|
|
|
origPos = pos; |
|
|
timer.start(50); |
|
|
timer.start(50); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool EmulateMB::handleTimeout(rfb::Timer *t) |
|
|
bool EmulateMB::handleTimeout(rfb::Timer *t) |
|
|
{ |
|
|
{ |
|
|
int action1, action2; |
|
|
int action1, action2; |
|
|
|
|
|
int buttonMask; |
|
|
|
|
|
|
|
|
if (&timer != t) |
|
|
if (&timer != t) |
|
|
return false; |
|
|
return false; |
|
|
|
|
|
|
|
|
if ((state > 10) || (state < 0)) |
|
|
if ((state > 10) || (state < 0)) |
|
|
throw rfb::Exception(_("Invalid state for 3 button emulation")); |
|
|
throw rfb::Exception(_("Invalid state for 3 button emulation")); |
|
|
|
|
|
|
|
|
|
|
|
// Timeout shouldn't trigger when there's no timeout action |
|
|
assert(stateTab[state][4][2] >= 0); |
|
|
assert(stateTab[state][4][2] >= 0); |
|
|
|
|
|
|
|
|
action1 = stateTab[state][4][0]; |
|
|
action1 = stateTab[state][4][0]; |
|
|
if (action1 != 0) |
|
|
if (action1 != 0) |
|
|
sendAction(lastPos, lastButtonMask, action1); |
|
|
|
|
|
|
|
|
sendAction(origPos, lastButtonMask, action1); |
|
|
|
|
|
|
|
|
action2 = stateTab[state][4][1]; |
|
|
action2 = stateTab[state][4][1]; |
|
|
if (action2 != 0) |
|
|
if (action2 != 0) |
|
|
sendAction(lastPos, lastButtonMask, action2); |
|
|
|
|
|
|
|
|
sendAction(origPos, lastButtonMask, action2); |
|
|
|
|
|
|
|
|
|
|
|
buttonMask = lastButtonMask; |
|
|
|
|
|
|
|
|
|
|
|
// Pointer move events are not sent when waiting for the timeout. |
|
|
|
|
|
// However, we can't let the position get out of sync so when |
|
|
|
|
|
// the pointer has moved we have to send the latest position here. |
|
|
|
|
|
if (!origPos.equals(lastPos)) { |
|
|
|
|
|
buttonMask = createButtonMask(buttonMask); |
|
|
|
|
|
sendPointerEvent(lastPos, buttonMask); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
state = stateTab[state][4][2]; |
|
|
state = stateTab[state][4][2]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else |
|
|
else |
|
|
emulatedButtonMask |= (1 << (action - 1)); |
|
|
emulatedButtonMask |= (1 << (action - 1)); |
|
|
|
|
|
|
|
|
buttonMask &= ~0x5; |
|
|
|
|
|
buttonMask |= emulatedButtonMask; |
|
|
|
|
|
|
|
|
buttonMask = createButtonMask(buttonMask); |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
sendPointerEvent(pos, buttonMask); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int EmulateMB::createButtonMask(int buttonMask) |
|
|
|
|
|
{ |
|
|
|
|
|
// Unset left and right buttons in the mask |
|
|
|
|
|
buttonMask &= ~0x5; |
|
|
|
|
|
|
|
|
|
|
|
// Set the left and right buttons according to the action |
|
|
|
|
|
return buttonMask |= emulatedButtonMask; |
|
|
|
|
|
} |