mirror of
https://github.com/nestriness/warp.git
synced 2025-12-14 02:45:37 +02:00
init
This commit is contained in:
264
wayland-display-core/src/comp/input.rs
Normal file
264
wayland-display-core/src/comp/input.rs
Normal file
@@ -0,0 +1,264 @@
|
||||
use super::{focus::FocusTarget, State};
|
||||
use smithay::{
|
||||
backend::{
|
||||
input::{
|
||||
Axis, AxisSource, Event, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent,
|
||||
PointerButtonEvent, PointerMotionEvent,
|
||||
},
|
||||
libinput::LibinputInputBackend,
|
||||
},
|
||||
input::{
|
||||
keyboard::{keysyms, FilterResult},
|
||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
|
||||
},
|
||||
reexports::{
|
||||
input::LibinputInterface,
|
||||
nix::{fcntl, fcntl::OFlag, sys::stat},
|
||||
wayland_server::protocol::wl_pointer,
|
||||
},
|
||||
utils::{Logical, Point, Serial, SERIAL_COUNTER},
|
||||
};
|
||||
use std::{
|
||||
os::{fd::FromRawFd, unix::io::OwnedFd},
|
||||
path::Path,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
pub struct NixInterface;
|
||||
|
||||
impl LibinputInterface for NixInterface {
|
||||
fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<OwnedFd, i32> {
|
||||
fcntl::open(path, OFlag::from_bits_truncate(flags), stat::Mode::empty())
|
||||
.map(|fd| unsafe { OwnedFd::from_raw_fd(fd) })
|
||||
.map_err(|err| err as i32)
|
||||
}
|
||||
fn close_restricted(&mut self, fd: OwnedFd) {
|
||||
let _ = fd;
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn process_input_event(&mut self, event: InputEvent<LibinputInputBackend>) {
|
||||
match event {
|
||||
InputEvent::Keyboard { event, .. } => {
|
||||
let keycode = event.key_code();
|
||||
let state = event.state();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let time = event.time_msec();
|
||||
let keyboard = self.seat.get_keyboard().unwrap();
|
||||
|
||||
keyboard.input::<(), _>(
|
||||
self,
|
||||
keycode,
|
||||
state,
|
||||
serial,
|
||||
time,
|
||||
|data, modifiers, handle| {
|
||||
if state == KeyState::Pressed {
|
||||
if modifiers.ctrl
|
||||
&& modifiers.shift
|
||||
&& !modifiers.alt
|
||||
&& !modifiers.logo
|
||||
{
|
||||
match handle.modified_sym() {
|
||||
keysyms::KEY_Tab => {
|
||||
if let Some(element) = data.space.elements().last().cloned()
|
||||
{
|
||||
data.surpressed_keys.insert(keysyms::KEY_Tab);
|
||||
let location =
|
||||
data.space.element_location(&element).unwrap();
|
||||
data.space.map_element(element.clone(), location, true);
|
||||
data.seat.get_keyboard().unwrap().set_focus(
|
||||
data,
|
||||
Some(FocusTarget::from(element)),
|
||||
serial,
|
||||
);
|
||||
return FilterResult::Intercept(());
|
||||
}
|
||||
}
|
||||
keysyms::KEY_Q => {
|
||||
if let Some(target) =
|
||||
data.seat.get_keyboard().unwrap().current_focus()
|
||||
{
|
||||
match target {
|
||||
FocusTarget::Wayland(window) => {
|
||||
window.toplevel().send_close();
|
||||
}
|
||||
_ => return FilterResult::Forward,
|
||||
};
|
||||
data.surpressed_keys.insert(keysyms::KEY_Q);
|
||||
return FilterResult::Intercept(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if data.surpressed_keys.remove(&handle.modified_sym()) {
|
||||
return FilterResult::Intercept(());
|
||||
}
|
||||
}
|
||||
|
||||
FilterResult::Forward
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerMotion { event, .. } => {
|
||||
self.last_pointer_movement = Instant::now();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let delta = event.delta();
|
||||
self.pointer_location += delta;
|
||||
self.pointer_location = self.clamp_coords(self.pointer_location);
|
||||
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
let under = self
|
||||
.space
|
||||
.element_under(self.pointer_location)
|
||||
.map(|(w, pos)| (w.clone().into(), pos));
|
||||
pointer.motion(
|
||||
self,
|
||||
under.clone(),
|
||||
&MotionEvent {
|
||||
location: self.pointer_location,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
pointer.relative_motion(
|
||||
self,
|
||||
under,
|
||||
&RelativeMotionEvent {
|
||||
delta,
|
||||
delta_unaccel: event.delta_unaccel(),
|
||||
utime: event.time(),
|
||||
},
|
||||
)
|
||||
}
|
||||
InputEvent::PointerMotionAbsolute { event } => {
|
||||
self.last_pointer_movement = Instant::now();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
if let Some(output) = self.output.as_ref() {
|
||||
let output_size = output
|
||||
.current_mode()
|
||||
.unwrap()
|
||||
.size
|
||||
.to_f64()
|
||||
.to_logical(output.current_scale().fractional_scale())
|
||||
.to_i32_round();
|
||||
self.pointer_location = (
|
||||
event.absolute_x_transformed(output_size.w),
|
||||
event.absolute_y_transformed(output_size.h),
|
||||
)
|
||||
.into();
|
||||
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
let under = self
|
||||
.space
|
||||
.element_under(self.pointer_location)
|
||||
.map(|(w, pos)| (w.clone().into(), pos));
|
||||
pointer.motion(
|
||||
self,
|
||||
under.clone(),
|
||||
&MotionEvent {
|
||||
location: self.pointer_location,
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
InputEvent::PointerButton { event, .. } => {
|
||||
self.last_pointer_movement = Instant::now();
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let button = event.button_code();
|
||||
|
||||
let state = wl_pointer::ButtonState::from(event.state());
|
||||
if wl_pointer::ButtonState::Pressed == state {
|
||||
self.update_keyboard_focus(serial);
|
||||
};
|
||||
self.seat.get_pointer().unwrap().button(
|
||||
self,
|
||||
&ButtonEvent {
|
||||
button,
|
||||
state: state.try_into().unwrap(),
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerAxis { event, .. } => {
|
||||
self.last_pointer_movement = Instant::now();
|
||||
let horizontal_amount = event
|
||||
.amount(Axis::Horizontal)
|
||||
.or_else(|| event.amount_discrete(Axis::Horizontal).map(|x| x * 2.0))
|
||||
.unwrap_or(0.0);
|
||||
let vertical_amount = event
|
||||
.amount(Axis::Vertical)
|
||||
.or_else(|| event.amount_discrete(Axis::Vertical).map(|y| y * 2.0))
|
||||
.unwrap_or(0.0);
|
||||
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
|
||||
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
|
||||
|
||||
{
|
||||
let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
|
||||
if horizontal_amount != 0.0 {
|
||||
frame = frame.value(Axis::Horizontal, horizontal_amount);
|
||||
if let Some(discrete) = horizontal_amount_discrete {
|
||||
frame = frame.discrete(Axis::Horizontal, discrete as i32);
|
||||
}
|
||||
} else if event.source() == AxisSource::Finger {
|
||||
frame = frame.stop(Axis::Horizontal);
|
||||
}
|
||||
if vertical_amount != 0.0 {
|
||||
frame = frame.value(Axis::Vertical, vertical_amount);
|
||||
if let Some(discrete) = vertical_amount_discrete {
|
||||
frame = frame.discrete(Axis::Vertical, discrete as i32);
|
||||
}
|
||||
} else if event.source() == AxisSource::Finger {
|
||||
frame = frame.stop(Axis::Vertical);
|
||||
}
|
||||
self.seat.get_pointer().unwrap().axis(self, frame);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn clamp_coords(&self, pos: Point<f64, Logical>) -> Point<f64, Logical> {
|
||||
if let Some(output) = self.output.as_ref() {
|
||||
if let Some(mode) = output.current_mode() {
|
||||
return (
|
||||
pos.x.max(0.0).min(mode.size.w as f64),
|
||||
pos.y.max(0.0).min(mode.size.h as f64),
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
pos
|
||||
}
|
||||
|
||||
fn update_keyboard_focus(&mut self, serial: Serial) {
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
let keyboard = self.seat.get_keyboard().unwrap();
|
||||
// change the keyboard focus unless the pointer or keyboard is grabbed
|
||||
// We test for any matching surface type here but always use the root
|
||||
// (in case of a window the toplevel) surface for the focus.
|
||||
// So for example if a user clicks on a subsurface or popup the toplevel
|
||||
// will receive the keyboard focus. Directly assigning the focus to the
|
||||
// matching surface leads to issues with clients dismissing popups and
|
||||
// subsurface menus (for example firefox-wayland).
|
||||
// see here for a discussion about that issue:
|
||||
// https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
|
||||
if !pointer.is_grabbed() && !keyboard.is_grabbed() {
|
||||
if let Some((window, _)) = self
|
||||
.space
|
||||
.element_under(self.pointer_location)
|
||||
.map(|(w, p)| (w.clone(), p))
|
||||
{
|
||||
self.space.raise_element(&window, true);
|
||||
keyboard.set_focus(self, Some(FocusTarget::from(window)), serial);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user