Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34594c3c authored by Harry Cutts's avatar Harry Cutts
Browse files

InputVerifier: make action_button a field of the action enum

Only MotionEvents with a button press or release action should have an
action button. Let's express this in the data structure by making
action_button a field of the relevant MotionActions, instead of a
separate field of MotionEvent that could potentially be set on
non-button actions.

This involves moving the translation from input_bindgen constants to
MotionAction into lib.rs, which I think makes more sense (as it keeps
the language interfacing code contained there), but also means we have
to move one piece of validation there too.

Bug: 245989146
Test: $ atest --host libinput_rust_test
Test: enable the verifier, check everything works as usual
Flag: EXEMPT refactor
Change-Id: Ida17429b0e12247b63a3ae44bab63e421d9fff0f
parent c932b071
Loading
Loading
Loading
Loading
+25 −11
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ bitflags! {

/// A rust enum representation of a MotionEvent action.
#[repr(u32)]
#[derive(Eq, PartialEq)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum MotionAction {
    /// ACTION_DOWN
    Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN,
@@ -132,9 +132,15 @@ pub enum MotionAction {
    /// ACTION_SCROLL
    Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL,
    /// ACTION_BUTTON_PRESS
    ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
    ButtonPress {
        /// The button being pressed.
        action_button: MotionButton,
    } = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
    /// ACTION_BUTTON_RELEASE
    ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
    ButtonRelease {
        /// The button being released.
        action_button: MotionButton,
    } = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
}

impl fmt::Display for MotionAction {
@@ -153,14 +159,20 @@ impl fmt::Display for MotionAction {
            MotionAction::Scroll => write!(f, "SCROLL"),
            MotionAction::HoverEnter => write!(f, "HOVER_ENTER"),
            MotionAction::HoverExit => write!(f, "HOVER_EXIT"),
            MotionAction::ButtonPress => write!(f, "BUTTON_PRESS"),
            MotionAction::ButtonRelease => write!(f, "BUTTON_RELEASE"),
            MotionAction::ButtonPress { action_button } => {
                write!(f, "BUTTON_PRESS({action_button:?})")
            }
            MotionAction::ButtonRelease { action_button } => {
                write!(f, "BUTTON_RELEASE({action_button:?})")
            }
        }
    }
}

impl From<u32> for MotionAction {
    fn from(action: u32) -> Self {
impl MotionAction {
    /// Creates a [`MotionAction`] from an `AMOTION_EVENT_ACTION_…` constant and an action button
    /// (which should be empty for all actions except `BUTTON_PRESS` and `…_RELEASE`).
    pub fn from_code(action: u32, action_button: MotionButton) -> Self {
        let (action_masked, action_index) = MotionAction::breakdown_action(action);
        match action_masked {
            input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down,
@@ -178,14 +190,16 @@ impl From<u32> for MotionAction {
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit,
            input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress,
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease,
            _ => panic!("Unknown action: {}", action),
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => {
                MotionAction::ButtonPress { action_button }
            }
            input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => {
                MotionAction::ButtonRelease { action_button }
            }
            _ => panic!("Unknown action: {}", action),
        }
    }

impl MotionAction {
    fn breakdown_action(action: u32) -> (u32, usize) {
        let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK;
        let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
+104 −198

File changed.

Preview size limit exceeded, changes collapsed.

+55 −2
Original line number Diff line number Diff line
@@ -152,11 +152,23 @@ fn process_movement(
             buttons need to be added to MotionButton."
        );
    };
    let motion_action = MotionAction::from_code(action, motion_action_button);
    if motion_action_button != MotionButton::empty() {
        match motion_action {
            MotionAction::ButtonPress { action_button: _ }
            | MotionAction::ButtonRelease { action_button: _ } => {}
            _ => {
                return format!(
                    "Invalid {motion_action} event: has action button {motion_action_button:?} but \
                     is not a button action"
                );
            }
        }
    }
    let result = verifier.process_movement(NotifyMotionArgs {
        device_id: DeviceId(device_id),
        source: Source::from_bits(source).unwrap(),
        action,
        action_button: motion_action_button,
        action: motion_action,
        pointer_properties,
        flags: motion_flags,
        button_state: motion_button_state,
@@ -227,3 +239,44 @@ fn process_key(
    }
    classifier.process_key(DeviceId(device_id), evdev_code, modifier_state.unwrap());
}

#[cfg(test)]
mod tests {
    use crate::create_input_verifier;
    use crate::process_movement;
    use crate::RustPointerProperties;

    const BASE_POINTER_PROPERTIES: [RustPointerProperties; 1] = [RustPointerProperties { id: 0 }];

    #[test]
    fn verify_nonbutton_action_with_action_button() {
        let mut verifier = create_input_verifier("Test".to_string(), /*verify_buttons*/ true);
        assert!(process_movement(
            &mut verifier,
            1,
            input_bindgen::AINPUT_SOURCE_MOUSE,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
            input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
            &BASE_POINTER_PROPERTIES,
            0,
            0,
        )
        .contains("button action"));
    }

    #[test]
    fn verify_nonbutton_action_with_action_button_and_button_state() {
        let mut verifier = create_input_verifier("Test".to_string(), /*verify_buttons*/ true);
        assert!(process_movement(
            &mut verifier,
            1,
            input_bindgen::AINPUT_SOURCE_MOUSE,
            input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
            input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
            &BASE_POINTER_PROPERTIES,
            0,
            input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
        )
        .contains("button action"));
    }
}