diff --git a/README.md b/README.md index a7be798..8aba68d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # Linux Apple Magic Mouse 2 and Magic Trackpad 2 Driver -This repository contains the linux hid-magicmouse driver with Magic Trackpad 2 and Magic Mouse 2 support for Linux 4.18. For older kernels you might have to diff and backport. It also contains 2 fixes to the Magic Mouse 2 regarding Bluetooth random disconnections and this driver not loading on bluetooth reconnection. +This repository contains the linux hid-magicmouse driver with Magic Trackpad 2 and Magic Mouse 2 support for Linux 4.18 onwards. For older kernels you might have to diff and backport. It also contains 2 fixes to the Magic Mouse 2 regarding Bluetooth random disconnections and this driver not loading on bluetooth reconnection. This driver is based off of the work of @robotrovsky, @svartalf, @0xABAD and probably others. Please help to test this driver and report issues. +**NOTE**: Since kernel version 5.15, there is support for the mouse without the need for this driver. We try to backport changes to this driver to have it up-to-date with the one on the kernel and try to offer a bit more functionality but it is not perfect. If you want the mouse to just work either install a more recent kernel or proceed with this driver installation. + ## Ubuntu (and derivatives) A `.deb` file is now available in Releases. Get the [latest version here](https://github.com/RicardoEPRodrigues/magicmouse-hid/releases/latest). diff --git a/linux/drivers/hid/hid-magicmouse.c b/linux/drivers/hid/hid-magicmouse.c index 78a8e6c..485f148 100644 --- a/linux/drivers/hid/hid-magicmouse.c +++ b/linux/drivers/hid/hid-magicmouse.c @@ -106,6 +106,10 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TOUCH_STATE_START 0x30 #define TOUCH_STATE_DRAG 0x40 +/* Number of high-resolution events for each low-resolution detent. */ +#define SCROLL_HR_STEPS 10 +#define SCROLL_HR_MULT (120 / SCROLL_HR_STEPS) +#define SCROLL_HR_THRESHOLD 90 /* units */ #define SCROLL_ACCEL_DEFAULT 3 /* Touch surface information. Dimension is in hundredths of a mm, min and max @@ -169,7 +173,11 @@ struct magicmouse_sc { short y; short scroll_x; short scroll_y; + short scroll_x_hr; + short scroll_y_hr; u8 size; + bool scroll_x_active; + bool scroll_y_active; } touches[MAX_TOUCHES]; int tracking_ids[MAX_TOUCHES]; @@ -346,6 +354,10 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, unsigned long now = jiffies; int step_x = msc->touches[id].scroll_x - x; int step_y = msc->touches[id].scroll_y - y; + int step_hr = ((64 - (int)scroll_speed) * msc->scroll_accel) / + SCROLL_HR_STEPS; + int step_x_hr = msc->touches[id].scroll_x_hr - x; + int step_y_hr = msc->touches[id].scroll_y_hr - y; /* Determine if the mouse has moved, if so then disable scrolling. */ bool continue_scroll = true; @@ -360,6 +372,10 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, case TOUCH_STATE_START: msc->touches[id].scroll_x = x; msc->touches[id].scroll_y = y; + msc->touches[id].scroll_x_hr = x; + msc->touches[id].scroll_y_hr = y; + msc->touches[id].scroll_x_active = false; + msc->touches[id].scroll_y_active = false; /* Reset acceleration after half a second. */ if (scroll_acceleration && time_before(now, @@ -400,6 +416,40 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, msc->scroll_jiffies = now; input_report_rel(input, REL_WHEEL, step_y); } + + if (!msc->touches[id].scroll_x_active && + abs(step_x_hr) > SCROLL_HR_THRESHOLD) { + msc->touches[id].scroll_x_active = true; + msc->touches[id].scroll_x_hr = x; + step_x_hr = 0; + } + + step_x_hr /= step_hr; + if (step_x_hr != 0 && + msc->touches[id].scroll_x_active) { + msc->touches[id].scroll_x_hr -= step_x_hr * + step_hr; + input_report_rel(input, + REL_HWHEEL_HI_RES, + -step_x_hr * SCROLL_HR_MULT); + } + + if (!msc->touches[id].scroll_y_active && + abs(step_y_hr) > SCROLL_HR_THRESHOLD) { + msc->touches[id].scroll_y_active = true; + msc->touches[id].scroll_y_hr = y; + step_y_hr = 0; + } + + step_y_hr /= step_hr; + if (step_y_hr != 0 && + msc->touches[id].scroll_y_active) { + msc->touches[id].scroll_y_hr -= step_y_hr * + step_hr; + input_report_rel(input, + REL_WHEEL_HI_RES, + step_y_hr * SCROLL_HR_MULT); + } break; } } @@ -623,6 +673,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd if (emulate_scroll_wheel) { __set_bit(REL_WHEEL, input->relbit); __set_bit(REL_HWHEEL, input->relbit); + __set_bit(REL_WHEEL_HI_RES, input->relbit); + __set_bit(REL_HWHEEL_HI_RES, input->relbit); } } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD){ /* input->keybit is initialized with incorrect button info @@ -835,7 +887,7 @@ static int magicmouse_probe(struct hid_device *hdev, if (id->vendor == USB_VENDOR_ID_APPLE && id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE) - return 0; + return -ENODEV; msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { @@ -922,7 +974,8 @@ static int magicmouse_probe(struct hid_device *hdev, static void magicmouse_remove(struct hid_device *hdev) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); - cancel_delayed_work_sync(&msc->work); + if (msc) + cancel_delayed_work_sync(&msc->work); hid_hw_stop(hdev); }