diff --git a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp index 8c7acd1..8e408c1 100755 --- a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp +++ b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp @@ -10,6 +10,16 @@ #define super VoodooI2CMultitouchHIDEventDriver +/* Check if the first set of coordinates is within fat finger distance of the second set + */ +static bool isCloseTo(IOFixed x, IOFixed y, IOFixed other_x, IOFixed other_y) { + IOFixed diff_x = x - other_x; + IOFixed diff_y = y - other_y; + return (diff_x * diff_x) + + (diff_y * diff_y) < + FAT_FINGER_ZONE; +} + OSDefineMetaClassAndStructors(VoodooI2CTouchscreenHIDEventDriver, VoodooI2CMultitouchHIDEventDriver); // Override of VoodooI2CMultitouchHIDEventDriver @@ -39,60 +49,60 @@ bool VoodooI2CTouchscreenHIDEventDriver::checkFingerTouch(AbsoluteTime timestamp IOFixed y = ((transducer->coordinates.y.value() * 1.0f) / transducer->logical_max_y) * 65535; checkRotation(&x, &y); - // Begin long press right click routine. Increasing compare_input_counter check will lengthen the time until execution. - - UInt16 temp_x = x; - UInt16 temp_y = y; - - if (!right_click && digitiser.contact_count->getValue() == 1 && transducer->type == kDigitiserTransducerFinger && transducer->tip_switch) { - if (temp_x == compare_input_x && temp_y == compare_input_y) { - compare_input_counter = compare_input_counter + 1; - compare_input_x = temp_x; - compare_input_y = temp_y; - - if (compare_input_counter >= 120 && !right_click) { - compare_input_x = 0; - compare_input_y = 0; - compare_input_counter = 0; - right_click = true; - } - } else { - compare_input_x = temp_x; - compare_input_y = temp_y; - compare_input_counter = 0; - } - } - // End long press right click routine. - + // Get time in a usable format + uint64_t nanoseconds; + absolutetime_to_nanoseconds(timestamp, &nanoseconds); + // We need the first couple of single touch events to be in hover mode. In modes such as Mission Control, this allows us // to select and drag windows vs just select and exit. We are mimicking a cursor being moved into position prior to - // executing a drag movement. There is little noticeable affect in other circumstances. This also assists in transitioning + // executing a drag movement. There is little noticeable effect in other circumstances. This also assists in transitioning // between single / multitouch. if (click_tick < HOVER_TICKS) { buttons = HOVER; - } else { + touch_start_time = nanoseconds; + touch_start_x = x; + touch_start_y = y; + } else if ( + !right_click && + digitiser.contact_count->getValue() == 1 && + isCloseTo(x, y, touch_start_x, touch_start_y) && + (nanoseconds - touch_start_time) >= RIGHT_CLICK_TIME + ) { + right_click = true; + dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, RIGHT_CLICK, x, y); + dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, HOVER, x, y); + } + else { buttons = transducer->tip_switch.value(); } - if (right_click) - buttons = RIGHT_CLICK; - + click_tick++; - // Get time in a usable format - uint64_t nanoseconds; - absolutetime_to_nanoseconds(timestamp, &nanoseconds); - // If we're clicking again where we just clicked, precisely position the pointer where it was before - if ( - isCloseToLastClick(x, y) && + if (right_click) { + // After a right click has been executed, all interactions are now hovers + buttons = HOVER; + + if (isCloseTo(x, y, touch_start_x, touch_start_y)) { + // Adopt the location of the touch start so we don't stray and close the right click menu + x = touch_start_x; + y = touch_start_y; + } + else { + // Track if we moved after the right click so we know if we need to click again on release + moved_during_right_click = true; + } + } else if ( + isCloseTo(x, y, last_click_x, last_click_y) && (nanoseconds - last_click_time) <= DOUBLE_CLICK_TIME ) { + // If we're clicking again where we just clicked, precisely position the pointer where it was before x = last_click_x; y = last_click_y; } - + // Only dispatch a single click event after we've done our hover ticks if ((click_tick <= HOVER_TICKS + 1) || (x != last_x || y != last_y)) { dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, buttons, x, y); @@ -177,21 +187,20 @@ void VoodooI2CTouchscreenHIDEventDriver::fingerLift() { // checkFingerTouch function, however, this has the side effect of not releasing the pointer. This watchdog // timer is needed regardless so the pointer release is best done here. - - click_tick = 0; - start_scroll = true; uint64_t now_abs; clock_get_uptime(&now_abs); - dispatchDigitizerEventWithTiltOrientation(now_abs, last_id, kDigitiserTransducerFinger, 0x1, HOVER, last_x, last_y); - - // If a right click has been executed, we reset our counter and ensure that pointer is not stuck in right - // click button down situation. - - if (right_click) { - right_click = false; + // This seems strange, but we go to hover mode after right clicking, and we need to execute a click if we've moved + if (right_click && moved_during_right_click) { + dispatchDigitizerEventWithTiltOrientation(now_abs, last_id, kDigitiserTransducerFinger, 0x1, LEFT_CLICK, last_x, last_y); } + dispatchDigitizerEventWithTiltOrientation(now_abs, last_id, kDigitiserTransducerFinger, 0x1, HOVER, last_x, last_y); + + click_tick = 0; + start_scroll = true; + right_click = false; + moved_during_right_click = false; last_click_time = now_abs; last_click_x = last_x; last_click_y = last_y; @@ -335,14 +344,6 @@ void VoodooI2CTouchscreenHIDEventDriver::scrollPosition(AbsoluteTime timestamp, scheduleLift(); } -bool VoodooI2CTouchscreenHIDEventDriver::isCloseToLastClick(IOFixed x, IOFixed y) { - IOFixed diff_x = x - last_click_x; - IOFixed diff_y = y - last_click_y; - return (diff_x * diff_x) + - (diff_y * diff_y) < - FAT_FINGER_ZONE; -} - void VoodooI2CTouchscreenHIDEventDriver::scheduleLift() { timer_source->setTimeoutMS(FINGER_LIFT_DELAY); } diff --git a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.hpp b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.hpp index 2b8ba4a..ab9991b 100755 --- a/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.hpp +++ b/VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.hpp @@ -26,6 +26,7 @@ #define FAT_FINGER_ZONE 1000000 // 1000^2 #define DOUBLE_CLICK_TIME 450 * 1000000 +#define RIGHT_CLICK_TIME 500 * 1000000 #define FINGER_LIFT_DELAY 50 #define HOVER_TICKS 3 @@ -72,10 +73,6 @@ class EXPORT VoodooI2CTouchscreenHIDEventDriver : public VoodooI2CMultitouchHIDE */ IOReturn parseElements(UInt32) override; - /* Check if this interaction is within fat finger distance - */ - bool isCloseToLastClick(IOFixed x, IOFixed y); - /* Schedule a finger lift event */ void scheduleLift(); @@ -96,6 +93,8 @@ class EXPORT VoodooI2CTouchscreenHIDEventDriver : public VoodooI2CMultitouchHIDE IOFixed last_y = 0; IOFixed last_click_x = 0; IOFixed last_click_y = 0; + IOFixed touch_start_x = 0; + IOFixed touch_start_y = 0; UInt32 barrel_switch_offset = 0; UInt32 eraser_switch_offset = 0; SInt32 last_id = 0; @@ -105,10 +104,9 @@ class EXPORT VoodooI2CTouchscreenHIDEventDriver : public VoodooI2CMultitouchHIDE UInt32 click_tick = 0; bool right_click = false; + bool moved_during_right_click = false; bool start_scroll = true; - UInt16 compare_input_x = 0; - UInt16 compare_input_y = 0; - int compare_input_counter = 0; + UInt64 touch_start_time = 0; UInt64 last_click_time = 0; /* The transducer is checked for singletouch finger based operation and the pointer event dispatched. This function