Skip to content

Commit

Permalink
config: allow handling switch events
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 28, 2024
1 parent 55d55bf commit cf233ab
Show file tree
Hide file tree
Showing 21 changed files with 443 additions and 27 deletions.
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

0 comments on commit cf233ab

Please sign in to comment.