Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: allow handling switch events #189

Merged
merged 1 commit into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,20 @@ You can use the `configure-connector` action to change this configuration at run

See the specification for more details.

### Disabling Connectors of Closed Laptops

If a laptop has a switch that is signaled when the laptop is closed, you can configure
the built-in connector to be disabled automatically:

```toml
[[inputs]]
match.name = "<switch name>"
on-lid-closed = { type = "configure-connector", connector = { match.name = "eDP-1", enabled = false } }
on-lid-opened = { type = "configure-connector", connector = { match.name = "eDP-1", enabled = true } }
```

See the specification for more details.

### Configuring Input Devices

You can configure input devices with the top-level `inputs` array.
Expand Down
29 changes: 27 additions & 2 deletions jay-config/src/_private/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use {
exec::Command,
input::{
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
Seat,
Seat, SwitchEvent,
},
keyboard::{
mods::{Modifiers, RELEASE},
Expand Down Expand Up @@ -95,6 +95,7 @@ pub(crate) struct Client {
on_new_drm_device: RefCell<Option<Callback<DrmDevice>>>,
on_del_drm_device: RefCell<Option<Callback<DrmDevice>>>,
on_idle: RefCell<Option<Callback>>,
on_switch_event: RefCell<HashMap<InputDevice, Callback<SwitchEvent>>>,
bufs: RefCell<Vec<Vec<u8>>>,
reload: Cell<bool>,
read_interests: RefCell<HashMap<PollableId, Interest>>,
Expand Down Expand Up @@ -222,6 +223,7 @@ pub unsafe extern "C" fn init(
on_new_drm_device: Default::default(),
on_del_drm_device: Default::default(),
on_idle: Default::default(),
on_switch_event: Default::default(),
bufs: Default::default(),
reload: Cell::new(false),
read_interests: Default::default(),
Expand Down Expand Up @@ -603,6 +605,16 @@ impl Client {
*self.on_new_input_device.borrow_mut() = Some(cb(f));
}

pub fn on_switch_event<F: FnMut(SwitchEvent) + 'static>(
&self,
input_device: InputDevice,
f: F,
) {
self.on_switch_event
.borrow_mut()
.insert(input_device, cb(f));
}

pub fn set_double_click_interval(&self, usec: u64) {
self.send(&ClientMessage::SetDoubleClickIntervalUsec { usec });
}
Expand Down Expand Up @@ -1258,7 +1270,9 @@ impl Client {
run_cb("new input device", &handler, device);
}
}
ServerMessage::DelInputDevice { .. } => {}
ServerMessage::DelInputDevice { device } => {
self.on_switch_event.borrow_mut().remove(&device);
}
ServerMessage::ConnectorConnect { device } => {
let handler = self.on_connector_connected.borrow_mut().clone();
if let Some(handler) = handler {
Expand Down Expand Up @@ -1332,6 +1346,17 @@ impl Client {
}
}
}
ServerMessage::SwitchEvent {
seat,
input_device,
event,
} => {
let _ = seat;
let cb = self.on_switch_event.borrow().get(&input_device).cloned();
if let Some(cb) = cb {
run_cb("switch event", &cb, event);
}
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion jay-config/src/_private/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
input::{
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
Seat,
Seat, SwitchEvent,
},
keyboard::{mods::Modifiers, syms::KeySym, Keymap},
logging::LogLevel,
Expand Down Expand Up @@ -83,6 +83,11 @@ pub enum ServerMessage {
effective_mods: Modifiers,
sym: KeySym,
},
SwitchEvent {
seat: Seat,
input_device: InputDevice,
event: SwitchEvent,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down
28 changes: 28 additions & 0 deletions jay-config/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ impl InputDevice {
pub fn devnode(self) -> String {
get!(String::new()).input_device_devnode(self)
}

/// Sets a callback that will be run if this device triggers a switch event.
pub fn on_switch_event<F: FnMut(SwitchEvent) + 'static>(self, f: F) {
get!().on_switch_event(self, f)
}
}

/// A seat.
Expand Down Expand Up @@ -479,3 +484,26 @@ pub fn set_double_click_distance(distance: i32) {
pub fn disable_default_seat() {
get!().disable_default_seat();
}

/// An event generated by a switch.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum SwitchEvent {
/// The lid of the device (usually a laptop) has been opened.
///
/// This is the default state.
LidOpened,
/// The lid of the device (usually a laptop) has been closed.
///
/// If the device is already in this state when the device is discovered, a synthetic
/// event of this kind is generated.
LidClosed,
/// The device has been converted from tablet to laptop mode.
///
/// This is the default state.
ConvertedToLaptop,
/// The device has been converted from laptop to tablet mode.
///
/// If the device is already in this state when the device is discovered, a synthetic
/// event of this kind is generated.
ConvertedToTablet,
}
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Add support for wp-drm-lease-v1.
- Focus-follows-mouse can now be disabled.
- Add support for pointer-gestures-unstable-v1.
- Configs can now handle switch events (laptop lid closed/opened).

# 1.1.0 (2024-04-22)

Expand Down
7 changes: 6 additions & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
libinput::consts::DeviceCapability,
video::drm::{ConnectorType, DrmConnector, DrmError, DrmVersion},
},
jay_config::video::GfxApi,
jay_config::{input::SwitchEvent, video::GfxApi},
std::{
any::Any,
error::Error,
Expand Down Expand Up @@ -312,6 +312,11 @@ pub enum InputEvent {
time_usec: u64,
cancelled: bool,
},

SwitchEvent {
time_usec: u64,
event: SwitchEvent,
},
}

pub enum DrmEvent {
Expand Down
23 changes: 23 additions & 0 deletions src/backends/metal/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ use {
consts::{
LIBINPUT_BUTTON_STATE_PRESSED, LIBINPUT_KEY_STATE_PRESSED,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
LIBINPUT_SWITCH_LID, LIBINPUT_SWITCH_STATE_OFF, LIBINPUT_SWITCH_STATE_ON,
LIBINPUT_SWITCH_TABLET_MODE,
},
event::LibInputEvent,
},
utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt},
},
jay_config::input::SwitchEvent,
std::rc::Rc,
uapi::c,
};
Expand Down Expand Up @@ -99,6 +102,7 @@ impl MetalBackend {
c::LIBINPUT_EVENT_GESTURE_PINCH_END => self.handle_gesture_pinch_end(event),
c::LIBINPUT_EVENT_GESTURE_HOLD_BEGIN => self.handle_gesture_hold_begin(event),
c::LIBINPUT_EVENT_GESTURE_HOLD_END => self.handle_gesture_hold_end(event),
c::LIBINPUT_EVENT_SWITCH_TOGGLE => self.handle_switch_toggle(event),
_ => {}
}
}
Expand Down Expand Up @@ -297,4 +301,23 @@ impl MetalBackend {
cancelled: event.cancelled(),
});
}

