Skip to content

Commit

Permalink
feat: advanced stylus support with right click, closes #14
Browse files Browse the repository at this point in the history
  • Loading branch information
lazd committed Jan 22, 2020
1 parent 59f1c38 commit 58a280a
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 25 deletions.
57 changes: 48 additions & 9 deletions VoodooI2CGoodix/VoodooI2CGoodixEventDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ static UInt64 getNanoseconds() {
return nanoseconds;
}

void VoodooI2CGoodixEventDriver::dispatchPenEvent(int logicalX, int logicalY, int pressure, UInt32 clickType) {
AbsoluteTime timestamp;
clock_get_uptime(&timestamp);

// Convert logical coordinates to IOFixed and Scaled;
IOFixed x = ((logicalX * 1.0f) / multitouch_interface->logical_max_x) * 65535;
IOFixed y = ((logicalY * 1.0f) / multitouch_interface->logical_max_y) * 65535;
IOFixed tipPressure = ((pressure * 1.0f) / 1024) * 65535;

checkRotation(&x, &y);

// Dispatch the actual event
dispatchDigitizerEventWithTiltOrientation(timestamp, 0, kDigitiserTransducerStylus, 0x1, clickType, x, y, 65535, tipPressure);

// Store the coordinates so we can lift the finger later
lastEventFixedX = x;
lastEventFixedY = y;
}

void VoodooI2CGoodixEventDriver::dispatchDigitizerEvent(int logicalX, int logicalY, UInt32 clickType) {
AbsoluteTime timestamp;
clock_get_uptime(&timestamp);
Expand Down Expand Up @@ -75,18 +94,38 @@ void VoodooI2CGoodixEventDriver::fingerLift() {
}
}

