Skip to content

Commit feb8461

Browse files
committed
macos: reset double click when mouse is moved
1 parent 2d1a037 commit feb8461

File tree

1 file changed

+155
-148
lines changed

1 file changed

+155
-148
lines changed

input-emulation/src/macos.rs

Lines changed: 155 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl MacOSEmulation {
8888
button_state,
8989
previous_button: None,
9090
previous_button_click: None,
91-
button_click_state: 1,
91+
button_click_state: 0,
9292
repeat_task: None,
9393
notify_repeat_task: Arc::new(Notify::new()),
9494
modifier_state: Rc::new(Cell::new(XMods::empty())),
@@ -244,158 +244,165 @@ impl Emulation for MacOSEmulation {
244244
) -> Result<(), EmulationError> {
245245
log::trace!("{event:?}");
246246
match event {
247-
Event::Pointer(pointer_event) => match pointer_event {
248-
PointerEvent::Motion { time: _, dx, dy } => {
249-
let mut mouse_location = match self.get_mouse_location() {
250-
Some(l) => l,
251-
None => {
252-
log::warn!("could not get mouse location!");
253-
return Ok(());
247+
Event::Pointer(pointer_event) => {
248+
match pointer_event {
249+
PointerEvent::Motion { time: _, dx, dy } => {
250+
let mut mouse_location = match self.get_mouse_location() {
251+
Some(l) => l,
252+
None => {
253+
log::warn!("could not get mouse location!");
254+
return Ok(());
255+
}
256+
};
257+
258+
let (new_mouse_x, new_mouse_y) =
259+
clamp_to_screen_space(mouse_location.x, mouse_location.y, dx, dy);
260+
261+
mouse_location.x = new_mouse_x;
262+
mouse_location.y = new_mouse_y;
263+
264+
let mut event_type = CGEventType::MouseMoved;
265+
if self.button_state.left {
266+
event_type = CGEventType::LeftMouseDragged
267+
} else if self.button_state.right {
268+
event_type = CGEventType::RightMouseDragged
269+
} else if self.button_state.center {
270+
event_type = CGEventType::OtherMouseDragged
271+
};
272+
let event = match CGEvent::new_mouse_event(
273+
self.event_source.clone(),
274+
event_type,
275+
mouse_location,
276+
CGMouseButton::Left,
277+
) {
278+
Ok(e) => e,
279+
Err(_) => {
280+
log::warn!("mouse event creation failed!");
281+
return Ok(());
282+
}
283+
};
284+
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_X, dx as i64);
285+
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_Y, dy as i64);
286+
event.post(CGEventTapLocation::HID);
287+
}
288+
PointerEvent::Button {
289+
time: _,
290+
button,
291+
state,
292+
} => {
293+
let (event_type, mouse_button) = match (button, state) {
294+
(BTN_LEFT, 1) => (CGEventType::LeftMouseDown, CGMouseButton::Left),
295+
(BTN_LEFT, 0) => (CGEventType::LeftMouseUp, CGMouseButton::Left),
296+
(BTN_RIGHT, 1) => (CGEventType::RightMouseDown, CGMouseButton::Right),
297+
(BTN_RIGHT, 0) => (CGEventType::RightMouseUp, CGMouseButton::Right),
298+
(BTN_MIDDLE, 1) => (CGEventType::OtherMouseDown, CGMouseButton::Center),
299+
(BTN_MIDDLE, 0) => (CGEventType::OtherMouseUp, CGMouseButton::Center),
300+
_ => {
301+
log::warn!("invalid button event: {button},{state}");
302+
return Ok(());
303+
}
304+
};
305+
// store button state
306+
self.button_state[mouse_button] = state == 1;
307+
308+
// update previous button state
309+
if state == 1 {
310+
if self.previous_button.is_some_and(|b| b.eq(&mouse_button))
311+
&& self
312+
.previous_button_click
313+
.is_some_and(|i| i.elapsed() < DOUBLE_CLICK_INTERVAL)
314+
{
315+
self.button_click_state += 1;
316+
} else {
317+
self.button_click_state = 1;
318+
}
319+
self.previous_button = Some(mouse_button);
320+
self.previous_button_click = Some(Instant::now());
254321
}
255-
};
256322

257-
let (new_mouse_x, new_mouse_y) =
258-
clamp_to_screen_space(mouse_location.x, mouse_location.y, dx, dy);
259-
260-
mouse_location.x = new_mouse_x;
261-
mouse_location.y = new_mouse_y;
262-
263-
let mut event_type = CGEventType::MouseMoved;
264-
if self.button_state.left {
265-
event_type = CGEventType::LeftMouseDragged
266-
} else if self.button_state.right {
267-
event_type = CGEventType::RightMouseDragged
268-
} else if self.button_state.center {
269-
event_type = CGEventType::OtherMouseDragged
270-
};
271-
let event = match CGEvent::new_mouse_event(
272-
self.event_source.clone(),
273-
event_type,
274-
mouse_location,
275-
CGMouseButton::Left,
276-
) {
277-
Ok(e) => e,
278-
Err(_) => {
279-
log::warn!("mouse event creation failed!");
280-
return Ok(());
281-
}
282-
};
283-
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_X, dx as i64);
284-
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_Y, dy as i64);
285-
event.post(CGEventTapLocation::HID);
286-
}
287-
PointerEvent::Button {
288-
time: _,
289-
button,
290-
state,
291-
} => {
292-
let (event_type, mouse_button) = match (button, state) {
293-
(BTN_LEFT, 1) => (CGEventType::LeftMouseDown, CGMouseButton::Left),
294-
(BTN_LEFT, 0) => (CGEventType::LeftMouseUp, CGMouseButton::Left),
295-
(BTN_RIGHT, 1) => (CGEventType::RightMouseDown, CGMouseButton::Right),
296-
(BTN_RIGHT, 0) => (CGEventType::RightMouseUp, CGMouseButton::Right),
297-
(BTN_MIDDLE, 1) => (CGEventType::OtherMouseDown, CGMouseButton::Center),
298-
(BTN_MIDDLE, 0) => (CGEventType::OtherMouseUp, CGMouseButton::Center),
299-
_ => {
300-
log::warn!("invalid button event: {button},{state}");
301-
return Ok(());
302-
}
303-
};
304-
// store button state
305-
self.button_state[mouse_button] = state == 1;
306-
307-
// update previous button state
308-
if state == 1 {
309-
if self.previous_button.is_some_and(|b| b.eq(&mouse_button))
310-
&& self
311-
.previous_button_click
312-
.is_some_and(|i| i.elapsed() < DOUBLE_CLICK_INTERVAL)
313-
{
314-
self.button_click_state += 1;
315-
} else {
316-
self.button_click_state = 1;
317-
}
318-
self.previous_button = Some(mouse_button);
319-
self.previous_button_click = Some(Instant::now());
323+
log::debug!("click_state: {}", self.button_click_state);
324+
let location = self.get_mouse_location().unwrap();
325+
let event = match CGEvent::new_mouse_event(
326+
self.event_source.clone(),
327+
event_type,
328+
location,
329+
mouse_button,
330+
) {
331+
Ok(e) => e,
332+
Err(()) => {
333+
log::warn!("mouse event creation failed!");
334+
return Ok(());
335+
}
336+
};
337+
event.set_integer_value_field(
338+
EventField::MOUSE_EVENT_CLICK_STATE,
339+
self.button_click_state,
340+
);
341+
event.post(CGEventTapLocation::HID);
342+
}
343+
PointerEvent::Axis {
344+
time: _,
345+
axis,
346+
value,
347+
} => {
348+
let value = value as i32;
349+
let (count, wheel1, wheel2, wheel3) = match axis {
350+
0 => (1, value, 0, 0), // 0 = vertical => 1 scroll wheel device (y axis)
351+
1 => (2, 0, value, 0), // 1 = horizontal => 2 scroll wheel devices (y, x) -> (0, x)
352+
_ => {
353+
log::warn!("invalid scroll event: {axis}, {value}");
354+
return Ok(());
355+
}
356+
};
357+
let event = match CGEvent::new_scroll_event(
358+
self.event_source.clone(),
359+
ScrollEventUnit::PIXEL,
360+
count,
361+
wheel1,
362+
wheel2,
363+
wheel3,
364+
) {
365+
Ok(e) => e,
366+
Err(()) => {
367+
log::warn!("scroll event creation failed!");
368+
return Ok(());
369+
}
370+
};
371+
event.post(CGEventTapLocation::HID);
372+
}
373+
PointerEvent::AxisDiscrete120 { axis, value } => {
374+
const LINES_PER_STEP: i32 = 3;
375+
let (count, wheel1, wheel2, wheel3) = match axis {
376+
0 => (1, value / (120 / LINES_PER_STEP), 0, 0), // 0 = vertical => 1 scroll wheel device (y axis)
377+
1 => (2, 0, value / (120 / LINES_PER_STEP), 0), // 1 = horizontal => 2 scroll wheel devices (y, x) -> (0, x)
378+
_ => {
379+
log::warn!("invalid scroll event: {axis}, {value}");
380+
return Ok(());
381+
}
382+
};
383+
let event = match CGEvent::new_scroll_event(
384+
self.event_source.clone(),
385+
ScrollEventUnit::LINE,
386+
count,
387+
wheel1,
388+
wheel2,
389+
wheel3,
390+
) {
391+
Ok(e) => e,
392+
Err(()) => {
393+
log::warn!("scroll event creation failed!");
394+
return Ok(());
395+
}
396+
};
397+
event.post(CGEventTapLocation::HID);
320398
}
321-
322-
log::debug!("click_state: {}", self.button_click_state);
323-
let location = self.get_mouse_location().unwrap();
324-
let event = match CGEvent::new_mouse_event(
325-
self.event_source.clone(),
326-
event_type,
327-
location,
328-
mouse_button,
329-
) {
330-
Ok(e) => e,
331-
Err(()) => {
332-
log::warn!("mouse event creation failed!");
333-
return Ok(());
334-
}
335-
};
336-
event.set_integer_value_field(
337-
EventField::MOUSE_EVENT_CLICK_STATE,
338-
self.button_click_state,
339-
);
340-
event.post(CGEventTapLocation::HID);
341-
}
342-
PointerEvent::Axis {
343-
time: _,
344-
axis,
345-
value,
346-
} => {
347-
let value = value as i32;
348-
let (count, wheel1, wheel2, wheel3) = match axis {
349-
0 => (1, value, 0, 0), // 0 = vertical => 1 scroll wheel device (y axis)
350-
1 => (2, 0, value, 0), // 1 = horizontal => 2 scroll wheel devices (y, x) -> (0, x)
351-
_ => {
352-
log::warn!("invalid scroll event: {axis}, {value}");
353-
return Ok(());
354-
}
355-
};
356-
let event = match CGEvent::new_scroll_event(
357-
self.event_source.clone(),
358-
ScrollEventUnit::PIXEL,
359-
count,
360-
wheel1,
361-
wheel2,
362-
wheel3,
363-
) {
364-
Ok(e) => e,
365-
Err(()) => {
366-
log::warn!("scroll event creation failed!");
367-
return Ok(());
368-
}
369-
};
370-
event.post(CGEventTapLocation::HID);
371399
}
372-
PointerEvent::AxisDiscrete120 { axis, value } => {
373-
const LINES_PER_STEP: i32 = 3;
374-
let (count, wheel1, wheel2, wheel3) = match axis {
375-
0 => (1, value / (120 / LINES_PER_STEP), 0, 0), // 0 = vertical => 1 scroll wheel device (y axis)
376-
1 => (2, 0, value / (120 / LINES_PER_STEP), 0), // 1 = horizontal => 2 scroll wheel devices (y, x) -> (0, x)
377-
_ => {
378-
log::warn!("invalid scroll event: {axis}, {value}");
379-
return Ok(());
380-
}
381-
};
382-
let event = match CGEvent::new_scroll_event(
383-
self.event_source.clone(),
384-
ScrollEventUnit::LINE,
385-
count,
386-
wheel1,
387-
wheel2,
388-
wheel3,
389-
) {
390-
Ok(e) => e,
391-
Err(()) => {
392-
log::warn!("scroll event creation failed!");
393-
return Ok(());
394-
}
395-
};
396-
event.post(CGEventTapLocation::HID);
400+
401+
// reset button click state in case it's not a button event
402+
if !matches!(pointer_event, PointerEvent::Button { .. }) {
403+
self.button_click_state = 0;
397404
}
398-
},
405+
}
399406
Event::Keyboard(keyboard_event) => match keyboard_event {
400407
KeyboardEvent::Key {
401408
time: _,

0 commit comments

Comments
 (0)