backend.input: rework libinput as a calloop source

This commit is contained in:
Victor Berger 2020-05-04 13:03:36 +02:00 committed by Victor Berger
parent 5552c81a32
commit 8f543eb597
7 changed files with 471 additions and 541 deletions

View File

@ -14,7 +14,7 @@ use slog::Logger;
use smithay::backend::session::{auto::AutoSession, Session};
use smithay::{
backend::input::{
self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent,
self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent,
PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent,
},
reexports::wayland_server::protocol::wl_pointer,
@ -77,20 +77,21 @@ impl AnvilInputHandler {
}
}
impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
fn on_seat_created(&mut self, _: &input::Seat) {
/* currently we just create a single static one */
impl AnvilInputHandler {
pub fn process_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event {
InputEvent::Keyboard { event, .. } => self.on_keyboard_key::<B>(event),
InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
InputEvent::PointerMotionAbsolute { event, .. } => self.on_pointer_move_absolute::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
_ => {
// other events are not handled in anvil (yet)
}
}
}
fn on_seat_destroyed(&mut self, _: &input::Seat) {
/* currently we just create a single static one */
}
fn on_seat_changed(&mut self, _: &input::Seat) {
/* currently we just create a single static one */
}
fn on_keyboard_key(&mut self, _: &input::Seat, evt: B::KeyboardKeyEvent) {
fn on_keyboard_key<B: InputBackend>(&mut self, evt: B::KeyboardKeyEvent) {
let keycode = evt.key_code();
let state = evt.state();
debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state));
@ -146,7 +147,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
}
}
fn on_pointer_move(&mut self, _: &input::Seat, evt: B::PointerMotionEvent) {
fn on_pointer_move<B: InputBackend>(&mut self, evt: B::PointerMotionEvent) {
let (x, y) = (evt.delta_x(), evt.delta_y());
let serial = SCOUNTER.next_serial();
let mut location = self.pointer_location.borrow_mut();
@ -163,7 +164,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
self.pointer.motion(*location, under, serial, evt.time());
}
fn on_pointer_move_absolute(&mut self, _: &input::Seat, evt: B::PointerMotionAbsoluteEvent) {
fn on_pointer_move_absolute<B: InputBackend>(&mut self, evt: B::PointerMotionAbsoluteEvent) {
// different cases depending on the context:
let (x, y) = {
#[cfg(feature = "udev")]
@ -188,7 +189,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
self.pointer.motion((x, y), under, serial, evt.time());
}
fn on_pointer_button(&mut self, _: &input::Seat, evt: B::PointerButtonEvent) {
fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) {
let serial = SCOUNTER.next_serial();
let button = match evt.button() {
input::MouseButton::Left => 0x110,
@ -214,7 +215,7 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
self.pointer.button(button, state, serial, evt.time());
}
fn on_pointer_axis(&mut self, _: &input::Seat, evt: B::PointerAxisEvent) {
fn on_pointer_axis<B: InputBackend>(&mut self, evt: B::PointerAxisEvent) {
let source = match evt.source() {
input::AxisSource::Continuous => wl_pointer::AxisSource::Continuous,
input::AxisSource::Finger => wl_pointer::AxisSource::Finger,
@ -250,25 +251,6 @@ impl<B: InputBackend> InputHandler<B> for AnvilInputHandler {
self.pointer.axis(frame);
}
}
fn on_touch_down(&mut self, _: &input::Seat, _: B::TouchDownEvent) {
/* not done in this example */
}
fn on_touch_motion(&mut self, _: &input::Seat, _: B::TouchMotionEvent) {
/* not done in this example */
}
fn on_touch_up(&mut self, _: &input::Seat, _: B::TouchUpEvent) {
/* not done in this example */
}
fn on_touch_cancel(&mut self, _: &input::Seat, _: B::TouchCancelEvent) {
/* not done in this example */
}
fn on_touch_frame(&mut self, _: &input::Seat, _: B::TouchFrameEvent) {
/* not done in this example */
}
fn on_input_config_changed(&mut self, _: &mut B::InputConfig) {
/* not done in this example */
}
}
/// Possible results of a keyboard action

View File

@ -26,8 +26,7 @@ use smithay::{
DevPath, Device, DeviceHandler, Surface,
},
graphics::CursorBackend,
input::InputBackend,
libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface},
libinput::{LibinputInputBackend, LibinputSessionInterface},
session::{
auto::{auto_session_bind, AutoSession},
notify_multiplexer, AsSessionObserver, Session, SessionNotifier,
@ -202,8 +201,8 @@ pub fn run_udev(
Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>(session.clone().into());
let libinput_session_id = notifier.register(libinput_context.observer());
libinput_context.udev_assign_seat(&seat).unwrap();
let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
libinput_backend.set_handler(AnvilInputHandler::new_with_session(
let libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
let mut input_handler = AnvilInputHandler::new_with_session(
log.clone(),
InputInitData {
pointer,
@ -214,13 +213,16 @@ pub fn run_udev(
pointer_location,
},
session,
));
);
/*
* Bind all our objects that get driven by the event loop
*/
let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle())
.map_err(|e| -> IoError { e.into() })
let libinput_event_source = event_loop
.handle()
.insert_source(libinput_backend, move |event, _, _anvil_state| {
input_handler.process_event(event)
})
.unwrap();
let session_event_source = auto_session_bind(notifier, event_loop.handle())
.map_err(|(e, _)| e)

View File

@ -31,7 +31,9 @@ pub fn run_winit(
event_loop: &mut EventLoop<AnvilState>,
log: Logger,
) -> Result<(), ()> {
let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?;
let (renderer, mut input) = winit::init(log.clone()).map_err(|err| {
slog::crit!(log, "Failed to initialize Winit backend: {}", err);
})?;
#[cfg(feature = "egl")]
let egl_buffer_reader = Rc::new(RefCell::new(
@ -111,7 +113,7 @@ pub fn run_winit(
let pointer_location = Rc::new(RefCell::new((0.0, 0.0)));
input.set_handler(AnvilInputHandler::new(
let mut input_handler = AnvilInputHandler::new(
log.clone(),
InputInitData {
pointer,
@ -121,12 +123,14 @@ pub fn run_winit(
running: state.running.clone(),
pointer_location: pointer_location.clone(),
},
));
);
info!(log, "Initialization completed, starting the main loop.");
while state.running.load(Ordering::SeqCst) {
input.dispatch_new_events().unwrap();
input
.dispatch_new_events(|event, _| input_handler.process_event(event))
.unwrap();
// drawing logic
{

View File

@ -491,9 +491,6 @@ impl TouchFrameEvent for UnusedEvent {}
/// need to implement this and provide the same base guarantees about the precision of
/// given events.
pub trait InputBackend: Sized {
/// Type of input device associated with the backend
type InputConfig: ?Sized;
/// Type representing errors that may be returned when processing events
type EventError: Error;
@ -518,168 +515,108 @@ pub trait InputBackend: Sized {
/// Type representing touch frame events
type TouchFrameEvent: TouchFrameEvent;
/// Sets a new handler for this [`InputBackend`]
fn set_handler<H: InputHandler<Self> + 'static>(&mut self, handler: H);
/// Get a reference to the currently set handler, if any
fn get_handler(&mut self) -> Option<&mut dyn InputHandler<Self>>;
/// Clears the currently handler, if one is set
fn clear_handler(&mut self);
/// Special events that are custom to this backend
type SpecialEvent;
/// Get current `InputConfig`
/// Backend-specific type allowing you to configure it
type InputConfig: ?Sized;
/// Get the list of currently known Seats
fn seats(&self) -> Vec<Seat>;
/// Access the input configuration interface
fn input_config(&mut self) -> &mut Self::InputConfig;
/// Processes new events of the underlying backend and drives the [`InputHandler`].
fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>;
///
/// The callback can only assume its second argument to be usable if the event is
/// `InputEvent::ConfigChanged`.
fn dispatch_new_events<F>(&mut self, callback: F) -> Result<(), Self::EventError>
where
F: FnMut(InputEvent<Self>, &mut Self::InputConfig);
}
/// Implement to receive input events from any [`InputBackend`].
pub trait InputHandler<B: InputBackend> {
/// Called when a new [`Seat`] has been created
fn on_seat_created(&mut self, seat: &Seat);
/// Called when an existing [`Seat`] has been destroyed.
fn on_seat_destroyed(&mut self, seat: &Seat);
/// Called when a [`Seat`]'s properties have changed.
/// Different events that can be generated by an input backend
pub enum InputEvent<B: InputBackend> {
/// A new seat has been created
NewSeat(Seat),
/// A seat has changed
SeatChanged(Seat),
/// A seat has been removed
SeatRemoved(Seat),
/// A keyboard event occured
Keyboard {
/// Seat that generated the event
seat: Seat,
/// The keyboard event
event: B::KeyboardKeyEvent,
},
/// A relative pointer motion occured
PointerMotion {
/// Seat that generated the event
seat: Seat,
/// The pointer motion event
event: B::PointerMotionEvent,
},
/// An absolute pointer motion occures
PointerMotionAbsolute {
/// Seat that generated the event
seat: Seat,
/// The absolute pointer motion event
event: B::PointerMotionAbsoluteEvent,
},
/// A pointer button was pressed or released
PointerButton {
/// Seat that generated the event
seat: Seat,
/// The pointer button event
event: B::PointerButtonEvent,
},
/// A pointer axis was actionned
PointerAxis {
/// Seat that generated the event
seat: Seat,
/// The pointer axis event
event: B::PointerAxisEvent,
},
/// A new touchpoint appeared
TouchDown {
/// Seat that generated the event
seat: Seat,
/// The touch down event
event: B::TouchDownEvent,
},
/// A touchpoint moved
TouchMotion {
/// Seat that generated the event
seat: Seat,
/// The touch motion event
event: B::TouchMotionEvent,
},
/// A touchpoint was removed
TouchUp {
/// Seat that generated the event
seat: Seat,
/// The touch up event
event: B::TouchUpEvent,
},
/// A touch sequence was cancelled
TouchCancel {
/// Seat that generated the event
seat: Seat,
/// The touch cancel event
event: B::TouchCancelEvent,
},
/// A touch frame was emmited
///
/// ## Note:
///
/// It is not guaranteed that any change has actually happened.
fn on_seat_changed(&mut self, seat: &Seat);
/// Called when a new keyboard event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The keyboard event
///
fn on_keyboard_key(&mut self, seat: &Seat, event: B::KeyboardKeyEvent);
/// Called when a new pointer movement event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The pointer movement event
fn on_pointer_move(&mut self, seat: &Seat, event: B::PointerMotionEvent);
/// Called when a new pointer absolute movement event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The pointer absolute movement event
fn on_pointer_move_absolute(&mut self, seat: &Seat, event: B::PointerMotionAbsoluteEvent);
/// Called when a new pointer button event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The pointer button event
fn on_pointer_button(&mut self, seat: &Seat, event: B::PointerButtonEvent);
/// Called when a new pointer scroll event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - A upward counting variable useful for event ordering. Makes no guarantees about actual time passed between events.
fn on_pointer_axis(&mut self, seat: &Seat, event: B::PointerAxisEvent);
/// Called when a new touch down event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The touch down event
fn on_touch_down(&mut self, seat: &Seat, event: B::TouchDownEvent);
/// Called when a new touch motion event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The touch motion event.
fn on_touch_motion(&mut self, seat: &Seat, event: B::TouchMotionEvent);
/// Called when a new touch up event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The touch up event.
fn on_touch_up(&mut self, seat: &Seat, event: B::TouchUpEvent);
/// Called when a new touch cancel event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The touch cancel event.
fn on_touch_cancel(&mut self, seat: &Seat, event: B::TouchCancelEvent);
/// Called when a new touch frame event was received.
///
/// # Arguments
///
/// - `seat` - The [`Seat`] the event belongs to
/// - `event` - The touch frame event.
fn on_touch_frame(&mut self, seat: &Seat, event: B::TouchFrameEvent);
/// Called when the `InputConfig` was changed through an external event.
///
/// What kind of events can trigger this call is completely backend dependent.
/// E.g. an input devices was attached/detached or changed it's own configuration.
fn on_input_config_changed(&mut self, config: &mut B::InputConfig);
}
impl<B: InputBackend> InputHandler<B> for Box<dyn InputHandler<B>> {
fn on_seat_created(&mut self, seat: &Seat) {
(**self).on_seat_created(seat)
}
fn on_seat_destroyed(&mut self, seat: &Seat) {
(**self).on_seat_destroyed(seat)
}
fn on_seat_changed(&mut self, seat: &Seat) {
(**self).on_seat_changed(seat)
}
fn on_keyboard_key(&mut self, seat: &Seat, event: B::KeyboardKeyEvent) {
(**self).on_keyboard_key(seat, event)
}
fn on_pointer_move(&mut self, seat: &Seat, event: B::PointerMotionEvent) {
(**self).on_pointer_move(seat, event)
}
fn on_pointer_move_absolute(&mut self, seat: &Seat, event: B::PointerMotionAbsoluteEvent) {
(**self).on_pointer_move_absolute(seat, event)
}
fn on_pointer_button(&mut self, seat: &Seat, event: B::PointerButtonEvent) {
(**self).on_pointer_button(seat, event)
}
fn on_pointer_axis(&mut self, seat: &Seat, event: B::PointerAxisEvent) {
(**self).on_pointer_axis(seat, event)
}
fn on_touch_down(&mut self, seat: &Seat, event: B::TouchDownEvent) {
(**self).on_touch_down(seat, event)
}
fn on_touch_motion(&mut self, seat: &Seat, event: B::TouchMotionEvent) {
(**self).on_touch_motion(seat, event)
}
fn on_touch_up(&mut self, seat: &Seat, event: B::TouchUpEvent) {
(**self).on_touch_up(seat, event)
}
fn on_touch_cancel(&mut self, seat: &Seat, event: B::TouchCancelEvent) {
(**self).on_touch_cancel(seat, event)
}
fn on_touch_frame(&mut self, seat: &Seat, event: B::TouchFrameEvent) {
(**self).on_touch_frame(seat, event)
}
fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
(**self).on_input_config_changed(config)
}
/// A set of two events received on the same seat between two frames should
/// be interpreted as an atomic event.
TouchFrame {
/// Seat that generated the event
seat: Seat,
/// The touch frame event
event: B::TouchFrameEvent,
},
/// Special event specific of this backend
Special(B::SpecialEvent),
}

View File

@ -1,25 +1,25 @@
use crate::backend::input::{self as backend};
use crate::backend::input::{self as backend, InputEvent};
use input as libinput;
use input::event::{
device::DeviceEvent, keyboard::KeyboardEvent, pointer::PointerEvent, touch::TouchEvent, EventTrait,
};
use slog::Logger;
use super::LibinputInputBackend;
use super::{LibinputConfig, LibinputEvent, LibinputInputBackend};
use std::{
collections::hash_map::{DefaultHasher, Entry, HashMap},
hash::{Hash, Hasher},
};
#[inline(always)]
pub fn on_device_event<H>(
handler: &mut Option<H>,
pub fn on_device_event<F>(
callback: &mut F,
seats: &mut HashMap<libinput::Seat, backend::Seat>,
devices: &mut Vec<libinput::Device>,
config: &mut LibinputConfig,
event: DeviceEvent,
logger: &Logger,
) where
H: backend::InputHandler<LibinputInputBackend>,
F: FnMut(InputEvent<LibinputInputBackend>, &mut LibinputConfig),
{
match event {
DeviceEvent::Added(device_added_event) => {
@ -38,7 +38,7 @@ pub fn on_device_event<H>(
added.sysname(),
device_seat.logical_name()
);
devices.push(added);
config.devices.push(added.clone());
match seats.entry(device_seat.clone()) {
Entry::Occupied(mut seat_entry) => {
@ -49,10 +49,7 @@ pub fn on_device_event<H>(
caps.keyboard = new_caps.keyboard || caps.keyboard;
caps.touch = new_caps.touch || caps.touch;
}
if let Some(ref mut handler) = handler {
trace!(logger, "Calling on_seat_changed with {:?}", old_seat);
handler.on_seat_changed(old_seat);
}
callback(InputEvent::SeatChanged(old_seat.clone()), config);
}
Entry::Vacant(seat_entry) => {
let mut hasher = DefaultHasher::default();
@ -62,18 +59,17 @@ pub fn on_device_event<H>(
format!("{}:{}", device_seat.physical_name(), device_seat.logical_name()),
new_caps,
));
if let Some(ref mut handler) = handler {
trace!(logger, "Calling on_seat_created with {:?}", seat);
handler.on_seat_created(seat);
}
callback(InputEvent::NewSeat(seat.clone()), config);
}
}
callback(InputEvent::Special(LibinputEvent::NewDevice(added)), config);
}
DeviceEvent::Removed(device_removed_event) => {
let removed = device_removed_event.device();
// remove device
devices.retain(|dev| *dev != removed);
config.devices.retain(|dev| *dev != removed);
let device_seat = removed.seat();
info!(
@ -86,15 +82,18 @@ pub fn on_device_event<H>(
// update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`.
if let Some(seat) = seats.get_mut(&device_seat) {
let caps = seat.capabilities_mut();
caps.pointer = devices
caps.pointer = config
.devices
.iter()
.filter(|x| x.seat() == device_seat)
.any(|x| x.has_capability(libinput::DeviceCapability::Pointer));
caps.keyboard = devices
caps.keyboard = config
.devices
.iter()
.filter(|x| x.seat() == device_seat)
.any(|x| x.has_capability(libinput::DeviceCapability::Keyboard));
caps.touch = devices
caps.touch = config
.devices
.iter()
.filter(|x| x.seat() == device_seat)
.any(|x| x.has_capability(libinput::DeviceCapability::Touch));
@ -104,7 +103,7 @@ pub fn on_device_event<H>(
}
// check if the seat has any other devices
if !devices.iter().any(|x| x.seat() == device_seat) {
if !config.devices.iter().any(|x| x.seat() == device_seat) {
// it has not, lets destroy it
if let Some(seat) = seats.remove(&device_seat) {
info!(
@ -112,133 +111,167 @@ pub fn on_device_event<H>(
"Removing seat {} which no longer has any device",
device_seat.logical_name()
);
if let Some(ref mut handler) = handler {
trace!(logger, "Calling on_seat_destroyed with {:?}", seat);
handler.on_seat_destroyed(&seat);
}
callback(InputEvent::SeatRemoved(seat), config);
} else {
warn!(logger, "Seat destroyed that was never created");
return;
}
// it has, notify about updates
} else if let Some(ref mut handler) = handler {
if let Some(seat) = seats.get(&device_seat) {
trace!(logger, "Calling on_seat_changed with {:?}", seat);
handler.on_seat_changed(&seat);
} else {
warn!(logger, "Seat changed that was never created");
return;
}
} else if let Some(seat) = seats.get(&device_seat) {
callback(InputEvent::SeatChanged(seat.clone()), config);
} else {
warn!(logger, "Seat changed that was never created");
return;
}
callback(InputEvent::Special(LibinputEvent::RemovedDevice(removed)), config);
}
}
if let Some(ref mut handler) = handler {
handler.on_input_config_changed(devices);
}
}
#[inline(always)]
pub fn on_touch_event<H>(
handler: &mut Option<H>,
pub fn on_touch_event<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: TouchEvent,
logger: &Logger,
) where
H: backend::InputHandler<LibinputInputBackend>,
F: FnMut(InputEvent<LibinputInputBackend>, &mut LibinputConfig),
{
if let Some(ref mut handler) = handler {
let device_seat = event.device().seat();
if let Some(ref seat) = seats.get(&device_seat) {
match event {
TouchEvent::Down(down_event) => {
trace!(logger, "Calling on_touch_down with {:?}", down_event);
handler.on_touch_down(seat, down_event)
}
TouchEvent::Motion(motion_event) => {
trace!(logger, "Calling on_touch_motion with {:?}", motion_event);
handler.on_touch_motion(seat, motion_event)
}
TouchEvent::Up(up_event) => {
trace!(logger, "Calling on_touch_up with {:?}", up_event);
handler.on_touch_up(seat, up_event)
}
TouchEvent::Cancel(cancel_event) => {
trace!(logger, "Calling on_touch_cancel with {:?}", cancel_event);
handler.on_touch_cancel(seat, cancel_event)
}
TouchEvent::Frame(frame_event) => {
trace!(logger, "Calling on_touch_frame with {:?}", frame_event);
handler.on_touch_frame(seat, frame_event)
}
let device_seat = event.device().seat();
if let Some(seat) = seats.get(&device_seat).cloned() {
match event {
TouchEvent::Down(down_event) => {
callback(
InputEvent::TouchDown {
seat,
event: down_event,
},
config,
);
}
TouchEvent::Motion(motion_event) => {
callback(
InputEvent::TouchMotion {
seat,
event: motion_event,
},
config,
);
}
TouchEvent::Up(up_event) => {
callback(
InputEvent::TouchUp {
seat,
event: up_event,
},
config,
);
}
TouchEvent::Cancel(cancel_event) => {
callback(
InputEvent::TouchCancel {
seat,
event: cancel_event,
},
config,
);
}
TouchEvent::Frame(frame_event) => {
callback(
InputEvent::TouchFrame {
seat,
event: frame_event,
},
config,
);
}
} else {
warn!(logger, "Received touch event of non existing Seat");
return;
}
} else {
warn!(logger, "Received touch event of non existing Seat");
}
}
#[inline(always)]
pub fn on_keyboard_event<H>(
handler: &mut Option<H>,
pub fn on_keyboard_event<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: KeyboardEvent,
logger: &Logger,
) where
H: backend::InputHandler<LibinputInputBackend>,
F: FnMut(InputEvent<LibinputInputBackend>, &mut LibinputConfig),
{
match event {
KeyboardEvent::Key(key_event) => {
if let Some(ref mut handler) = handler {
let device_seat = key_event.device().seat();
if let Some(ref seat) = seats.get(&device_seat) {
trace!(logger, "Calling on_keyboard_key with {:?}", key_event);
handler.on_keyboard_key(seat, key_event);
} else {
warn!(logger, "Received key event of non existing Seat");
return;
}
let device_seat = key_event.device().seat();
if let Some(seat) = seats.get(&device_seat).cloned() {
callback(
InputEvent::Keyboard {
seat,
event: key_event,
},
config,
);
} else {
warn!(logger, "Received key event of non existing Seat");
}
}
}
}
#[inline(always)]
pub fn on_pointer_event<H>(
handler: &mut Option<H>,
pub fn on_pointer_event<F>(
callback: &mut F,
seats: &HashMap<libinput::Seat, backend::Seat>,
config: &mut LibinputConfig,
event: PointerEvent,
logger: &Logger,
) where
H: backend::InputHandler<LibinputInputBackend>,
F: FnMut(InputEvent<LibinputInputBackend>, &mut LibinputConfig),
{
if let Some(ref mut handler) = handler {
let device_seat = event.device().seat();
if let Some(ref seat) = seats.get(&device_seat) {
match event {
PointerEvent::Motion(motion_event) => {
trace!(logger, "Calling on_pointer_move with {:?}", motion_event);
handler.on_pointer_move(seat, motion_event);
}
PointerEvent::MotionAbsolute(motion_abs_event) => {
trace!(
logger,
"Calling on_pointer_move_absolute with {:?}",
motion_abs_event
);
handler.on_pointer_move_absolute(seat, motion_abs_event);
}
PointerEvent::Axis(axis_event) => {
trace!(logger, "Calling on_pointer_axis with {:?}", axis_event);
handler.on_pointer_axis(seat, axis_event);
}
PointerEvent::Button(button_event) => {
trace!(logger, "Calling on_pointer_button with {:?}", button_event);
handler.on_pointer_button(seat, button_event);
}
let device_seat = event.device().seat();
if let Some(seat) = seats.get(&device_seat).cloned() {
match event {
PointerEvent::Motion(motion_event) => {
callback(
InputEvent::PointerMotion {
seat,
event: motion_event,
},
config,
);
}
PointerEvent::MotionAbsolute(motion_abs_event) => {
callback(
InputEvent::PointerMotionAbsolute {
seat,
event: motion_abs_event,
},
config,
);
}
PointerEvent::Axis(axis_event) => {
callback(
InputEvent::PointerAxis {
seat,
event: axis_event,
},
config,
);
}
PointerEvent::Button(button_event) => {
callback(
InputEvent::PointerButton {
seat,
event: button_event,
},
config,
);
}
} else {
warn!(logger, "Received pointer event of non existing Seat");
}
} else {
warn!(logger, "Received pointer event of non existing Seat");
}
}

View File

@ -3,7 +3,7 @@
mod helpers;
use helpers::{on_device_event, on_keyboard_event, on_pointer_event, on_touch_event};
use crate::backend::input::{self as backend, Axis, InputBackend};
use crate::backend::input::{self as backend, Axis, InputBackend, InputEvent};
#[cfg(feature = "backend_session")]
use crate::backend::session::{AsErrno, Session, SessionObserver};
use input as libinput;
@ -17,7 +17,7 @@ use std::{
os::unix::io::{AsRawFd, RawFd},
};
use calloop::{generic::Generic, InsertError, LoopHandle, Source};
use calloop::{EventSource, Interest, Mode, Poll, Readiness, Token};
// No idea if this is the same across unix platforms
// Lets make this linux exclusive for now, once someone tries to build it for
@ -31,9 +31,8 @@ const INPUT_MAJOR: u32 = 13;
/// context.
pub struct LibinputInputBackend {
context: libinput::Libinput,
devices: Vec<libinput::Device>,
config: LibinputConfig,
seats: HashMap<libinput::Seat, backend::Seat>,
handler: Option<Box<dyn backend::InputHandler<LibinputInputBackend> + 'static>>,
logger: ::slog::Logger,
}
@ -48,9 +47,8 @@ impl LibinputInputBackend {
info!(log, "Initializing a libinput backend");
LibinputInputBackend {
context,
devices: Vec::new(),
config: LibinputConfig { devices: Vec::new() },
seats: HashMap::new(),
handler: None,
logger: log,
}
}
@ -246,8 +244,30 @@ impl backend::Event for event::touch::TouchFrameEvent {
impl backend::TouchFrameEvent for event::touch::TouchFrameEvent {}
/// Special events generated by Libinput
pub enum LibinputEvent {
/// A new device was plugged in
NewDevice(libinput::Device),
/// A device was plugged out
RemovedDevice(libinput::Device),
}
/// Configuration handle for libinput
///
/// This type allows you to access the list of know devices to configure them
/// if relevant
pub struct LibinputConfig {
devices: Vec<libinput::Device>,
}
impl LibinputConfig {
/// Access the list of current devices
pub fn devices(&mut self) -> &mut [libinput::Device] {
&mut self.devices
}
}
impl InputBackend for LibinputInputBackend {
type InputConfig = [libinput::Device];
type EventError = IoError;
type KeyboardKeyEvent = event::keyboard::KeyboardKeyEvent;
@ -261,60 +281,60 @@ impl InputBackend for LibinputInputBackend {
type TouchCancelEvent = event::touch::TouchCancelEvent;
type TouchFrameEvent = event::touch::TouchFrameEvent;
fn set_handler<H: backend::InputHandler<Self> + 'static>(&mut self, mut handler: H) {
if self.handler.is_some() {
self.clear_handler();
}
info!(self.logger, "New input handler set");
for seat in self.seats.values() {
trace!(self.logger, "Calling on_seat_created with {:?}", seat);
handler.on_seat_created(seat);
}
self.handler = Some(Box::new(handler));
}
type SpecialEvent = LibinputEvent;
type InputConfig = LibinputConfig;
fn get_handler(&mut self) -> Option<&mut dyn backend::InputHandler<Self>> {
self.handler
.as_mut()
.map(|handler| handler as &mut dyn backend::InputHandler<Self>)
}
fn clear_handler(&mut self) {
if let Some(mut handler) = self.handler.take() {
for seat in self.seats.values() {
trace!(self.logger, "Calling on_seat_destroyed with {:?}", seat);
handler.on_seat_destroyed(seat);
}
info!(self.logger, "Removing input handler");
}
fn seats(&self) -> Vec<backend::Seat> {
self.seats.values().cloned().collect()
}
fn input_config(&mut self) -> &mut Self::InputConfig {
&mut self.devices
&mut self.config
}
fn dispatch_new_events(&mut self) -> Result<(), IoError> {
fn dispatch_new_events<F>(&mut self, mut callback: F) -> Result<(), IoError>
where
F: FnMut(InputEvent<Self>, &mut LibinputConfig),
{
self.context.dispatch()?;
for event in &mut self.context {
match event {
libinput::Event::Device(device_event) => {
on_device_event(
&mut self.handler,
&mut callback,
&mut self.seats,
&mut self.devices,
&mut self.config,
device_event,
&self.logger,
);
}
libinput::Event::Touch(touch_event) => {
on_touch_event(&mut self.handler, &self.seats, touch_event, &self.logger);
on_touch_event(
&mut callback,
&self.seats,
&mut self.config,
touch_event,
&self.logger,
);
}
libinput::Event::Keyboard(keyboard_event) => {
on_keyboard_event(&mut self.handler, &self.seats, keyboard_event, &self.logger);
on_keyboard_event(
&mut callback,
&self.seats,
&mut self.config,
keyboard_event,
&self.logger,
);
}
libinput::Event::Pointer(pointer_event) => {
on_pointer_event(&mut self.handler, &self.seats, pointer_event, &self.logger);
on_pointer_event(
&mut callback,
&self.seats,
&mut self.config,
pointer_event,
&self.logger,
);
}
_ => {} //FIXME: What to do with the rest.
}
@ -421,24 +441,27 @@ impl AsRawFd for LibinputInputBackend {
}
}
/// calloop source associated with the libinput backend
pub type LibinputSource = Generic<LibinputInputBackend>;
impl EventSource for LibinputInputBackend {
type Event = InputEvent<LibinputInputBackend>;
type Metadata = LibinputConfig;
type Ret = ();
/// Binds a [`LibinputInputBackend`] to a given [`LoopHandle`].
///
/// Automatically feeds the backend with incoming events without any manual calls to
/// [`dispatch_new_events`](InputBackend::dispatch_new_events). Should be used to achieve the smallest possible latency.
pub fn libinput_bind<Data: 'static>(
backend: LibinputInputBackend,
handle: LoopHandle<Data>,
) -> Result<Source<LibinputSource>, InsertError<LibinputSource>> {
let source = Generic::new(backend, calloop::Interest::Readable, calloop::Mode::Level);
fn process_events<F>(&mut self, _: Readiness, _: Token, callback: F) -> std::io::Result<()>
where
F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
{
self.dispatch_new_events(callback)
}
handle.insert_source(source, move |_, backend, _| {
if let Err(error) = backend.dispatch_new_events() {
warn!(backend.logger, "Libinput errored: {}", error);
return Err(std::io::Error::new(std::io::ErrorKind::Other, Box::new(error)));
}
Ok(())
})
fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(self.as_raw_fd(), Interest::Readable, Mode::Level, token)
}
fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.reregister(self.as_raw_fd(), Interest::Readable, Mode::Level, token)
}
fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
poll.unregister(self.as_raw_fd())
}
}

View File

@ -6,7 +6,7 @@ use crate::backend::{
egl::{context::GlAttributes, native, EGLContext, EGLSurface, Error as EGLError, SurfaceCreationError},
graphics::{gl::GLGraphicsBackend, CursorBackend, PixelFormat, SwapBuffersError},
input::{
Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState, KeyboardKeyEvent,
Axis, AxisSource, Event as BackendEvent, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent,
Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent, TouchMotionEvent, TouchSlot, TouchUpEvent,
UnusedEvent,
@ -94,13 +94,10 @@ pub struct WinitGraphicsBackend {
/// periodically to receive any events.
pub struct WinitInputBackend {
events_loop: EventLoop<()>,
events_handler: Option<Box<dyn WinitEventsHandler>>,
window: Rc<Window>,
time: Instant,
key_counter: u32,
seat: Seat,
input_config: (),
handler: Option<Box<dyn InputHandler<WinitInputBackend> + 'static>>,
logger: ::slog::Logger,
size: Rc<RefCell<WindowSize>>,
}
@ -211,7 +208,6 @@ where
},
WinitInputBackend {
events_loop,
events_handler: None,
window,
time: Instant::now(),
key_counter: 0,
@ -224,24 +220,25 @@ where
touch: true,
},
),
input_config: (),
handler: None,
logger: log.new(o!("smithay_winit_component" => "input")),
size,
},
))
}
/// Handler trait to receive window-related events to provide a better *nested* experience.
pub trait WinitEventsHandler {
/// The window was resized, can be used to adjust the associated [`Output`](::wayland::output::Output)s mode.
///
/// Here are provided the new size (in physical pixels) and the new scale factor provided by `winit`.
fn resized(&mut self, size: (f64, f64), scale: f64);
/// The window gained or lost focus
fn focus_changed(&mut self, focused: bool);
/// The window needs to be redrawn
fn refresh(&mut self);
/// Specific events generated by Winit
pub enum WinitEvent {
/// The window has been resized
Resized {
/// The new physical size (in pixels)
size: (f64, f64),
/// The new scale factor
scale_factor: f64,
},
/// The focus state of the window changed
Focus(bool),
/// A redraw was requested
Refresh,
}
impl WinitGraphicsBackend {
@ -611,29 +608,12 @@ impl TouchCancelEvent for WinitTouchCancelledEvent {
}
}
impl WinitInputBackend {
/// Set the events handler
pub fn set_events_handler<H: WinitEventsHandler + 'static>(&mut self, handler: H) {
self.events_handler = Some(Box::new(handler));
info!(self.logger, "New events handler set.");
}
/// Get a reference to the set events handler, if any
pub fn get_events_handler(&mut self) -> Option<&mut dyn WinitEventsHandler> {
self.events_handler
.as_mut()
.map(|handler| &mut **handler as &mut dyn WinitEventsHandler)
}
/// Clear out the currently set events handler
pub fn clear_events_handler(&mut self) {
self.events_handler = None;
info!(self.logger, "Events handler unset.");
}
}
/// Input config for Winit
///
/// This backend does not allow any input configuration, so this type does nothing.
pub struct WinitInputConfig;
impl InputBackend for WinitInputBackend {
type InputConfig = ();
type EventError = WinitInputError;
type KeyboardKeyEvent = WinitKeyboardInputEvent;
@ -647,32 +627,17 @@ impl InputBackend for WinitInputBackend {
type TouchCancelEvent = WinitTouchCancelledEvent;
type TouchFrameEvent = UnusedEvent;
fn set_handler<H: InputHandler<Self> + 'static>(&mut self, mut handler: H) {
if self.handler.is_some() {
self.clear_handler();
}
info!(self.logger, "New input handler set.");
trace!(self.logger, "Calling on_seat_created with {:?}", self.seat);
handler.on_seat_created(&self.seat);
self.handler = Some(Box::new(handler));
}
type SpecialEvent = WinitEvent;
type InputConfig = WinitInputConfig;
fn get_handler(&mut self) -> Option<&mut dyn InputHandler<Self>> {
self.handler
.as_mut()
.map(|handler| handler as &mut dyn InputHandler<Self>)
}
fn clear_handler(&mut self) {
if let Some(mut handler) = self.handler.take() {
trace!(self.logger, "Calling on_seat_destroyed with {:?}", self.seat);
handler.on_seat_destroyed(&self.seat);
}
info!(self.logger, "Removing input handler");
fn seats(&self) -> Vec<Seat> {
vec![self.seat.clone()]
}
fn input_config(&mut self) -> &mut Self::InputConfig {
&mut self.input_config
/// So much effort to return a useless singleton!
static mut CONFIG: WinitInputConfig = WinitInputConfig;
unsafe { &mut CONFIG }
}
/// Processes new events of the underlying event loop to drive the set [`InputHandler`].
@ -687,7 +652,10 @@ impl InputBackend for WinitInputBackend {
///
/// The linked [`WinitGraphicsBackend`] will error with a lost context and should
/// not be used anymore as well.
fn dispatch_new_events(&mut self) -> ::std::result::Result<(), WinitInputError> {
fn dispatch_new_events<F>(&mut self, mut callback: F) -> ::std::result::Result<(), WinitInputError>
where
F: FnMut(InputEvent<Self>, &mut WinitInputConfig),
{
let mut closed = false;
{
@ -701,10 +669,9 @@ impl InputBackend for WinitInputBackend {
let time = &self.time;
let seat = &self.seat;
let window = &self.window;
let mut handler = self.handler.as_mut();
let mut events_handler = self.events_handler.as_mut();
let logger = &self.logger;
let window_size = &self.size;
let mut callback = move |event| callback(event, &mut WinitInputConfig);
self.events_loop
.run_return(move |event, _target, control_flow| match event {
@ -712,16 +679,14 @@ impl InputBackend for WinitInputBackend {
*control_flow = ControlFlow::Exit;
}
Event::RedrawRequested(_id) => {
if let Some(events_handler) = events_handler.as_mut() {
events_handler.refresh();
}
callback(InputEvent::Special(WinitEvent::Refresh));
}
Event::WindowEvent { event, .. } => {
let duration = Instant::now().duration_since(*time);
let nanos = duration.subsec_nanos() as u64;
let time = ((1000 * duration.as_secs()) + (nanos / 1_000_000)) as u32;
match (event, handler.as_mut(), events_handler.as_mut()) {
(WindowEvent::Resized(psize), _, events_handler) => {
match event {
WindowEvent::Resized(psize) => {
trace!(logger, "Resizing window to {:?}", psize);
let scale_factor = window.window().scale_factor();
let mut wsize = window_size.borrow_mut();
@ -730,156 +695,140 @@ impl InputBackend for WinitInputBackend {
if let Window::Wayland { ref surface, .. } = **window {
surface.resize(psize.width as i32, psize.height as i32, 0, 0);
}
if let Some(events_handler) = events_handler {
events_handler.resized(psize.into(), scale_factor);
}
}
(WindowEvent::Focused(focus), _, Some(events_handler)) => {
events_handler.focus_changed(focus)
}
(
WindowEvent::ScaleFactorChanged {
callback(InputEvent::Special(WinitEvent::Resized {
size: psize.into(),
scale_factor,
new_inner_size: new_psize,
},
_,
events_handler,
) => {
}));
}
WindowEvent::Focused(focus) => {
callback(InputEvent::Special(WinitEvent::Focus(focus)));
}
WindowEvent::ScaleFactorChanged {
scale_factor,
new_inner_size: new_psize,
} => {
let mut wsize = window_size.borrow_mut();
wsize.scale_factor = scale_factor;
if let Window::Wayland { ref surface, .. } = **window {
surface.resize(new_psize.width as i32, new_psize.height as i32, 0, 0);
}
if let Some(events_handler) = events_handler {
let psize_f64: (f64, f64) =
(new_psize.width.into(), new_psize.height.into());
events_handler.resized(psize_f64, wsize.scale_factor);
}
let psize_f64: (f64, f64) = (new_psize.width.into(), new_psize.height.into());
callback(InputEvent::Special(WinitEvent::Resized {
size: psize_f64,
scale_factor: wsize.scale_factor,
}));
}
(
WindowEvent::KeyboardInput {
input: KeyboardInput { scancode, state, .. },
..
},
Some(handler),
_,
) => {
WindowEvent::KeyboardInput {
input: KeyboardInput { scancode, state, .. },
..
} => {
match state {
ElementState::Pressed => *key_counter += 1,
ElementState::Released => {
*key_counter = key_counter.checked_sub(1).unwrap_or(0)
}
};
trace!(logger, "Calling on_keyboard_key with {:?}", (scancode, state));
handler.on_keyboard_key(
seat,
WinitKeyboardInputEvent {
callback(InputEvent::Keyboard {
seat: seat.clone(),
event: WinitKeyboardInputEvent {
time,
key: scancode,
count: *key_counter,
state,
},
)
});
}
(WindowEvent::CursorMoved { position, .. }, Some(handler), _) => {
trace!(logger, "Calling on_pointer_move_absolute with {:?}", position);
WindowEvent::CursorMoved { position, .. } => {
let lpos = position.to_logical(window_size.borrow().scale_factor);
handler.on_pointer_move_absolute(
seat,
WinitMouseMovedEvent {
callback(InputEvent::PointerMotionAbsolute {
seat: seat.clone(),
event: WinitMouseMovedEvent {
size: window_size.clone(),
time,
logical_position: lpos,
},
)
});
}
(WindowEvent::MouseWheel { delta, .. }, Some(handler), _) => {
WindowEvent::MouseWheel { delta, .. } => {
let event = WinitMouseWheelEvent { time, delta };
trace!(logger, "Calling on_pointer_axis with {:?}", delta);
handler.on_pointer_axis(seat, event);
callback(InputEvent::PointerAxis {
seat: seat.clone(),
event,
});
}
(WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => {
trace!(logger, "Calling on_pointer_button with {:?}", (button, state));
handler.on_pointer_button(seat, WinitMouseInputEvent { time, button, state })
WindowEvent::MouseInput { state, button, .. } => {
callback(InputEvent::PointerButton {
seat: seat.clone(),
event: WinitMouseInputEvent { time, button, state },
});
}
(
WindowEvent::Touch(Touch {
phase: TouchPhase::Started,
location,
id,
..
}),
Some(handler),
_,
) => {
trace!(logger, "Calling on_touch_down at {:?}", location);
handler.on_touch_down(
seat,
WinitTouchStartedEvent {
WindowEvent::Touch(Touch {
phase: TouchPhase::Started,
location,
id,
..
}) => {
callback(InputEvent::TouchDown {
seat: seat.clone(),
event: WinitTouchStartedEvent {
size: window_size.clone(),
time,
location: location.into(),
id,
},
)
});
}
(
WindowEvent::Touch(Touch {
phase: TouchPhase::Moved,
location,
id,
..
}),
Some(handler),
_,
) => {
trace!(logger, "Calling on_touch_motion at {:?}", location);
handler.on_touch_motion(
seat,
WinitTouchMovedEvent {
WindowEvent::Touch(Touch {
phase: TouchPhase::Moved,
location,
id,
..
}) => {
callback(InputEvent::TouchMotion {
seat: seat.clone(),
event: WinitTouchMovedEvent {
size: window_size.clone(),
time,
location: location.into(),
id,
},
)
});
}
(
WindowEvent::Touch(Touch {
phase: TouchPhase::Ended,
location,
id,
..
}),
Some(handler),
_,
) => {
trace!(logger, "Calling on_touch_motion at {:?}", location);
handler.on_touch_motion(
seat,
WinitTouchMovedEvent {
WindowEvent::Touch(Touch {
phase: TouchPhase::Ended,
location,
id,
..
}) => {
callback(InputEvent::TouchMotion {
seat: seat.clone(),
event: WinitTouchMovedEvent {
size: window_size.clone(),
time,
location: location.into(),
id,
},
);
trace!(logger, "Calling on_touch_up");
handler.on_touch_up(seat, WinitTouchEndedEvent { time, id });
});
callback(InputEvent::TouchUp {
seat: seat.clone(),
event: WinitTouchEndedEvent { time, id },
})
}
(
WindowEvent::Touch(Touch {
phase: TouchPhase::Cancelled,
id,
..
}),
Some(handler),
_,
) => {
trace!(logger, "Calling on_touch_cancel");
handler.on_touch_cancel(seat, WinitTouchCancelledEvent { time, id })
WindowEvent::Touch(Touch {
phase: TouchPhase::Cancelled,
id,
..
}) => {
callback(InputEvent::TouchCancel {
seat: seat.clone(),
event: WinitTouchCancelledEvent { time, id },
});
}
(WindowEvent::CloseRequested, _, _) | (WindowEvent::Destroyed, _, _) => {
WindowEvent::CloseRequested | WindowEvent::Destroyed => {
warn!(logger, "Window closed");
*closed_ptr = true;
}