Skip to content

Commit 58a280a

Browse files
committed
feat: advanced stylus support with right click, closes #14
1 parent 59f1c38 commit 58a280a

File tree

5 files changed

+109
-25
lines changed

5 files changed

+109
-25
lines changed

VoodooI2CGoodix/VoodooI2CGoodixEventDriver.cpp

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,25 @@ static UInt64 getNanoseconds() {
2121
return nanoseconds;
2222
}
2323

24+
void VoodooI2CGoodixEventDriver::dispatchPenEvent(int logicalX, int logicalY, int pressure, UInt32 clickType) {
25+
AbsoluteTime timestamp;
26+
clock_get_uptime(&timestamp);
27+
28+
// Convert logical coordinates to IOFixed and Scaled;
29+
IOFixed x = ((logicalX * 1.0f) / multitouch_interface->logical_max_x) * 65535;
30+
IOFixed y = ((logicalY * 1.0f) / multitouch_interface->logical_max_y) * 65535;
31+
IOFixed tipPressure = ((pressure * 1.0f) / 1024) * 65535;
32+
33+
checkRotation(&x, &y);
34+
35+
// Dispatch the actual event
36+
dispatchDigitizerEventWithTiltOrientation(timestamp, 0, kDigitiserTransducerStylus, 0x1, clickType, x, y, 65535, tipPressure);
37+
38+
// Store the coordinates so we can lift the finger later
39+
lastEventFixedX = x;
40+
lastEventFixedY = y;
41+
}
42+
2443
void VoodooI2CGoodixEventDriver::dispatchDigitizerEvent(int logicalX, int logicalY, UInt32 clickType) {
2544
AbsoluteTime timestamp;
2645
clock_get_uptime(&timestamp);
@@ -75,18 +94,38 @@ void VoodooI2CGoodixEventDriver::fingerLift() {
7594
}
7695
}
7796

