event.rs

  1use x11rb::protocol::{
  2    xinput,
  3    xproto::{self, ModMask},
  4};
  5
  6use crate::{Modifiers, MouseButton, NavigationDirection};
  7
  8pub(crate) enum ButtonOrScroll {
  9    Button(MouseButton),
 10    Scroll(ScrollDirection),
 11}
 12
 13pub(crate) enum ScrollDirection {
 14    Up,
 15    Down,
 16    Left,
 17    Right,
 18}
 19
 20pub(crate) fn button_or_scroll_from_event_detail(detail: u32) -> Option<ButtonOrScroll> {
 21    Some(match detail {
 22        1 => ButtonOrScroll::Button(MouseButton::Left),
 23        2 => ButtonOrScroll::Button(MouseButton::Middle),
 24        3 => ButtonOrScroll::Button(MouseButton::Right),
 25        4 => ButtonOrScroll::Scroll(ScrollDirection::Up),
 26        5 => ButtonOrScroll::Scroll(ScrollDirection::Down),
 27        6 => ButtonOrScroll::Scroll(ScrollDirection::Left),
 28        7 => ButtonOrScroll::Scroll(ScrollDirection::Right),
 29        8 => ButtonOrScroll::Button(MouseButton::Navigate(NavigationDirection::Back)),
 30        9 => ButtonOrScroll::Button(MouseButton::Navigate(NavigationDirection::Forward)),
 31        _ => return None,
 32    })
 33}
 34
 35pub(crate) fn modifiers_from_state(state: xproto::KeyButMask) -> Modifiers {
 36    Modifiers {
 37        control: state.contains(xproto::KeyButMask::CONTROL),
 38        alt: state.contains(xproto::KeyButMask::MOD1),
 39        shift: state.contains(xproto::KeyButMask::SHIFT),
 40        platform: state.contains(xproto::KeyButMask::MOD4),
 41        function: false,
 42    }
 43}
 44
 45pub(crate) fn modifiers_from_xinput_info(modifier_info: xinput::ModifierInfo) -> Modifiers {
 46    Modifiers {
 47        control: modifier_info.effective as u16 & ModMask::CONTROL.bits()
 48            == ModMask::CONTROL.bits(),
 49        alt: modifier_info.effective as u16 & ModMask::M1.bits() == ModMask::M1.bits(),
 50        shift: modifier_info.effective as u16 & ModMask::SHIFT.bits() == ModMask::SHIFT.bits(),
 51        platform: modifier_info.effective as u16 & ModMask::M4.bits() == ModMask::M4.bits(),
 52        function: false,
 53    }
 54}
 55
 56pub(crate) fn pressed_button_from_mask(button_mask: u32) -> Option<MouseButton> {
 57    Some(if button_mask & 2 == 2 {
 58        MouseButton::Left
 59    } else if button_mask & 4 == 4 {
 60        MouseButton::Middle
 61    } else if button_mask & 8 == 8 {
 62        MouseButton::Right
 63    } else {
 64        return None;
 65    })
 66}
 67
 68pub(crate) fn get_valuator_axis_index(
 69    valuator_mask: &Vec<u32>,
 70    valuator_number: u16,
 71) -> Option<usize> {
 72    // XInput valuator masks have a 1 at the bit indexes corresponding to each
 73    // valuator present in this event's axisvalues. Axisvalues is ordered from
 74    // lowest valuator number to highest, so counting bits before the 1 bit for
 75    // this valuator yields the index in axisvalues.
 76    if bit_is_set_in_vec(valuator_mask, valuator_number) {
 77        Some(popcount_upto_bit_index(valuator_mask, valuator_number) as usize)
 78    } else {
 79        None
 80    }
 81}
 82
 83/// Returns the number of 1 bits in `bit_vec` for all bits where `i < bit_index`.
 84fn popcount_upto_bit_index(bit_vec: &Vec<u32>, bit_index: u16) -> u32 {
 85    let array_index = bit_index as usize / 32;
 86    let popcount: u32 = bit_vec
 87        .get(array_index)
 88        .map_or(0, |bits| keep_bits_upto(*bits, bit_index % 32).count_ones());
 89    if array_index == 0 {
 90        popcount
 91    } else {
 92        // Valuator numbers over 32 probably never occur for scroll position, but may as well
 93        // support it.
 94        let leading_popcount: u32 = bit_vec
 95            .iter()
 96            .take(array_index)
 97            .map(|bits| bits.count_ones())
 98            .sum();
 99        popcount + leading_popcount
100    }
101}
102
103fn bit_is_set_in_vec(bit_vec: &Vec<u32>, bit_index: u16) -> bool {
104    let array_index = bit_index as usize / 32;
105    bit_vec
106        .get(array_index)
107        .is_some_and(|bits| bit_is_set(*bits, bit_index % 32))
108}
109
110fn bit_is_set(bits: u32, bit_index: u16) -> bool {
111    bits & (1 << bit_index) != 0
112}
113
114/// Sets every bit with `i >= bit_index` to 0.
115fn keep_bits_upto(bits: u32, bit_index: u16) -> u32 {
116    if bit_index == 0 {
117        0
118    } else if bit_index >= 32 {
119        u32::MAX
120    } else {
121        bits & ((1 << bit_index) - 1)
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_get_valuator_axis_index() {
131        assert!(get_valuator_axis_index(&vec![0b11], 0) == Some(0));
132        assert!(get_valuator_axis_index(&vec![0b11], 1) == Some(1));
133        assert!(get_valuator_axis_index(&vec![0b11], 2) == None);
134
135        assert!(get_valuator_axis_index(&vec![0b100], 0) == None);
136        assert!(get_valuator_axis_index(&vec![0b100], 1) == None);
137        assert!(get_valuator_axis_index(&vec![0b100], 2) == Some(0));
138        assert!(get_valuator_axis_index(&vec![0b100], 3) == None);
139
140        assert!(get_valuator_axis_index(&vec![0b1010, 0], 0) == None);
141        assert!(get_valuator_axis_index(&vec![0b1010, 0], 1) == Some(0));
142        assert!(get_valuator_axis_index(&vec![0b1010, 0], 2) == None);
143        assert!(get_valuator_axis_index(&vec![0b1010, 0], 3) == Some(1));
144
145        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 0) == None);
146        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 1) == Some(0));
147        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 2) == None);
148        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 3) == Some(1));
149        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 32) == Some(2));
150        assert!(get_valuator_axis_index(&vec![0b1010, 0b1], 33) == None);
151
152        assert!(get_valuator_axis_index(&vec![0b1010, 0b101], 34) == Some(3));
153    }
154}