Skip to content

Commit

Permalink
Working double click for touchscreens (#67)
Browse files Browse the repository at this point in the history
* Working double click, but sometimes it seems to triple click

* Better implementation of double click

Fires a weird ghost click off screen to "cancel" the existing click, not ideal

* This should work better, but it just triple clicks

* Smarter double click, but it always triple clicks?

* Don't mess with hover

* Rename method

* Store click time in nanoseconds, eliminating the need for millis()

* Put logs behind flag

* Reliable double click!

* This does nothing

* Disable debug output

* Use a circle instead of a square for fat finger zone

* Remove log statements
  • Loading branch information
lazd authored Mar 29, 2023
1 parent dfb3f0d commit f67a7e5
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 29 deletions.
86 changes: 58 additions & 28 deletions VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ bool VoodooI2CTouchscreenHIDEventDriver::checkFingerTouch(AbsoluteTime timestamp
IOFixed y = ((transducer->coordinates.y.value() * 1.0f) / transducer->logical_max_y) * 65535;

checkRotation(&x, &y);

// Track last ID and coordinates so that we can send the finger lift event after our watch dog timeout.
last_x = x;
last_y = y;
last_id = transducer->secondary_id;

// Begin long press right click routine. Increasing compare_input_counter check will lengthen the time until execution.

UInt16 temp_x = x;
Expand Down Expand Up @@ -76,22 +70,43 @@ bool VoodooI2CTouchscreenHIDEventDriver::checkFingerTouch(AbsoluteTime timestamp
// executing a drag movement. There is little noticeable affect in other circumstances. This also assists in transitioning
// between single / multitouch.

if (click_tick <= 2) {
buttons = 0x0;
click_tick++;
if (click_tick < HOVER_TICKS) {
buttons = HOVER;
} else {
buttons = transducer->tip_switch.value();
}
if (right_click)
buttons = 0x2;

dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, buttons, x, y);
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) &&
(nanoseconds - last_click_time) <= DOUBLE_CLICK_TIME
) {
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);
}

// Track last ID and coordinates so that we can send the finger lift event after our watch dog timeout.
last_x = x;
last_y = y;
last_id = transducer->secondary_id;

// This timer serves to let us know when a finger based event is finished executing as well as let us
// know to reset the clicktick counter.


timer_source->setTimeoutMS(14);
scheduleLift();
}
}
return got_transducer;
Expand Down Expand Up @@ -132,23 +147,23 @@ bool VoodooI2CTouchscreenHIDEventDriver::checkStylus(AbsoluteTime timestamp, Voo

checkRotation(&x, &y);

if (stylus->barrel_switch.value() != 0x0 && stylus->barrel_switch.value() !=0x2 && (stylus->barrel_switch.value()-barrel_switch_offset) != 0x2)
if (stylus->barrel_switch.value() != HOVER && stylus->barrel_switch.value() != RIGHT_CLICK && (stylus->barrel_switch.value()-barrel_switch_offset) != RIGHT_CLICK)
barrel_switch_offset = stylus->barrel_switch.value();
if (stylus->eraser.value() != 0x0 && stylus->eraser.value() !=0x2 && (stylus->eraser.value()-eraser_switch_offset) != 0x4)
if (stylus->eraser.value() != HOVER && stylus->eraser.value() != RIGHT_CLICK && (stylus->eraser.value()-eraser_switch_offset) != ERASE)
eraser_switch_offset = stylus->eraser.value();

stylus_buttons = stylus->tip_switch.value();

if (stylus->barrel_switch.value() == 0x2 || (stylus->barrel_switch.value() - barrel_switch_offset) == 0x2) {
stylus_buttons = 0x2;
if (stylus->barrel_switch.value() == RIGHT_CLICK || (stylus->barrel_switch.value() - barrel_switch_offset) == RIGHT_CLICK) {
stylus_buttons = RIGHT_CLICK;
}

if (stylus->eraser.value() == 0x4 || (stylus->eraser.value() - eraser_switch_offset) == 0x4) {
stylus_buttons = 0x4;
if (stylus->eraser.value() == ERASE || (stylus->eraser.value() - eraser_switch_offset) == ERASE) {
stylus_buttons = ERASE;
}

dispatchDigitizerEventWithTiltOrientation(timestamp, stylus->secondary_id, stylus->type, stylus->in_range, stylus_buttons, x, y, z, stylus_pressure, stylus->barrel_pressure.value(), stylus->azi_alti_orientation.twist.value(), stylus->tilt_orientation.x_tilt.value(), stylus->tilt_orientation.y_tilt.value());

return true;
}
}
Expand All @@ -167,16 +182,19 @@ void VoodooI2CTouchscreenHIDEventDriver::fingerLift() {
start_scroll = true;
uint64_t now_abs;
clock_get_uptime(&now_abs);

dispatchDigitizerEventWithTiltOrientation(now_abs, last_id, kDigitiserTransducerFinger, 0x1, 0x0, last_x, last_y);


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;
}

last_click_time = now_abs;
last_click_x = last_x;
last_click_y = last_y;
}

