mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-29 20:34:46 +01:00
Fix keyboard input to Steam games on winit
This commit is contained in:
parent
78e53abf95
commit
43d6cde926
5 changed files with 263 additions and 26 deletions
208
src/focus.rs
208
src/focus.rs
|
@ -1,8 +1,19 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
use smithay::{output::Output, utils::IsAlive};
|
||||
use smithay::{
|
||||
desktop::PopupKind,
|
||||
input::{
|
||||
keyboard::KeyboardTarget,
|
||||
pointer::{MotionEvent, PointerTarget},
|
||||
Seat,
|
||||
},
|
||||
output::Output,
|
||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
||||
utils::IsAlive,
|
||||
wayland::seat::WaylandFocus,
|
||||
};
|
||||
|
||||
use crate::window::WindowElement;
|
||||
use crate::{backend::Backend, state::State, window::WindowElement};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FocusState {
|
||||
|
@ -33,3 +44,196 @@ impl FocusState {
|
|||
self.focus_stack.push(window);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum FocusTarget {
|
||||
Window(WindowElement),
|
||||
Popup(PopupKind),
|
||||
// TODO: LayerSurface
|
||||
}
|
||||
|
||||
impl IsAlive for FocusTarget {
|
||||
fn alive(&self) -> bool {
|
||||
match self {
|
||||
FocusTarget::Window(window) => window.alive(),
|
||||
FocusTarget::Popup(popup) => popup.alive(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FocusTarget> for WlSurface {
|
||||
fn from(value: FocusTarget) -> Self {
|
||||
value.wl_surface().expect("no wl_surface")
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Backend> PointerTarget<State<B>> for FocusTarget {
|
||||
fn enter(&self, seat: &Seat<State<B>>, data: &mut State<B>, event: &MotionEvent) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => PointerTarget::enter(window, seat, data, event),
|
||||
FocusTarget::Popup(popup) => {
|
||||
PointerTarget::enter(popup.wl_surface(), seat, data, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &Seat<State<B>>, data: &mut State<B>, event: &MotionEvent) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => PointerTarget::motion(window, seat, data, event),
|
||||
FocusTarget::Popup(popup) => {
|
||||
PointerTarget::motion(popup.wl_surface(), seat, data, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
event: &smithay::input::pointer::RelativeMotionEvent,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => {
|
||||
PointerTarget::relative_motion(window, seat, data, event);
|
||||
}
|
||||
FocusTarget::Popup(popup) => {
|
||||
PointerTarget::relative_motion(popup.wl_surface(), seat, data, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn button(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
event: &smithay::input::pointer::ButtonEvent,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => PointerTarget::button(window, seat, data, event),
|
||||
FocusTarget::Popup(popup) => {
|
||||
PointerTarget::button(popup.wl_surface(), seat, data, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn axis(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
frame: smithay::input::pointer::AxisFrame,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame),
|
||||
FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame),
|
||||
}
|
||||
}
|
||||
|
||||
fn leave(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
serial: smithay::utils::Serial,
|
||||
time: u32,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => PointerTarget::leave(window, seat, data, serial, time),
|
||||
FocusTarget::Popup(popup) => {
|
||||
PointerTarget::leave(popup.wl_surface(), seat, data, serial, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Backend> KeyboardTarget<State<B>> for FocusTarget {
|
||||
fn enter(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
keys: Vec<smithay::input::keyboard::KeysymHandle<'_>>,
|
||||
serial: smithay::utils::Serial,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => KeyboardTarget::enter(window, seat, data, keys, serial),
|
||||
FocusTarget::Popup(popup) => {
|
||||
KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &Seat<State<B>>, data: &mut State<B>, serial: smithay::utils::Serial) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => KeyboardTarget::leave(window, seat, data, serial),
|
||||
FocusTarget::Popup(popup) => {
|
||||
KeyboardTarget::leave(popup.wl_surface(), seat, data, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn key(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
key: smithay::input::keyboard::KeysymHandle<'_>,
|
||||
state: smithay::backend::input::KeyState,
|
||||
serial: smithay::utils::Serial,
|
||||
time: u32,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => {
|
||||
KeyboardTarget::key(window, seat, data, key, state, serial, time);
|
||||
}
|
||||
FocusTarget::Popup(popup) => {
|
||||
KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn modifiers(
|
||||
&self,
|
||||
seat: &Seat<State<B>>,
|
||||
data: &mut State<B>,
|
||||
modifiers: smithay::input::keyboard::ModifiersState,
|
||||
serial: smithay::utils::Serial,
|
||||
) {
|
||||
match self {
|
||||
FocusTarget::Window(window) => {
|
||||
KeyboardTarget::modifiers(window, seat, data, modifiers, serial);
|
||||
}
|
||||
FocusTarget::Popup(popup) => {
|
||||
KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandFocus for FocusTarget {
|
||||
fn wl_surface(&self) -> Option<WlSurface> {
|
||||
match self {
|
||||
FocusTarget::Window(window) => window.wl_surface(),
|
||||
FocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn same_client_as(
|
||||
&self,
|
||||
object_id: &smithay::reexports::wayland_server::backend::ObjectId,
|
||||
) -> bool {
|
||||
match self {
|
||||
FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id),
|
||||
FocusTarget::Window(WindowElement::X11(surface)) => surface.same_client_as(object_id),
|
||||
FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WindowElement> for FocusTarget {
|
||||
fn from(value: WindowElement) -> Self {
|
||||
FocusTarget::Window(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PopupKind> for FocusTarget {
|
||||
fn from(value: PopupKind) -> Self {
|
||||
FocusTarget::Popup(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ use smithay::{
|
|||
},
|
||||
dmabuf,
|
||||
fractional_scale::{self, FractionalScaleHandler},
|
||||
seat::WaylandFocus,
|
||||
shell::xdg::{
|
||||
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
|
||||
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
|
||||
|
@ -49,6 +50,7 @@ use smithay::{
|
|||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
focus::FocusTarget,
|
||||
state::{CalloopData, ClientState, State, WithState},
|
||||
window::{window_state::WindowResizeState, WindowBlocker, WindowElement, BLOCKER_COUNTER},
|
||||
};
|
||||
|
@ -206,8 +208,8 @@ impl<B: Backend> DataDeviceHandler for State<B> {
|
|||
delegate_data_device!(@<B: Backend> State<B>);
|
||||
|
||||
impl<B: Backend> SeatHandler for State<B> {
|
||||
type KeyboardFocus = WlSurface;
|
||||
type PointerFocus = WlSurface;
|
||||
type KeyboardFocus = FocusTarget;
|
||||
type PointerFocus = FocusTarget;
|
||||
|
||||
fn seat_state(&mut self) -> &mut SeatState<Self> {
|
||||
&mut self.seat_state
|
||||
|
@ -219,14 +221,13 @@ impl<B: Backend> SeatHandler for State<B> {
|
|||
}
|
||||
|
||||
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&Self::KeyboardFocus>) {
|
||||
if let Some(wl_surface) = focused {
|
||||
if let Some(window) = self.window_for_surface(wl_surface) {
|
||||
if let Some(focus) = focused.and_then(|focus| focus.wl_surface()) {
|
||||
if let Some(window) = self.window_for_surface(&focus) {
|
||||
self.focus_state.set_focus(window);
|
||||
// let focus = focused.and_then(|surf| self.display_handle.get_client(surf.id()).ok());
|
||||
// set_data_device_focus(&self.display_handle, seat, focus);
|
||||
}
|
||||
}
|
||||
|
||||
let focus = focused.and_then(|surf| self.display_handle.get_client(surf.id()).ok());
|
||||
set_data_device_focus(&self.display_handle, seat, focus);
|
||||
}
|
||||
}
|
||||
delegate_seat!(@<B: Backend> State<B>);
|
||||
|
@ -347,7 +348,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
.expect("Seat had no keyboard") // FIXME: actually handle error
|
||||
.set_focus(
|
||||
&mut data.state,
|
||||
window.wl_surface(),
|
||||
Some(FocusTarget::Window(window)),
|
||||
SERIAL_COUNTER.next_serial(),
|
||||
);
|
||||
});
|
||||
|
@ -377,10 +378,7 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
// let mut windows: Vec<Window> = self.space.elements().cloned().collect();
|
||||
// windows.retain(|window| window.toplevel() != &surface);
|
||||
// Layouts::master_stack(self, windows, crate::layout::Direction::Left);
|
||||
let focus = self
|
||||
.focus_state
|
||||
.current_focus()
|
||||
.and_then(|win| win.wl_surface());
|
||||
let focus = self.focus_state.current_focus().map(FocusTarget::Window);
|
||||
self.seat
|
||||
.get_keyboard()
|
||||
.expect("Seat had no keyboard")
|
||||
|
@ -440,10 +438,9 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
.ok()
|
||||
.and_then(|root| self.window_for_surface(&root))
|
||||
{
|
||||
let Some(wl_surface) = root.wl_surface() else { return };
|
||||
if let Ok(mut grab) = self
|
||||
.popup_manager
|
||||
.grab_popup(wl_surface, popup_kind, &seat, serial)
|
||||
if let Ok(mut grab) =
|
||||
self.popup_manager
|
||||
.grab_popup(FocusTarget::Window(root), popup_kind, &seat, serial)
|
||||
{
|
||||
if let Some(keyboard) = seat.get_keyboard() {
|
||||
if keyboard.is_grabbed()
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
grab::resize_grab::{ResizeSurfaceGrab, ResizeSurfaceState},
|
||||
state::{CalloopData, WithState},
|
||||
window::{WindowBlocker, WindowElement, BLOCKER_COUNTER, window_state::Float},
|
||||
window::{WindowBlocker, WindowElement, BLOCKER_COUNTER, window_state::Float}, focus::FocusTarget,
|
||||
};
|
||||
|
||||
impl<B: Backend> XwmHandler for CalloopData<B> {
|
||||
|
@ -38,7 +38,17 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
|||
tracing::debug!("-----MAP WINDOW REQUEST");
|
||||
// tracing::debug!("new x11 window from map_window_request");
|
||||
// tracing::debug!("window popup is {}", window.is_popup());
|
||||
//
|
||||
// TODO: TOMORROW: figure out why keyboard input isn't going to games (prolly you never
|
||||
// | change keyboard focus)
|
||||
|
||||
if window.is_override_redirect() {
|
||||
let loc = window.geometry().loc;
|
||||
let window = WindowElement::X11(window);
|
||||
// tracing::debug!("mapped_override_redirect_window to loc {loc:?}");
|
||||
self.state.space.map_element(window, loc, true);
|
||||
return;
|
||||
}
|
||||
window.set_mapped(true).expect("failed to map x11 window");
|
||||
let window = WindowElement::X11(window);
|
||||
self.state.space.map_element(window.clone(), (0, 0), true);
|
||||
|
@ -174,7 +184,7 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
|
|||
.expect("Seat had no keyboard") // FIXME: actually handle error
|
||||
.set_focus(
|
||||
&mut data.state,
|
||||
window.wl_surface(),
|
||||
Some(FocusTarget::Window(window)),
|
||||
SERIAL_COUNTER.next_serial(),
|
||||
);
|
||||
});
|
||||
|
|
31
src/input.rs
31
src/input.rs
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
|||
|
||||
use crate::{
|
||||
api::msg::{CallbackId, Modifier, ModifierMask, OutgoingMsg},
|
||||
focus::FocusTarget,
|
||||
window::WindowElement,
|
||||
};
|
||||
use smithay::{
|
||||
|
@ -18,6 +19,7 @@ use smithay::{
|
|||
},
|
||||
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
|
||||
utils::{Logical, Point, SERIAL_COUNTER},
|
||||
wayland::compositor,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -144,15 +146,36 @@ impl<B: Backend> State<B> {
|
|||
.expect("no xwm")
|
||||
.raise_window(surface)
|
||||
.expect("failed to raise x11 win");
|
||||
surface.set_activated(true).unwrap();
|
||||
}
|
||||
|
||||
keyboard.set_focus(self, window.wl_surface(), serial);
|
||||
tracing::debug!(
|
||||
"wl_surface focus is some? {}",
|
||||
window.wl_surface().is_some()
|
||||
);
|
||||
keyboard.set_focus(self, Some(FocusTarget::Window(window.clone())), serial);
|
||||
|
||||
self.space.elements().for_each(|window| {
|
||||
if let WindowElement::Wayland(window) = window {
|
||||
window.toplevel().send_configure();
|
||||
}
|
||||
});
|
||||
|
||||
let focused_name = match &window {
|
||||
WindowElement::Wayland(win) => {
|
||||
compositor::with_states(win.toplevel().wl_surface(), |states| {
|
||||
let lock = states
|
||||
.data_map
|
||||
.get::<smithay::wayland::shell::xdg::XdgToplevelSurfaceData>()
|
||||
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
||||
.lock()
|
||||
.expect("failed to acquire lock");
|
||||
lock.app_id.clone().unwrap_or_default()
|
||||
})
|
||||
}
|
||||
WindowElement::X11(surf) => surf.class(),
|
||||
};
|
||||
tracing::debug!("setting keyboard focus to {focused_name}");
|
||||
}
|
||||
} else {
|
||||
self.space.elements().for_each(|window| match window {
|
||||
|
@ -361,7 +384,7 @@ impl State<WinitData> {
|
|||
.and_then(|(window, location)| {
|
||||
window
|
||||
.surface_under(pointer_loc - location.to_f64(), WindowSurfaceType::ALL)
|
||||
.map(|(s, p)| (s, p + location))
|
||||
.map(|(_s, p)| (FocusTarget::Window(window.clone()), p + location))
|
||||
});
|
||||
|
||||
pointer.motion(
|
||||
|
@ -418,7 +441,7 @@ impl State<UdevData> {
|
|||
|
||||
let surface_under = self
|
||||
.surface_under(self.pointer_location)
|
||||
.and_then(|(window, loc)| window.wl_surface().map(|surface| (surface, loc)));
|
||||
.map(|(window, loc)| (FocusTarget::Window(window), loc));
|
||||
|
||||
// tracing::info!("{:?}", self.pointer_location);
|
||||
if let Some(ptr) = self.seat.get_pointer() {
|
||||
|
@ -485,7 +508,7 @@ impl State<UdevData> {
|
|||
|
||||
let surface_under = self
|
||||
.surface_under(self.pointer_location)
|
||||
.and_then(|(window, loc)| window.wl_surface().map(|surface| (surface, loc)));
|
||||
.map(|(window, loc)| (FocusTarget::Window(window), loc));
|
||||
|
||||
if let Some(ptr) = self.seat.get_pointer() {
|
||||
ptr.motion(
|
||||
|
|
|
@ -7,8 +7,11 @@ use smithay::{
|
|||
},
|
||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
||||
utils::Serial,
|
||||
wayland::seat::WaylandFocus,
|
||||
};
|
||||
|
||||
use crate::focus::FocusTarget;
|
||||
|
||||
/// Returns the [GrabStartData] from a pointer grab, if any.
|
||||
pub fn pointer_grab_start_data<S>(
|
||||
pointer: &PointerHandle<S>,
|
||||
|
@ -16,7 +19,7 @@ pub fn pointer_grab_start_data<S>(
|
|||
serial: Serial,
|
||||
) -> Option<GrabStartData<S>>
|
||||
where
|
||||
S: SeatHandler<PointerFocus = WlSurface> + 'static,
|
||||
S: SeatHandler<PointerFocus = FocusTarget> + 'static,
|
||||
{
|
||||
println!("start of pointer_grab_start_data");
|
||||
if !pointer.has_grab(serial) {
|
||||
|
@ -28,7 +31,7 @@ where
|
|||
|
||||
let (focus_surface, _point) = start_data.focus.as_ref()?;
|
||||
|
||||
if !focus_surface.id().same_client_as(&surface.id()) {
|
||||
if !focus_surface.same_client_as(&surface.id()) {
|
||||
println!("surface isn't the same");
|
||||
return None;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue