Merge pull request #365 from i509VCB/mouse-f/b

This commit is contained in:
Victor Brekenfeld 2021-10-27 20:03:13 +02:00 committed by GitHub
commit b890bfd768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 155 additions and 147 deletions

View File

@ -10,6 +10,9 @@
- `XdgPositionerState` moved to `XdgPopupState` and added to `XdgRequest::NewPopup` - `XdgPositionerState` moved to `XdgPopupState` and added to `XdgRequest::NewPopup`
- `PopupSurface::send_configure` now checks the protocol version and returns an `Result` - `PopupSurface::send_configure` now checks the protocol version and returns an `Result`
- `KeyboardHandle::input` filter closure now receives a `KeysymHandle` instead of a `Keysym` and returns a `FilterResult`. - `KeyboardHandle::input` filter closure now receives a `KeysymHandle` instead of a `Keysym` and returns a `FilterResult`.
- `PointerButtonEvent::button` now returns an `Option<MouseButton>`.
- `MouseButton` is now non-exhaustive.
- Remove `Other` and add `Forward` and `Back` variants to `MouseButton`. Use the new `PointerButtonEvent::button_code` in place of `Other`.
#### Backends #### Backends
@ -40,6 +43,7 @@
- `x11rb` event source integration used in anvil's XWayland implementation is now part of smithay at `utils::x11rb`. Enabled through the `x11rb_event_source` feature. - `x11rb` event source integration used in anvil's XWayland implementation is now part of smithay at `utils::x11rb`. Enabled through the `x11rb_event_source` feature.
- `KeyState`, `MouseButton`, `ButtonState` and `Axis` in `backend::input` now derive `Hash`. - `KeyState`, `MouseButton`, `ButtonState` and `Axis` in `backend::input` now derive `Hash`.
- New `DrmNode` type in drm backend. This is primarily for use a backend which needs to run as client inside another session. - New `DrmNode` type in drm backend. This is primarily for use a backend which needs to run as client inside another session.
- The button code for a `PointerButtonEvent` may now be obtained using `PointerButtonEvent::button_code`.
### Bugfixes ### Bugfixes

View File