IOFramebuffer* VoodooI2CTouchscreenHIDEventDriver::getFramebuffer() {
Expand Down Expand Up @@ -225,7 +243,7 @@ void VoodooI2CTouchscreenHIDEventDriver::forwardReport(VoodooI2CMultitouchEvent
if (event.contact_count == 2 && start_scroll) {
scrollPosition(timestamp, event);
} else if (event.contact_count == 2 && !start_scroll) {
timer_source->setTimeoutMS(14);
scheduleLift();
}

multitouch_interface->handleInterruptReport(event, timestamp);
Expand Down Expand Up @@ -305,14 +323,26 @@ void VoodooI2CTouchscreenHIDEventDriver::scrollPosition(AbsoluteTime timestamp,

checkRotation(&cursor_x, &cursor_y);

dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, 0x0, cursor_x, cursor_y);
dispatchDigitizerEventWithTiltOrientation(timestamp, transducer->secondary_id, transducer->type, 0x1, HOVER, cursor_x, cursor_y);

last_x = cursor_x;
last_y = cursor_y;
last_id = transducer->secondary_id;

start_scroll = false;
}

timer_source->setTimeoutMS(14);
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);
}
23 changes: 22 additions & 1 deletion VoodooI2CHID/VoodooI2CTouchscreenHIDEventDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@

#include "VoodooI2CMultitouchHIDEventDriver.hpp"

#define FAT_FINGER_ZONE 1000000 // 1000^2
#define DOUBLE_CLICK_TIME 450 * 1000000
#define FINGER_LIFT_DELAY 50
#define HOVER_TICKS 3

#define HOVER 0x0
#define LEFT_CLICK 0x1
#define RIGHT_CLICK 0x2
#define ERASE 0x4

/* Implements an HID Event Driver for touchscreen devices as well as stylus input.
*/

Expand Down Expand Up @@ -62,6 +72,14 @@ 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();

private:
IOWorkLoop *work_loop;
IOTimerEventSource *timer_source;
Expand All @@ -76,19 +94,22 @@ class EXPORT VoodooI2CTouchscreenHIDEventDriver : public VoodooI2CMultitouchHIDE
UInt32 stylus_buttons = 0;
IOFixed last_x = 0;
IOFixed last_y = 0;
IOFixed last_click_x = 0;
IOFixed last_click_y = 0;
UInt32 barrel_switch_offset = 0;
UInt32 eraser_switch_offset = 0;
SInt32 last_id = 0;

/* handler variables
*/

int click_tick = 0;
UInt32 click_tick = 0;
bool right_click = false;
bool start_scroll = true;
UInt16 compare_input_x = 0;
UInt16 compare_input_y = 0;
int compare_input_counter = 0;
UInt64 last_click_time = 0;

/* The transducer is checked for singletouch finger based operation and the pointer event dispatched. This function
* also handles a long-press, right-click function.
Expand Down

0 comments on commit f67a7e5

Please sign in to comment.