fn handle_switch_toggle(self: &Rc<Self>, event: LibInputEvent) {
let (event, dev) = unpack!(self, event, switch_event);
let switch_event = match (event.switch(), event.switch_state()) {
(LIBINPUT_SWITCH_LID, LIBINPUT_SWITCH_STATE_OFF) => SwitchEvent::LidOpened,
(LIBINPUT_SWITCH_LID, LIBINPUT_SWITCH_STATE_ON) => SwitchEvent::LidClosed,
(LIBINPUT_SWITCH_TABLET_MODE, LIBINPUT_SWITCH_STATE_OFF) => {
SwitchEvent::ConvertedToLaptop
}
(LIBINPUT_SWITCH_TABLET_MODE, LIBINPUT_SWITCH_STATE_ON) => {
SwitchEvent::ConvertedToTablet
}
_ => return,
};
dev.event(InputEvent::SwitchEvent {
time_usec: event.time_usec(),
event: switch_event,
});
}
}
22 changes: 21 additions & 1 deletion src/cli/seat_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
jay_seat_events::{
Axis120, AxisFrame, AxisInverted, AxisPx, AxisSource, AxisStop, Button, HoldBegin,
HoldEnd, Key, Modifiers, PinchBegin, PinchEnd, PinchUpdate, PointerAbs, PointerRel,
SwipeBegin, SwipeEnd, SwipeUpdate,
SwipeBegin, SwipeEnd, SwipeUpdate, SwitchEvent,
},
},
},
Expand Down Expand Up @@ -324,6 +324,26 @@ async fn run(seat_test: Rc<SeatTest>) {
println!();
}
});
let st = seat_test.clone();
SwitchEvent::handle(tc, se, (), move |_, ev| {
let event = match ev.event {
0 => "lid opened",
1 => "lid closed",
2 => "converted to laptop",
3 => "converted to tablet",
_ => "unknown event",
};
if all || ev.seat == seat {
if all {
print!("Seat: {}, ", st.name(ev.seat));
}
println!(
"Time: {:.4}, Device: {}, {event}",
time(ev.time_usec),
ev.input_device
);
}
});
pending::<()>().await;
}

