Skip to content

Commit

Permalink
Add ability to stop scrolling when moving the mouse.
Browse files Browse the repository at this point in the history
This update brings a feature that allows you to stop scrolling if the mouse is moving. It is still very rough, but it works.
  • Loading branch information
RicardoEPRodrigues committed Jun 7, 2021
1 parent ec80ec6 commit 71570b7
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 66 deletions.
2 changes: 1 addition & 1 deletion build-deb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ETC_DIR="/etc"
PKG_DIR="/pkg-debian"
OPT_DIR="/opt/magicmouse-hid"

DEB="magicmouse-hid_2.0.0-0.deb"
DEB="magicmouse-hid_2.1.0-0.deb"

cp -rf ${DIR}${ETC_DIR} ${DIR}${PKG_DIR}

Expand Down
7 changes: 4 additions & 3 deletions etc/modprobe.d/hid-magicmouse.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
options hid-magicmouse \
scroll_acceleration=1 \
scroll_speed=25 \
stop_scroll_while_moving=1 \
scroll_speed=10 \
middle_click_3finger=1 \
scroll_delay_pos_x=200 \
scroll_delay_pos_y=200
scroll_delay_pos_x=300 \
scroll_delay_pos_y=250
139 changes: 77 additions & 62 deletions linux/drivers/hid/hid-magicmouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ static bool emulate_scroll_wheel = true;
module_param(emulate_scroll_wheel, bool, 0644);
MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");

static bool stop_scroll_while_moving = true;
module_param(stop_scroll_while_moving, bool, 0644);
MODULE_PARM_DESC(stop_scroll_while_moving, "Stop scrolling whenever the mouse moves");

static unsigned int scroll_speed = 32;
static int param_set_scroll_speed(const char *val,
const struct kernel_param *kp) {
Expand Down Expand Up @@ -157,12 +161,12 @@ struct magicmouse_sc {
int ntouches;
int scroll_accel;
unsigned long scroll_jiffies;
int x;
int y;

struct {
short x;
short y;
short scroll_x_start;
short scroll_y_start;
short scroll_x;
short scroll_y;
u8 size;
Expand Down Expand Up @@ -265,7 +269,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
}

static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id,
u8 *tdata, int npoints)
u8 *tdata, int npoints, int mouse_loc_x, int mouse_loc_y)
{
struct input_dev *input = msc->input;
int id, x, y, size, orientation, touch_major, touch_minor, state, down;
Expand Down Expand Up @@ -343,54 +347,61 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id,
int step_x = msc->touches[id].scroll_x - x;
int step_y = msc->touches[id].scroll_y - y;

/* Calculate and apply the scroll motion. */
switch (state) {
case TOUCH_STATE_START:
msc->touches[id].scroll_x_start = x;
msc->touches[id].scroll_y_start = y;
msc->touches[id].scroll_x = x;
msc->touches[id].scroll_y = y;

/* Reset acceleration after half a second. */
if (scroll_acceleration && time_before(now,
msc->scroll_jiffies + HZ / 2))
msc->scroll_accel = max_t(int,
msc->scroll_accel - 1, 1);
else
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;

break;
case TOUCH_STATE_DRAG:
/* Add a position delay since the drag start in which
* drag events are not registered. This decreases the
* sensitivity of dragging on Magic Mouse devices.
*/
if (abs(step_x) < scroll_delay_pos_x) {
step_x = 0;
} else {
step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
}

if (abs(step_y) < scroll_delay_pos_y) {
step_y = 0;
} else {
step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
}

if (step_x != 0) {
msc->touches[id].scroll_x -= step_x *
(64 - scroll_speed) * msc->scroll_accel;
msc->scroll_jiffies = now;
input_report_rel(input, REL_HWHEEL, -step_x);
}
/* Determine if the mouse has moved, if so then disable scrolling. */
bool continue_scroll = true;
if (stop_scroll_while_moving)
{
continue_scroll = msc->x == mouse_loc_x && msc->y == mouse_loc_y;
}

if (step_y != 0) {
msc->touches[id].scroll_y -= step_y *
(64 - scroll_speed) * msc->scroll_accel;
msc->scroll_jiffies = now;
input_report_rel(input, REL_WHEEL, step_y);
if (continue_scroll) {
/* Calculate and apply the scroll motion. */
switch (state) {
case TOUCH_STATE_START:
msc->touches[id].scroll_x = x;
msc->touches[id].scroll_y = y;

/* Reset acceleration after half a second. */
if (scroll_acceleration && time_before(now,
msc->scroll_jiffies + HZ / 2))
msc->scroll_accel = max_t(int,
msc->scroll_accel - 1, 1);
else
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;

break;
case TOUCH_STATE_DRAG:
/* Add a position delay since the drag start in which
* drag events are not registered. This decreases the
* sensitivity of dragging on Magic Mouse devices.
*/
if (abs(step_x) < scroll_delay_pos_x) {
step_x = 0;
} else {
step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
}

if (abs(step_y) < scroll_delay_pos_y) {
step_y = 0;
} else {
step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
}

if (step_x != 0) {
msc->touches[id].scroll_x -= step_x *
(64 - scroll_speed) * msc->scroll_accel;
msc->scroll_jiffies = now;
input_report_rel(input, REL_HWHEEL, -step_x);
}

if (step_y != 0) {
msc->touches[id].scroll_y -= step_y *
(64 - scroll_speed) * msc->scroll_accel;
msc->scroll_jiffies = now;
input_report_rel(input, REL_WHEEL, step_y);
}
break;
}
break;
}
}

Expand Down Expand Up @@ -444,7 +455,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
}
msc->ntouches = 0;
for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 9 + 4, npoints);
magicmouse_emit_touch(msc, ii, data + ii * 9 + 4, npoints, 0, 0);

clicks = data[1];
break;
Expand All @@ -460,7 +471,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
}
msc->ntouches = 0;
for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 9 + 12, npoints);
magicmouse_emit_touch(msc, ii, data + ii * 9 + 12, npoints, 0, 0);

clicks = data[1];
break;
Expand All @@ -475,17 +486,17 @@ static int magicmouse_raw_event(struct hid_device *hdev,
return 0;
}
msc->ntouches = 0;
for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6, npoints);

/* When emulating three-button mode, it is important
* to have the current touch information before
* generating a click event.
*/
x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
clicks = data[3];
for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6, npoints, x, y);

clicks = data[3];
/* The following bits provide a device specific timestamp. They
* are unused here.
*
Expand Down Expand Up @@ -524,6 +535,14 @@ static int magicmouse_raw_event(struct hid_device *hdev,
return 0;
}
msc->ntouches = 0;

/* When emulating three-button mode, it is important
* to have the current touch information before
* generating a click event.
*/
x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;

// print the values of the first 14 bytes of data and number of points and size.
// printk("The contents of npoints are: %i\n", npoints);
// printk("Size is: %i\n", size);
Expand All @@ -533,14 +552,8 @@ static int magicmouse_raw_event(struct hid_device *hdev,
// printk("data %i is: %i\n", jj, d);
// }
for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 14, npoints);

/* When emulating three-button mode, it is important
* to have the current touch information before
* generating a click event.
*/
x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
magicmouse_emit_touch(msc, ii, data + ii * 8 + 14, npoints, x, y);

clicks = data[1];
break;
case DOUBLE_REPORT_ID:
Expand All @@ -557,6 +570,8 @@ static int magicmouse_raw_event(struct hid_device *hdev,

if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
msc->x = x;
msc->y = y;
magicmouse_emit_buttons(msc, clicks & 3);
input_report_rel(input, REL_X, x);
input_report_rel(input, REL_Y, y);
Expand Down

0 comments on commit 71570b7

Please sign in to comment.