78-
void VoodooI2CGoodixEventDriver::handleSingletouchInteraction(Touch touch) {
97+
void VoodooI2CGoodixEventDriver::handleSingletouchInteraction(Touch touch, bool stylusButton1, bool stylusButton2) {
7998
int logicalX = touch.x;
8099
int logicalY = touch.y;
81100
int width = touch.width;
101+
bool isStylus = touch.type;
82102

83-
if (width == 0) {
84-
#ifdef GOODIX_EVENT_DRIVER_DEBUG
85-
IOLog("%s::Stylus hovering at %d, %d \n", getName(), logicalX, logicalY);
86-
#endif
103+
if (isStylus) {
104+
UInt8 type = HOVER;
87105

88-
// Stylus hovers come with a 0 width, so don't bother with any of our routines
89-
dispatchDigitizerEvent(logicalX, logicalY, HOVER);
106+
if (width == 0) {
107+
#ifdef GOODIX_EVENT_DRIVER_DEBUG
108+
IOLog("%s::Stylus hovering at %d, %d \n", getName(), logicalX, logicalY);
109+
#endif
110+
}
111+
else {
112+
if (stylusButton1) {
113+
type = RIGHT_CLICK;
114+
#ifdef GOODIX_EVENT_DRIVER_DEBUG
115+
IOLog("%s::Stylus right click at %d, %d \n", getName(), logicalX, logicalY);
116+
#endif
117+
}
118+
else {
119+
type = LEFT_CLICK;
120+
#ifdef GOODIX_EVENT_DRIVER_DEBUG
121+
IOLog("%s::Stylus left click at %d, %d \n", getName(), logicalX, logicalY);
122+
#endif
123+
}
124+
125+
scheduleLift();
126+
}
127+
128+
dispatchPenEvent(logicalX, logicalY, width, type);
90129

91130
return;
92131
}
@@ -242,7 +281,7 @@ void VoodooI2CGoodixEventDriver::handleMultitouchInteraction(struct Touch touche
242281
scheduleLift();
243282
}
244283

245-
void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTouches) {
284+
void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTouches, bool stylusButton1, bool stylusButton2) {
246285
if (!activeFramebuffer) {
247286
activeFramebuffer = getFramebuffer();
248287
}
@@ -253,7 +292,7 @@ void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTo
253292
}
254293

255294
if (numTouches == 1) {
256-
handleSingletouchInteraction(touches[0]);
295+
handleSingletouchInteraction(touches[0], stylusButton1, stylusButton2);
257296
}
258297
else {
259298
handleMultitouchInteraction(touches, numTouches);

VoodooI2CGoodix/VoodooI2CGoodixEventDriver.hpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@
4141
#define RIGHT_CLICK 0x2
4242
#define DRAG 0x5
4343

44+
//#define GOODIX_EVENT_DRIVER_DEBUG
45+
4446
struct Touch {
4547
int x;
4648
int y;
4749
int width;
50+
bool type; // 0 = finger, 1 = pen
4851
};
4952

5053
/* Implements an HID Event Driver for HID devices that expose a digitiser usage page.
@@ -100,7 +103,7 @@ class EXPORT VoodooI2CGoodixEventDriver : public IOHIDEventService {
100103
* @numTouches The number of touches in the Touch array
101104
*/
102105

103-
void reportTouches(struct Touch touches[], int numTouches);
106+
void reportTouches(struct Touch touches[], int numTouches, bool stylusButton1, bool stylusButton2);
104107

105108
/* Initialize the multitouch interface with the provided logical size
106109
* @logicalMaxX The logical max X coordinate in pixels
@@ -136,11 +139,21 @@ class EXPORT VoodooI2CGoodixEventDriver : public IOHIDEventService {
136139
*
137140
* @logicalX The logical X position of the event
138141
* @logicalY The logical Y position of the event
139-
* @click Whether this is a click event
142+
* @clickType what type of click to dispatch, if any
140143
*/
141144

142145
void dispatchDigitizerEvent(int logicalX, int logicalY, UInt32 clickType);
143146

147+
/* Dispatch a pen event at the given screen coordinate
148+
*
149+
* @logicalX The logical X position of the event
150+
* @logicalY The logical Y position of the event
151+
* @pressure The pressure (0-1024)
152+
* @clickType what type of click to dispatch, if any
153+
*/
154+
155+
void dispatchPenEvent(int logicalX, int logicalY, int pressure, UInt32 clickType);
156+
144157
/* Dispatch a finger lift event at the location of the last digitizer event
145158
*/
146159

@@ -174,7 +187,7 @@ class EXPORT VoodooI2CGoodixEventDriver : public IOHIDEventService {
174187
*
175188
* @touch A single Touch object
176189
*/
177-
void handleSingletouchInteraction(Touch touch);
190+
void handleSingletouchInteraction(Touch touch, bool stylusButton1, bool stylusButton2);
178191

179192
/* Schedule a check for a click
180193
*/

VoodooI2CGoodix/VoodooI2CGoodixTouchDriver.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -260,26 +260,33 @@ IOReturn VoodooI2CGoodixTouchDriver::goodix_end_cmd() {
260260

261261
/* Ported from goodix.c */
262262
IOReturn VoodooI2CGoodixTouchDriver::goodix_process_events() {
263-
UInt8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
263+
// Allocate enough space for the status byte, all touches, and the extra button byte
264+
UInt8 data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS + 1];
264265

265-
numTouches = goodix_ts_read_input_report(point_data);
266+
numTouches = goodix_ts_read_input_report(data);
266267
if (numTouches <= 0) {
267268
return kIOReturnSuccess;
268269
}
269270

270-
/*
271-
* Bit 4 of the first byte reports the status of the capacitive
272-
* Windows/Home button.
273-
*/
274-
// bool home_pressed = point_data[0] & BIT(4);
271+
UInt8 keys = data[1 + numTouches * GOODIX_CONTACT_SIZE];
272+
if (GOODIX_KEYDOWN_EVENT(keys)) {
273+
stylusButton1 = GOODIX_IS_STYLUS_BTN_DOWN(keys, GOODIX_STYLUS_BTN1);
274+
stylusButton2 = GOODIX_IS_STYLUS_BTN_DOWN(keys, GOODIX_STYLUS_BTN2);
275+
}
276+
else {
277+
stylusButton1 = false;
278+
stylusButton2 = false;
279+
}
275280

281+
UInt8 *point_data;
276282
for (int i = 0; i < numTouches; i++) {
277-
goodix_ts_store_touch(&point_data[1 + GOODIX_CONTACT_SIZE * i]);
283+
point_data = &data[1 + i * GOODIX_CONTACT_SIZE];
284+
goodix_ts_store_touch(point_data);
278285
}
279286

280287
if (numTouches > 0) {
281288
// send the event into the event driver
282-
event_driver->reportTouches(touches, numTouches);
289+
event_driver->reportTouches(touches, numTouches, stylusButton1, stylusButton2);
283290
}
284291

285292
return kIOReturnSuccess;
@@ -306,7 +313,8 @@ int VoodooI2CGoodixTouchDriver::goodix_ts_read_input_report(UInt8 *data) {
306313
clock_get_uptime(&timestamp);
307314
absolutetime_to_nanoseconds(timestamp, &timestamp_ns);
308315

309-
retVal = goodix_read_reg(GOODIX_READ_COOR_ADDR, data, GOODIX_CONTACT_SIZE + 1);
316+
// On the intial read, get the status byte, the first touch, and the pen buttons
317+
retVal = goodix_read_reg(GOODIX_READ_COOR_ADDR, data, 1 + GOODIX_CONTACT_SIZE + 1);
310318
if (retVal != kIOReturnSuccess) {
311319
IOLog("%s::I2C transfer error starting coordinate read: %d\n", getName(), retVal);
312320
return -1;
@@ -320,7 +328,8 @@ int VoodooI2CGoodixTouchDriver::goodix_ts_read_input_report(UInt8 *data) {
320328

321329
if (touch_num > 1) {
322330
data += 1 + GOODIX_CONTACT_SIZE;
323-
retVal = goodix_read_reg(GOODIX_READ_COOR_ADDR + 1 + GOODIX_CONTACT_SIZE, data, GOODIX_CONTACT_SIZE * (touch_num - 1));
331+
// Read all touches, and 1 additional byte for the pen buttons
332+
retVal = goodix_read_reg(GOODIX_READ_COOR_ADDR + 1 + GOODIX_CONTACT_SIZE, data, GOODIX_CONTACT_SIZE * (touch_num - 1) + 1);
324333
if (retVal != kIOReturnSuccess) {
325334
IOLog("%s::I2C transfer error during coordinate read: %d\n", getName(), retVal);
326335
return -1;
@@ -346,6 +355,7 @@ void VoodooI2CGoodixTouchDriver::goodix_ts_store_touch(UInt8 *coor_data) {
346355
int input_x = get_unaligned_le16(&coor_data[1]);
347356
int input_y = get_unaligned_le16(&coor_data[3]);
348357
int input_w = get_unaligned_le16(&coor_data[5]);
358+
bool type = GOODIX_TOOL_TYPE(coor_data[0]) == GOODIX_TOOL_PEN;
349359

350360
// Inversions have to happen before axis swapping
351361
if (ts->inverted_x)
@@ -357,12 +367,15 @@ void VoodooI2CGoodixTouchDriver::goodix_ts_store_touch(UInt8 *coor_data) {
357367
swap(input_x, input_y);
358368
}
359369

360-
// IOLog("%s::Touch %d with width %d at %d,%d\n", getName(), id, input_w, input_x, input_y);
370+
#ifndef GOODIX_TOUCH_DRIVER_DEBUG
371+
IOLog("%s::%s %d with width %d at %d,%d\n", getName(), type ? "Stylus" : "Touch", id, input_w, input_x, input_y);
372+
#endif
361373

362374
// Store touch information
363375
touches[id].x = input_x;
364376
touches[id].y = input_y;
365377
touches[id].width = input_w;
378+
touches[id].type = type;
366379
}
367380

368381
void VoodooI2CGoodixTouchDriver::stop(IOService* provider) {
@@ -374,7 +387,7 @@ void VoodooI2CGoodixTouchDriver::stop(IOService* provider) {
374387
}
375388

376389
IOReturn VoodooI2CGoodixTouchDriver::setPowerState(unsigned long powerState, IOService* whatDevice) {
377-
#ifndef GOODIX_EVENT_DRIVER_DEBUG
390+
#ifndef GOODIX_TOUCH_DRIVER_DEBUG
378391
if (powerState == 0) {
379392
if (awake) {
380393
awake = false;

VoodooI2CGoodix/VoodooI2CGoodixTouchDriver.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "./VoodooI2CGoodixEventDriver.hpp"
1919
#include "goodix.h"
2020

21+
//#define GOODIX_TOUCH_DRIVER_DEBUG
22+
2123
class VoodooI2CGoodixTouchDriver : public IOService {
2224
OSDeclareDefaultStructors(VoodooI2CGoodixTouchDriver);
2325

@@ -66,6 +68,8 @@ class VoodooI2CGoodixTouchDriver : public IOService {
6668

6769
struct Touch touches[GOODIX_MAX_CONTACTS];
6870
int numTouches;
71+
bool stylusButton1 = false;
72+
bool stylusButton2 = false;
6973

7074
/* Sends the appropriate packets to
7175
* initialise the device into multitouch mode

VoodooI2CGoodix/goodix.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@
3131
#define GOODIX_BUFFER_STATUS_READY BIT(7)
3232
#define GOODIX_BUFFER_STATUS_TIMEOUT 20000000
3333

34+
#define GOODIX_STYLUS_BTN1 0
35+
#define GOODIX_STYLUS_BTN2 1
36+
37+
#define GOODIX_TOOL_FINGER 0
38+
#define GOODIX_TOOL_PEN 1
39+
40+
#define GOODIX_KEYDOWN_EVENT(byte) \
41+
(byte & 0b01110000)
42+
43+
#define GOODIX_IS_STYLUS_BTN_DOWN(byte, btn) \
44+
((byte & 0x40) || (byte & (0x10 << btn)))
45+
46+
#define GOODIX_TOOL_TYPE(id_byte) \
47+
(id_byte & 0x80 ? GOODIX_TOOL_PEN : GOODIX_TOOL_FINGER)
48+
3449
#define msleep(x) IOSleep(x)
3550
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
3651
#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))

0 commit comments

Comments
 (0)