Expand Down
10 changes: 9 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use {
ipc::{InitMessage, ServerFeature, ServerMessage, V1InitMessage},
ConfigEntry, VERSION,
},
input::{InputDevice, Seat},
input::{InputDevice, Seat, SwitchEvent},
keyboard::{mods::Modifiers, syms::KeySym},
video::{Connector, DrmDevice},
},
Expand Down Expand Up @@ -144,6 +144,14 @@ impl ConfigProxy {
pub fn idle(&self) {
self.send(&ServerMessage::Idle);
}

pub fn switch_event(&self, seat: SeatId, input_device: InputDeviceId, event: SwitchEvent) {
self.send(&ServerMessage::SwitchEvent {
seat: Seat(seat.raw() as _),
input_device: InputDevice(input_device.raw() as _),
event,
});
}
}

impl Drop for ConfigProxy {
Expand Down
18 changes: 17 additions & 1 deletion src/ifs/jay_seat_events.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{
backend::KeyState,
backend::{InputDeviceId, KeyState},
client::Client,
fixed::Fixed,
ifs::wl_seat::{wl_pointer::PendingScroll, SeatId},
Expand Down Expand Up @@ -220,6 +220,22 @@ impl JaySeatEvents {
cancelled: cancelled as _,
});
}

pub fn send_switch_event(
&self,
seat: SeatId,
input_device: InputDeviceId,
time_usec: u64,
event: jay_config::input::SwitchEvent,
) {
self.client.event(SwitchEvent {
self_id: self.id,
seat: seat.raw(),
time_usec,
input_device: input_device.raw(),
event: event as _,
});
}
}

impl JaySeatEventsRequestHandler for JaySeatEvents {
Expand Down
26 changes: 21 additions & 5 deletions src/ifs/wl_seat/event_handling.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{
backend::{ConnectorId, InputEvent, KeyState, AXIS_120},
backend::{ConnectorId, InputDeviceId, InputEvent, KeyState, AXIS_120},
client::ClientId,
config::InvokedShortcut,
fixed::Fixed,
Expand Down Expand Up @@ -37,9 +37,12 @@ use {
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
},
isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt},
jay_config::keyboard::{
mods::{Modifiers, CAPS, NUM, RELEASE},
syms::{KeySym, SYM_Escape},
jay_config::{
input::SwitchEvent,
keyboard::{
mods::{Modifiers, CAPS, NUM, RELEASE},
syms::{KeySym, SYM_Escape},
},
},
smallvec::SmallVec,
std::{cell::RefCell, collections::hash_map::Entry, rc::Rc},
Expand Down Expand Up @@ -200,7 +203,8 @@ impl WlSeatGlobal {
| InputEvent::PinchUpdate { time_usec, .. }
| InputEvent::PinchEnd { time_usec, .. }
| InputEvent::HoldBegin { time_usec, .. }
| InputEvent::HoldEnd { time_usec, .. } => {
| InputEvent::HoldEnd { time_usec, .. }
| InputEvent::SwitchEvent { time_usec, .. } => {
self.last_input_usec.set(time_usec);
if self.idle_notifications.is_not_empty() {
for (_, notification) in self.idle_notifications.lock().drain() {
Expand Down Expand Up @@ -299,6 +303,9 @@ impl WlSeatGlobal {
time_usec,
cancelled,
} => self.hold_end(time_usec, cancelled),
InputEvent::SwitchEvent { time_usec, event } => {
self.switch_event(dev.device.id(), time_usec, event)
}
}
}

Expand Down Expand Up @@ -504,6 +511,15 @@ impl WlSeatGlobal {
self.gesture_owner.hold_end(self, time_usec, cancelled)
}

fn switch_event(self: &Rc<Self>, dev: InputDeviceId, time_usec: u64, event: SwitchEvent) {
self.state.for_each_seat_tester(|t| {
t.send_switch_event(self.id, dev, time_usec, event);
});
if let Some(config) = self.state.config.get() {
config.switch_event(self.id, dev, event);
}
}

pub(super) fn key_event<F>(
self: &Rc<Self>,
time_usec: u64,
Expand Down
1 change: 1 addition & 0 deletions src/it/test_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
ServerMessage::DevicesEnumerated => {}
ServerMessage::InterestReady { .. } => {}
ServerMessage::Features { .. } => {}
ServerMessage::SwitchEvent { .. } => {}
}
}

Expand Down
Loading
Loading