@ -86,12 +86,7 @@ impl<Backend> AnvilState<Backend> {
fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) { fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) {
let serial = SCOUNTER.next_serial(); let serial = SCOUNTER.next_serial();
let button = match evt.button() { let button = evt.button_code();
input::MouseButton::Left => 0x110,
input::MouseButton::Right => 0x111,
input::MouseButton::Middle => 0x112,
input::MouseButton::Other(b) => b as u32,
};
let state = match evt.state() { let state = match evt.state() {
input::ButtonState::Pressed => { input::ButtonState::Pressed => {
// change the keyboard focus unless the pointer is grabbed // change the keyboard focus unless the pointer is grabbed

View File

@ -87,10 +87,17 @@ pub enum KeyState {
/// Trait for keyboard event /// Trait for keyboard event
pub trait KeyboardKeyEvent<B: InputBackend>: Event<B> { pub trait KeyboardKeyEvent<B: InputBackend>: Event<B> {
/// Code of the pressed key. See `linux/input-event-codes.h` /// Returns the numerical button code of the keyboard button.
///
/// The value will correspond to one `KEY_` constants from the Linux [input event codes] inside
/// `input-event-codes.h`.
///
/// [input event codes]: https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h
fn key_code(&self) -> u32; fn key_code(&self) -> u32;
/// State of the key /// State of the key
fn state(&self) -> KeyState; fn state(&self) -> KeyState;
/// Total number of keys pressed on all devices on the associated [`Seat`](crate::wayland::seat::Seat) /// Total number of keys pressed on all devices on the associated [`Seat`](crate::wayland::seat::Seat)
fn count(&self) -> u32; fn count(&self) -> u32;
} }
@ -110,6 +117,7 @@ impl<B: InputBackend> KeyboardKeyEvent<B> for UnusedEvent {
} }
/// A particular mouse button /// A particular mouse button
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum MouseButton { pub enum MouseButton {
/// Left mouse button /// Left mouse button
@ -118,8 +126,10 @@ pub enum MouseButton {
Middle, Middle,
/// Right mouse button /// Right mouse button
Right, Right,
/// Other mouse button with index /// Forward mouse button.
Other(u8), Forward,
/// Back mouse button.
Back,
} }
/// State of a button on a pointer device, like mouse or tablet tool. Either pressed or released /// State of a button on a pointer device, like mouse or tablet tool. Either pressed or released
@ -133,14 +143,35 @@ pub enum ButtonState {
/// Common methods pointer event generated by pressed buttons do implement /// Common methods pointer event generated by pressed buttons do implement
pub trait PointerButtonEvent<B: InputBackend>: Event<B> { pub trait PointerButtonEvent<B: InputBackend>: Event<B> {
/// Pressed button of the event /// Pressed button of the event.
fn button(&self) -> MouseButton; ///
/// This may return [`None`] if the button pressed in the event is not a standard mouse button. You may
/// obtain the button code using [`PointerButtonEvent::button_code`].
fn button(&self) -> Option<MouseButton> {
match self.button_code() {
0x110 => Some(MouseButton::Left),
0x111 => Some(MouseButton::Right),
0x112 => Some(MouseButton::Middle),
0x115 => Some(MouseButton::Forward),
0x116 => Some(MouseButton::Back),
_ => None,
}
}
/// Returns the numerical button code of the mouse button.
///
/// The value will correspond to one `BTN_` constants from the Linux [input event codes] inside
/// `input-event-codes.h`.
///
/// [input event codes]: https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h
fn button_code(&self) -> u32;
/// State of the button /// State of the button
fn state(&self) -> ButtonState; fn state(&self) -> ButtonState;
} }
impl<B: InputBackend> PointerButtonEvent<B> for UnusedEvent { impl<B: InputBackend> PointerButtonEvent<B> for UnusedEvent {
fn button(&self) -> MouseButton { fn button_code(&self) -> u32 {
match *self {} match *self {}
} }
@ -613,3 +644,17 @@ pub enum InputEvent<B: InputBackend> {
/// Special event specific of this backend /// Special event specific of this backend
Special(B::SpecialEvent), Special(B::SpecialEvent),
} }
/// Converts an xorg mouse button to the format used by libinput.
///
/// Taken from https://sources.debian.org/src/xserver-xorg-input-libinput/1.1.0-1/src/xf86libinput.c/?hl=1508#L236-L252
#[cfg(any(feature = "backend_winit", feature = "backend_x11"))]
pub(crate) fn xorg_mouse_to_libinput(xorg: u32) -> u32 {
match xorg {
0 => 0,
1 => 0x110, // BTN_LEFT
2 => 0x112, // BTN_MIDDLE
3 => 0x111, // BTN_RIGHT
_ => xorg - 8 + 0x113, // BTN_SIZE
}
}

View File

@ -188,13 +188,8 @@ impl backend::Event<LibinputInputBackend> for event::pointer::PointerButtonEvent
} }
impl backend::PointerButtonEvent<LibinputInputBackend> for event::pointer::PointerButtonEvent { impl backend::PointerButtonEvent<LibinputInputBackend> for event::pointer::PointerButtonEvent {
fn button(&self) -> backend::MouseButton { fn button_code(&self) -> u32 {
match self.button() { self.button()
0x110 => backend::MouseButton::Left,
0x111 => backend::MouseButton::Right,
0x112 => backend::MouseButton::Middle,
x => backend::MouseButton::Other(x as u8),
}
} }
fn state(&self) -> backend::ButtonState { fn state(&self) -> backend::ButtonState {

View File

@ -6,9 +6,9 @@ use winit::{
}; };
use crate::backend::input::{ use crate::backend::input::{
Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState, self, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState,
KeyboardKeyEvent, MouseButton, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, TouchCancelEvent,
TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent,
}; };
use super::{WindowSize, WinitError}; use super::{WindowSize, WinitError};
@ -170,6 +170,7 @@ pub struct WinitMouseInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) button: WinitMouseButton, pub(crate) button: WinitMouseButton,
pub(crate) state: ElementState, pub(crate) state: ElementState,
pub(crate) is_x11: bool,
} }
impl Event<WinitInput> for WinitMouseInputEvent { impl Event<WinitInput> for WinitMouseInputEvent {
@ -183,8 +184,19 @@ impl Event<WinitInput> for WinitMouseInputEvent {
} }
impl PointerButtonEvent<WinitInput> for WinitMouseInputEvent { impl PointerButtonEvent<WinitInput> for WinitMouseInputEvent {
fn button(&self) -> MouseButton { fn button_code(&self) -> u32 {
self.button.into() match self.button {
WinitMouseButton::Left => 0x110,
WinitMouseButton::Right => 0x111,
WinitMouseButton::Middle => 0x112,
WinitMouseButton::Other(b) => {
if self.is_x11 {
input::xorg_mouse_to_libinput(b as u32)
} else {
b as u32
}
}
}
} }
fn state(&self) -> ButtonState { fn state(&self) -> ButtonState {
@ -332,17 +344,6 @@ impl TouchCancelEvent<WinitInput> for WinitTouchCancelledEvent {
} }
} }
impl From<WinitMouseButton> for MouseButton {
fn from(button: WinitMouseButton) -> MouseButton {
match button {
WinitMouseButton::Left => MouseButton::Left,
WinitMouseButton::Right => MouseButton::Right,
WinitMouseButton::Middle => MouseButton::Middle,
WinitMouseButton::Other(num) => MouseButton::Other(num as u8),
}
}
}
impl From<ElementState> for KeyState { impl From<ElementState> for KeyState {
fn from(state: ElementState) -> Self { fn from(state: ElementState) -> Self {
match state { match state {

View File

@ -106,6 +106,8 @@ pub struct WinitEventLoop {
initialized: bool, initialized: bool,
size: Rc<RefCell<WindowSize>>, size: Rc<RefCell<WindowSize>>,
resize_notification: Rc<Cell<Option<Size<i32, Physical>>>>, resize_notification: Rc<Cell<Option<Size<i32, Physical>>>>,
/// Whether winit is using Wayland or X11 as it's backend.
is_x11: bool,
} }
/// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait and a corresponding /// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait and a corresponding
@ -164,16 +166,17 @@ where
debug!(log, "Window created"); debug!(log, "Window created");
let reqs = Default::default(); let reqs = Default::default();
let (display, context, surface) = { let (display, context, surface, is_x11) = {
let display = EGLDisplay::new(&winit_window, log.clone())?; let display = EGLDisplay::new(&winit_window, log.clone())?;
let context = EGLContext::new_with_config(&display, attributes, reqs, log.clone())?; let context = EGLContext::new_with_config(&display, attributes, reqs, log.clone())?;
let surface = if let Some(wl_surface) = winit_window.wayland_surface() { let (surface, is_x11) = if let Some(wl_surface) = winit_window.wayland_surface() {
debug!(log, "Winit backend: Wayland"); debug!(log, "Winit backend: Wayland");
let size = winit_window.inner_size(); let size = winit_window.inner_size();
let surface = unsafe { let surface = unsafe {
wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32) wegl::WlEglSurface::new_from_raw(wl_surface as *mut _, size.width as i32, size.height as i32)
}; };
(
EGLSurface::new( EGLSurface::new(
&display, &display,
context.pixel_format().unwrap(), context.pixel_format().unwrap(),
@ -181,9 +184,12 @@ where
surface, surface,
log.clone(), log.clone(),
) )
.map_err(EGLError::CreationFailed)? .map_err(EGLError::CreationFailed)?,
false,
)
} else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) { } else if let Some(xlib_window) = winit_window.xlib_window().map(native::XlibWindow) {
debug!(log, "Winit backend: X11"); debug!(log, "Winit backend: X11");
(
EGLSurface::new( EGLSurface::new(
&display, &display,
context.pixel_format().unwrap(), context.pixel_format().unwrap(),
@ -191,14 +197,16 @@ where
xlib_window, xlib_window,
log.clone(), log.clone(),
) )
.map_err(EGLError::CreationFailed)? .map_err(EGLError::CreationFailed)?,
true,
)
} else { } else {
unreachable!("No backends for winit other then Wayland and X11 are supported") unreachable!("No backends for winit other then Wayland and X11 are supported")
}; };
let _ = context.unbind(); let _ = context.unbind();
(display, context, surface) (display, context, surface, is_x11)
}; };
let (w, h): (u32, u32) = winit_window.inner_size().into(); let (w, h): (u32, u32) = winit_window.inner_size().into();
@ -230,6 +238,7 @@ where
initialized: false, initialized: false,
logger: log.new(o!("smithay_winit_component" => "event_loop")), logger: log.new(o!("smithay_winit_component" => "event_loop")),
size, size,
is_x11,
}, },
)) ))
} }
@ -338,6 +347,7 @@ impl WinitEventLoop {
let resize_notification = &self.resize_notification; let resize_notification = &self.resize_notification;
let logger = &self.logger; let logger = &self.logger;
let window_size = &self.size; let window_size = &self.size;
let is_x11 = self.is_x11;
if !self.initialized { if !self.initialized {
callback(Input(InputEvent::DeviceAdded { callback(Input(InputEvent::DeviceAdded {
@ -428,7 +438,12 @@ impl WinitEventLoop {
} }
WindowEvent::MouseInput { state, button, .. } => { WindowEvent::MouseInput { state, button, .. } => {
callback(Input(InputEvent::PointerButton { callback(Input(InputEvent::PointerButton {
event: WinitMouseInputEvent { time, button, state }, event: WinitMouseInputEvent {
time,
button,
state,
is_x11,
},
})); }));
} }

View File

@ -4,8 +4,7 @@ use super::X11Error;
use crate::{ use crate::{
backend::input::{ backend::input::{
self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, InputEvent, KeyState, self, Axis, AxisSource, ButtonState, Device, DeviceCapability, InputBackend, InputEvent, KeyState,
KeyboardKeyEvent, MouseButton, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, UnusedEvent,
UnusedEvent,
}, },
utils::{Logical, Size}, utils::{Logical, Size},
}; };
@ -120,7 +119,7 @@ impl PointerAxisEvent<X11Input> for X11MouseWheelEvent {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct X11MouseInputEvent { pub struct X11MouseInputEvent {
pub(crate) time: u32, pub(crate) time: u32,
pub(crate) button: MouseButton, pub(crate) raw: u32,
pub(crate) state: ButtonState, pub(crate) state: ButtonState,
} }
@ -135,8 +134,8 @@ impl input::Event<X11Input> for X11MouseInputEvent {
} }
impl PointerButtonEvent<X11Input> for X11MouseInputEvent { impl PointerButtonEvent<X11Input> for X11MouseInputEvent {
fn button(&self) -> MouseButton { fn button_code(&self) -> u32 {
self.button input::xorg_mouse_to_libinput(self.raw)
} }
fn state(&self) -> ButtonState { fn state(&self) -> ButtonState {

View File

@ -59,7 +59,7 @@ use crate::{
backend::{ backend::{
allocator::dmabuf::{AsDmabuf, Dmabuf}, allocator::dmabuf::{AsDmabuf, Dmabuf},
drm::{DrmNode, NodeType}, drm::{DrmNode, NodeType},
input::{Axis, ButtonState, InputEvent, KeyState, MouseButton}, input::{Axis, ButtonState, InputEvent, KeyState},
}, },
utils::{x11rb::X11Source, Logical, Size}, utils::{x11rb::X11Source, Logical, Size},
}; };
@ -625,32 +625,9 @@ impl EventSource for X11Backend {
// 6 => Axis::Horizontal -1.0 // 6 => Axis::Horizontal -1.0
// 7 => Axis::Horizontal +1.0 // 7 => Axis::Horizontal +1.0
// Others => ?? // Others => ??
match button_press.detail {
1..=3 => {
// Clicking a button.
callback(
Input(InputEvent::PointerButton {
event: X11MouseInputEvent {
time: button_press.time,
button: match button_press.detail {
1 => MouseButton::Left,
// Confusion: XCB docs for ButtonIndex and what plasma does don't match?
2 => MouseButton::Middle,
3 => MouseButton::Right,
_ => unreachable!(),
},
state: ButtonState::Pressed,
},
}),
&mut event_window,
)
}
4..=7 => {
// Scrolling // Scrolling
if button_press.detail >= 4 && button_press.detail <= 7 {
callback( callback(
Input(InputEvent::PointerAxis { Input(InputEvent::PointerAxis {
event: X11MouseWheelEvent { event: X11MouseWheelEvent {
@ -677,63 +654,40 @@ impl EventSource for X11Backend {
}), }),
&mut event_window, &mut event_window,
) )
} } else {
callback(
// Unknown mouse button
_ => callback(
Input(InputEvent::PointerButton { Input(InputEvent::PointerButton {
event: X11MouseInputEvent { event: X11MouseInputEvent {
time: button_press.time, time: button_press.time,
button: MouseButton::Other(button_press.detail), raw: button_press.detail as u32,
state: ButtonState::Pressed, state: ButtonState::Pressed,
}, },
}), }),
&mut event_window, &mut event_window,
), )
} }
} }
} }
x11::Event::ButtonRelease(button_release) => { x11::Event::ButtonRelease(button_release) => {
if button_release.event == window.id { if button_release.event == window.id {
match button_release.detail { // Ignore release tick because this event is always sent immediately after the press
1..=3 => { // tick for scrolling and the backend will dispatch release event automatically during
// Releasing a button. // the press event.
if button_release.detail >= 4 && button_release.detail <= 7 {
return;
}
callback( callback(
Input(InputEvent::PointerButton { Input(InputEvent::PointerButton {
event: X11MouseInputEvent { event: X11MouseInputEvent {
time: button_release.time, time: button_release.time,
button: match button_release.detail { raw: button_release.detail as u32,
1 => MouseButton::Left,
2 => MouseButton::Middle,
3 => MouseButton::Right,
_ => unreachable!(),
},
state: ButtonState::Released, state: ButtonState::Released,
}, },
}), }),
&mut event_window, &mut event_window,
) );
}
// We may ignore the release tick for scrolling, as the X server will
// always emit this immediately after press.
4..=7 => (),
_ => callback(
Input(InputEvent::PointerButton {
event: X11MouseInputEvent {
time: button_release.time,
button: MouseButton::Other(button_release.detail),
state: ButtonState::Released,
},
}),
&mut event_window,
),
}
} }
} }