View
@@ -54,31 +54,41 @@
#include "kbd.h"
/*
* Inoffical and unannounced report ids for Apple Mice and trackpad
* Unoffical and unannounced report ids for Apple mice and trackpads
*/
#define TRACKPAD_REPORT_ID 0x28
#define AMM_REPORT_ID 0x29
#define BATT_STAT_REPORT_ID 0x30
#define BATT_STRENGTH_REPORT_ID 0x47
#define SURFACE_REPORT_ID 0x61
#define MAGIC_MOUSE(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30d))
#define MAGIC_TRACKPAD(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30e))
/*
* Apple magic mouse (AMM) specific device state
* Apple magic mouse/trackpad (AMM/AMT) specific device state
*/
#define AMM_MAX_BUTTONS 16
struct apple_state {
int y [AMM_MAX_BUTTONS];
int button_state;
};
#define MAGIC_MOUSE(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30d))
#define AMM_BASIC_BLOCK 5
#define AMM_FINGER_BLOCK 8
#define AMM_VALID_REPORT(L) (((L) >= AMM_BASIC_BLOCK) && \
((L) <= 16*AMM_FINGER_BLOCK + AMM_BASIC_BLOCK) && \
((L) % AMM_FINGER_BLOCK) == AMM_BASIC_BLOCK)
((L) <= AMM_MAX_BUTTONS*AMM_FINGER_BLOCK + AMM_BASIC_BLOCK) && \
((L) % AMM_FINGER_BLOCK) == AMM_BASIC_BLOCK)
#define AMM_WHEEL_SPEED 100
#define AMT_MAX_TOUCHES 16
#define AMT_BASIC_BLOCK 3
#define AMT_FINGER_BLOCK 9
#define AMT_VALID_REPORT(L) (((L) >= AMT_BASIC_BLOCK) && \
((L) <= AMT_MAX_TOUCHES*AMT_FINGER_BLOCK + AMT_BASIC_BLOCK) && \
((L) % AMT_FINGER_BLOCK) == AMT_BASIC_BLOCK)
#define AMT_STATE_MASK 0xf0
struct apple_state {
int y [AMM_MAX_BUTTONS];
int button_state;
};
/*
* Probe for per-device initialisation
*/
@@ -87,8 +97,8 @@ hid_initialise(bthid_session_p s)
{
hid_device_p hid_device = get_hid_device(&s->bdaddr);
if (hid_device && MAGIC_MOUSE(hid_device)) {
/* Magic report to enable trackpad on Apple's Magic Mouse */
if (hid_device && (MAGIC_MOUSE(hid_device) || MAGIC_TRACKPAD(hid_device))) {
/* Magic report to enable touch on Apple's Magic Mouse/Trackpad */
static uint8_t rep[] = {0x53, 0xd7, 0x01};
if ((s->ctx = calloc(1, sizeof(struct apple_state))) == NULL)
@@ -513,6 +523,63 @@ hid_interrupt(bthid_session_p s, uint8_t *data, int32_t len)
c->button_state = mouse_butt, mevents++;
}
/*
* Feed trackpad events into kernel.
*/
if (hid_device->mouse && s->srv->uinput && MAGIC_TRACKPAD(hid_device)) {
data++, len--; /* Chomp report_id */
if (report_id == TRACKPAD_REPORT_ID && AMT_VALID_REPORT(len)) {
int nfingers = 0;
int clicked = data[0] & 1;
for (data += AMT_BASIC_BLOCK, len -= AMT_BASIC_BLOCK;
len >= AMT_FINGER_BLOCK;
data += AMT_FINGER_BLOCK, len -= AMT_FINGER_BLOCK) {
int32_t id = 0xf & (data[7] << 2 | data[6] >> 6);
int32_t x = (data[1] << 27 | data[0] << 19) >> 19;
int32_t y = -((data[3] << 30 | data[2] << 22 | data[1] << 14) >> 19);
int32_t orientation = (data[7] >> 2) - 32;
int32_t touch_major = data[4];
int32_t touch_minor = data[5];
int32_t state = data[8] & AMT_STATE_MASK;
if (uinput_rep_multi_touch(s->umouse, id, x, y, orientation,
touch_major, touch_minor, state) < 0) {
syslog(LOG_ERR, "Could not process multi-touch events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
strerror(errno), errno);
}
if (nfingers == 0) {
if (uinput_rep_single_touch(s->umouse, x, y, state) < 0) {
syslog(LOG_ERR, "Could not process single-touch events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
strerror(errno), errno);
}
}
nfingers++;
}
if (uinput_rep_fingers(s->umouse, nfingers) < 0) {
syslog(LOG_ERR, "Could not process fingers events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
strerror(errno), errno);
}
if (uinput_rep_click(s->umouse, clicked) < 0) {
syslog(LOG_ERR, "Could not process click events from " \
"%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL),
strerror(errno), errno);
}
}
uinput_rep_sync(s->umouse);
}
/*
* XXX FIXME Feed keyboard events into kernel.
* The code below works, bit host also needs to track
View
@@ -50,6 +50,8 @@
#include "btuinput.h"
#include "kbd.h"
#define MAGIC_TRACKPAD(D) (((D)->vendor_id == 0x5ac) && ((D)->product_id == 0x30e))
/*
* Create new session
*/
@@ -128,7 +130,7 @@ session_run(bthid_session_p s)
getsockname(s->ctrl, (struct sockaddr *) &local, &len);
if (d->mouse && s->srv->uinput) {
s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr);
s->umouse = uinput_open_mouse(d, &local.l2cap_bdaddr, MAGIC_TRACKPAD(d));
if (s->umouse < 0) {
syslog(LOG_ERR, "Could not open /dev/uinput " \
"for %s. %s (%d)", bt_ntoa(&s->bdaddr,