void VoodooI2CGoodixEventDriver::handleSingletouchInteraction(Touch touch) {
void VoodooI2CGoodixEventDriver::handleSingletouchInteraction(Touch touch, bool stylusButton1, bool stylusButton2) {
int logicalX = touch.x;
int logicalY = touch.y;
int width = touch.width;
bool isStylus = touch.type;

if (width == 0) {
#ifdef GOODIX_EVENT_DRIVER_DEBUG
IOLog("%s::Stylus hovering at %d, %d \n", getName(), logicalX, logicalY);
#endif
if (isStylus) {
UInt8 type = HOVER;

// Stylus hovers come with a 0 width, so don't bother with any of our routines
dispatchDigitizerEvent(logicalX, logicalY, HOVER);
if (width == 0) {
#ifdef GOODIX_EVENT_DRIVER_DEBUG
IOLog("%s::Stylus hovering at %d, %d \n", getName(), logicalX, logicalY);
#endif
}
else {
if (stylusButton1) {
type = RIGHT_CLICK;
#ifdef GOODIX_EVENT_DRIVER_DEBUG
IOLog("%s::Stylus right click at %d, %d \n", getName(), logicalX, logicalY);
#endif
}
else {
type = LEFT_CLICK;
#ifdef GOODIX_EVENT_DRIVER_DEBUG
IOLog("%s::Stylus left click at %d, %d \n", getName(), logicalX, logicalY);
#endif
}

scheduleLift();
}

dispatchPenEvent(logicalX, logicalY, width, type);

return;
}
Expand Down Expand Up @@ -242,7 +281,7 @@ void VoodooI2CGoodixEventDriver::handleMultitouchInteraction(struct Touch touche
scheduleLift();
}

void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTouches) {
void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTouches, bool stylusButton1, bool stylusButton2) {
if (!activeFramebuffer) {
activeFramebuffer = getFramebuffer();
}
Expand All @@ -253,7 +292,7 @@ void VoodooI2CGoodixEventDriver::reportTouches(struct Touch touches[], int numTo
}

if (numTouches == 1) {
handleSingletouchInteraction(touches[0]);
handleSingletouchInteraction(touches[0], stylusButton1, stylusButton2);
}
else {
handleMultitouchInteraction(touches, numTouches);
Expand Down
19 changes: 16 additions & 3 deletions VoodooI2CGoodix/VoodooI2CGoodixEventDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@
#define RIGHT_CLICK 0x2
#define DRAG 0x5

//#define GOODIX_EVENT_DRIVER_DEBUG

struct Touch {
int x;
int y;
int width;
bool type; // 0 = finger, 1 = pen
};

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

void reportTouches(struct Touch touches[], int numTouches);
void reportTouches(struct Touch touches[], int numTouches, bool stylusButton1, bool stylusButton2);

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

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

/* Dispatch a pen event at the given screen coordinate
*
* @logicalX The logical X position of the event
* @logicalY The logical Y position of the event
* @pressure The pressure (0-1024)
* @clickType what type of click to dispatch, if any
*/

void dispatchPenEvent(int logicalX, int logicalY, int pressure, UInt32 clickType);

/* Dispatch a finger lift event at the location of the last digitizer event
*/

Expand Down Expand Up @@ -174,7 +187,7 @@ class EXPORT VoodooI2CGoodixEventDriver : public IOHIDEventService {
*
* @touch A single Touch object
*/
void handleSingletouchInteraction(Touch touch);
void handleSingletouchInteraction(Touch touch, bool stylusButton1, bool stylusButton2);

/* Schedule a check for a click
*/
Expand Down
39 changes: 26 additions & 13 deletions VoodooI2CGoodix/VoodooI2CGoodixTouchDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,26 +260,33 @@ IOReturn VoodooI2CGoodixTouchDriver::goodix_end_cmd() {

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

numTouches = goodix_ts_read_input_report(point_data);
numTouches = goodix_ts_read_input_report(data);
if (numTouches <= 0) {
return kIOReturnSuccess;
}

/*
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
*/
// bool home_pressed = point_data[0] & BIT(4);
UInt8 keys = data[1 + numTouches * GOODIX_CONTACT_SIZE];
if (GOODIX_KEYDOWN_EVENT(keys)) {
stylusButton1 = GOODIX_IS_STYLUS_BTN_DOWN(keys, GOODIX_STYLUS_BTN1);
stylusButton2 = GOODIX_IS_STYLUS_BTN_DOWN(keys, GOODIX_STYLUS_BTN2);
}
else {
stylusButton1 = false;
stylusButton2 = false;
}

UInt8 *point_data;
for (int i = 0; i < numTouches; i++) {
goodix_ts_store_touch(&point_data[1 + GOODIX_CONTACT_SIZE * i]);
point_data = &data[1 + i * GOODIX_CONTACT_SIZE];
goodix_ts_store_touch(point_data);
}

if (numTouches > 0) {
// send the event into the event driver
event_driver->reportTouches(touches, numTouches);
event_driver->reportTouches(touches, numTouches, stylusButton1, stylusButton2);
}

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

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

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

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

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

// Store touch information
touches[id].x = input_x;
touches[id].y = input_y;
touches[id].width = input_w;
touches[id].type = type;
}

void VoodooI2CGoodixTouchDriver::stop(IOService* provider) {
Expand All @@ -374,7 +387,7 @@ void VoodooI2CGoodixTouchDriver::stop(IOService* provider) {
}

IOReturn VoodooI2CGoodixTouchDriver::setPowerState(unsigned long powerState, IOService* whatDevice) {
#ifndef GOODIX_EVENT_DRIVER_DEBUG
#ifndef GOODIX_TOUCH_DRIVER_DEBUG
if (powerState == 0) {
if (awake) {
awake = false;
Expand Down
4 changes: 4 additions & 0 deletions VoodooI2CGoodix/VoodooI2CGoodixTouchDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "./VoodooI2CGoodixEventDriver.hpp"
#include "goodix.h"

//#define GOODIX_TOUCH_DRIVER_DEBUG

class VoodooI2CGoodixTouchDriver : public IOService {
OSDeclareDefaultStructors(VoodooI2CGoodixTouchDriver);

Expand Down Expand Up @@ -66,6 +68,8 @@ class VoodooI2CGoodixTouchDriver : public IOService {

struct Touch touches[GOODIX_MAX_CONTACTS];
int numTouches;
bool stylusButton1 = false;
bool stylusButton2 = false;

/* Sends the appropriate packets to
* initialise the device into multitouch mode
Expand Down
15 changes: 15 additions & 0 deletions VoodooI2CGoodix/goodix.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@
#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20000000

#define GOODIX_STYLUS_BTN1 0
#define GOODIX_STYLUS_BTN2 1

#define GOODIX_TOOL_FINGER 0
#define GOODIX_TOOL_PEN 1

#define GOODIX_KEYDOWN_EVENT(byte) \
(byte & 0b01110000)

#define GOODIX_IS_STYLUS_BTN_DOWN(byte, btn) \
((byte & 0x40) || (byte & (0x10 << btn)))

#define GOODIX_TOOL_TYPE(id_byte) \
(id_byte & 0x80 ? GOODIX_TOOL_PEN : GOODIX_TOOL_FINGER)

#define msleep(x) IOSleep(x)
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
Expand Down

0 comments on commit 58a280a

Please sign in to comment.