use super::*;
const GESTURE: &[u16] = &[reprog_controls::GESTURE_BUTTON_CID];
const PANEL: &[u16] = &[reprog_controls::HAPTIC_PANEL_CID];
const BOTH: &[u16] = &[
reprog_controls::GESTURE_BUTTON_CID,
reprog_controls::HAPTIC_PANEL_CID,
];
fn reporting(
diverted: bool,
remap: Option<reprog_controls::ControlId>,
) -> reprog_controls::CidReporting {
reprog_controls::CidReporting {
cid: reprog_controls::ControlId(reprog_controls::GESTURE_BUTTON_CID),
diverted,
persistently_diverted: true,
force_raw_xy: true,
raw_xy: true,
remap,
analytics_key_events: true,
raw_wheel: true,
}
}
#[test]
fn restore_clears_a_diversion_it_found_already_set() {
let change = undivert_change(reporting(true, None));
assert_eq!(change.diverted, Some(false));
assert_eq!(change.raw_xy, Some(false));
}
#[test]
fn restore_returns_the_remap_target_and_touches_nothing_else() {
let remap = reprog_controls::ControlId(0x0053);
let change = undivert_change(reporting(false, Some(remap)));
assert_eq!(change.remap, Some(remap));
assert_eq!(change.persistently_diverted, None);
assert_eq!(change.force_raw_xy, None);
assert_eq!(change.analytics_key_events, None);
assert_eq!(change.raw_wheel, None);
}
fn press() -> RawControlEvent {
RawControlEvent::DivertedButtons([reprog_controls::GESTURE_BUTTON_CID, 0, 0, 0])
}
fn panel_press() -> RawControlEvent {
RawControlEvent::DivertedButtons([reprog_controls::HAPTIC_PANEL_CID, 0, 0, 0])
}
fn both_press() -> RawControlEvent {
RawControlEvent::DivertedButtons([
reprog_controls::GESTURE_BUTTON_CID,
reprog_controls::HAPTIC_PANEL_CID,
0,
0,
])
}
fn release() -> RawControlEvent {
RawControlEvent::DivertedButtons([0, 0, 0, 0])
}
#[test]
fn a_still_held_second_source_takes_over_when_the_holder_releases() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), BOTH, &[], &[], &tx);
handle_reprog(&mut acc, both_press(), BOTH, &[], &[], &tx);
handle_reprog(&mut acc, panel_press(), BOTH, &[], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Click
)),
"the released holder still clicks"
);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
BOTH,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::HapticPanel,
GestureDirection::Right
)),
"the taken-over hold dispatches through the panel's own map"
);
handle_reprog(&mut acc, release(), BOTH, &[], &[], &tx);
assert!(
rx.try_recv().is_err(),
"a committed takeover swipe must not also click on release"
);
}
#[test]
fn raw_xy_during_a_two_source_overlap_is_dropped_not_misattributed() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), BOTH, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(&mut acc, both_press(), BOTH, &[], &[], &tx);
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
BOTH,
&[],
&[],
&tx,
);
assert!(
rx.try_recv().is_err(),
"ambiguous overlap motion must not commit a swipe"
);
handle_reprog(&mut acc, press(), BOTH, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
BOTH,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Right
)),
"the original hold resumes once the overlap ends"
);
}
#[test]
fn a_same_report_swap_to_the_panel_still_discards_its_contact_jump() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), BOTH, &[], &[], &tx);
handle_reprog(&mut acc, panel_press(), BOTH, &[], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Click
)),
"the swapped-out holder still clicks"
);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: -3000, dy: 40 },
BOTH,
&[],
&[],
&tx,
);
assert!(
rx.try_recv().is_err(),
"the panel's contact jump must not commit a swipe"
);
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
BOTH,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::HapticPanel,
GestureDirection::Right
))
);
}
#[test]
fn quick_tap_is_a_click_even_while_the_cursor_moves() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), GESTURE, &[], &[], &tx);
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
GESTURE,
&[],
&[],
&tx,
);
handle_reprog(&mut acc, release(), GESTURE, &[], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Click
))
);
assert!(
rx.try_recv().is_err(),
"a quick tap emits exactly one click"
);
}
#[test]
fn a_held_gesture_commits_a_swipe_and_does_not_also_click() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), GESTURE, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
GESTURE,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Right
))
);
handle_reprog(&mut acc, release(), GESTURE, &[], &[], &tx);
assert!(
rx.try_recv().is_err(),
"a committed swipe must not also click on release"
);
}
#[test]
fn the_haptic_panel_gestures_when_diverted_for_gestures() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, panel_press(), PANEL, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: -3000, dy: 40 },
PANEL,
&[],
&[],
&tx,
);
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 5, dy: -120 },
PANEL,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::HapticPanel,
GestureDirection::Up
))
);
handle_reprog(&mut acc, release(), PANEL, &[], &[], &tx);
assert!(
rx.try_recv().is_err(),
"a committed panel swipe must not also click on release"
);
}
#[test]
fn a_quick_panel_tap_is_a_click() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, panel_press(), PANEL, &[], &[], &tx);
handle_reprog(&mut acc, release(), PANEL, &[], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::HapticPanel,
GestureDirection::Click
))
);
assert!(
rx.try_recv().is_err(),
"a panel tap emits exactly one click"
);
}
#[test]
fn the_panels_first_raw_xy_sample_after_contact_is_discarded() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, panel_press(), PANEL, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: -3000, dy: 40 },
PANEL,
&[],
&[],
&tx,
);
assert!(
rx.try_recv().is_err(),
"the contact jump must not commit a swipe"
);
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
PANEL,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::HapticPanel,
GestureDirection::Right
))
);
}
#[test]
fn the_dedicated_buttons_first_sample_is_not_discarded() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), GESTURE, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
GESTURE,
&[],
&[],
&tx,
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::Gesture(
ButtonId::GestureButton,
GestureDirection::Right
)),
"the dedicated button's very first sample still counts"
);
}
#[test]
fn an_undiverted_gesture_source_does_not_gesture() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
handle_reprog(&mut acc, press(), PANEL, &[], &[], &tx);
acc.swipe.backdate_hold_for_test();
handle_reprog(
&mut acc,
RawControlEvent::RawXy { dx: 120, dy: 5 },
PANEL,
&[],
&[],
&tx,
);
handle_reprog(&mut acc, release(), PANEL, &[], &[], &tx);
assert!(
rx.try_recv().is_err(),
"a non-owner source must neither gesture nor click"
);
}
#[test]
fn a_plain_diverted_gesture_button_presses_without_gesturing() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
let buttons = [(reprog_controls::GESTURE_BUTTON_CID, ButtonId::GestureButton)];
handle_reprog(&mut acc, press(), &[], &[], &buttons, &tx);
handle_reprog(&mut acc, release(), &[], &[], &buttons, &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::ButtonPressed(ButtonId::GestureButton, None))
);
assert!(
rx.try_recv().is_err(),
"a plain-diverted gesture button must not also emit a gesture click"
);
}
#[test]
fn a_plain_diverted_haptic_panel_presses_as_its_own_button() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
let buttons = [(reprog_controls::HAPTIC_PANEL_CID, ButtonId::HapticPanel)];
handle_reprog(&mut acc, panel_press(), &[], &[], &buttons, &tx);
handle_reprog(&mut acc, release(), &[], &[], &buttons, &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::ButtonPressed(ButtonId::HapticPanel, None))
);
assert!(
rx.try_recv().is_err(),
"a plain-diverted panel must not also emit a gesture click"
);
}
#[test]
fn a_held_dpi_button_presses_once_on_the_rising_edge() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
let dpi = reprog_controls::DPI_MODE_SHIFT_CIDS[0];
let down = RawControlEvent::DivertedButtons([dpi, 0, 0, 0]);
handle_reprog(&mut acc, down, GESTURE, &[dpi], &[], &tx);
handle_reprog(&mut acc, down, GESTURE, &[dpi], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::ButtonPressed(ButtonId::DpiToggle, None))
);
assert!(rx.try_recv().is_err(), "a held DPI button presses once");
}
#[test]
fn a_dpi_button_re_presses_after_a_release() {
let (tx, mut rx) = mpsc::unbounded_channel();
let mut acc = CaptureAccum::default();
let dpi = reprog_controls::DPI_MODE_SHIFT_CIDS[0];
let down = RawControlEvent::DivertedButtons([dpi, 0, 0, 0]);
let up = RawControlEvent::DivertedButtons([0, 0, 0, 0]);
handle_reprog(&mut acc, down, GESTURE, &[dpi], &[], &tx);
handle_reprog(&mut acc, up, GESTURE, &[dpi], &[], &tx);
handle_reprog(&mut acc, down, GESTURE, &[dpi], &[], &tx);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::ButtonPressed(ButtonId::DpiToggle, None))
);
assert_eq!(
rx.try_recv(),
Ok(CapturedInput::ButtonPressed(ButtonId::DpiToggle, None)),
"a release re-arms the rising edge"
);
assert!(
rx.try_recv().is_err(),
"press → release → press emits exactly two presses"
);
}