Merge pull request #189 from mahkoh/jorth/switch
config: allow handling switch events
This commit is contained in:
commit
a20008d446
21 changed files with 443 additions and 27 deletions
|
|
@ -425,6 +425,20 @@ You can use the `configure-connector` action to change this configuration at run
|
||||||
|
|
||||||
See the specification for more details.
|
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
|
### Configuring Input Devices
|
||||||
|
|
||||||
You can configure input devices with the top-level `inputs` array.
|
You can configure input devices with the top-level `inputs` array.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use {
|
||||||
exec::Command,
|
exec::Command,
|
||||||
input::{
|
input::{
|
||||||
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
|
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
|
||||||
Seat,
|
Seat, SwitchEvent,
|
||||||
},
|
},
|
||||||
keyboard::{
|
keyboard::{
|
||||||
mods::{Modifiers, RELEASE},
|
mods::{Modifiers, RELEASE},
|
||||||
|
|
@ -95,6 +95,7 @@ pub(crate) struct Client {
|
||||||
on_new_drm_device: RefCell<Option<Callback<DrmDevice>>>,
|
on_new_drm_device: RefCell<Option<Callback<DrmDevice>>>,
|
||||||
on_del_drm_device: RefCell<Option<Callback<DrmDevice>>>,
|
on_del_drm_device: RefCell<Option<Callback<DrmDevice>>>,
|
||||||
on_idle: RefCell<Option<Callback>>,
|
on_idle: RefCell<Option<Callback>>,
|
||||||
|
on_switch_event: RefCell<HashMap<InputDevice, Callback<SwitchEvent>>>,
|
||||||
bufs: RefCell<Vec<Vec<u8>>>,
|
bufs: RefCell<Vec<Vec<u8>>>,
|
||||||
reload: Cell<bool>,
|
reload: Cell<bool>,
|
||||||
read_interests: RefCell<HashMap<PollableId, Interest>>,
|
read_interests: RefCell<HashMap<PollableId, Interest>>,
|
||||||
|
|
@ -222,6 +223,7 @@ pub unsafe extern "C" fn init(
|
||||||
on_new_drm_device: Default::default(),
|
on_new_drm_device: Default::default(),
|
||||||
on_del_drm_device: Default::default(),
|
on_del_drm_device: Default::default(),
|
||||||
on_idle: Default::default(),
|
on_idle: Default::default(),
|
||||||
|
on_switch_event: Default::default(),
|
||||||
bufs: Default::default(),
|
bufs: Default::default(),
|
||||||
reload: Cell::new(false),
|
reload: Cell::new(false),
|
||||||
read_interests: Default::default(),
|
read_interests: Default::default(),
|
||||||
|
|
@ -603,6 +605,16 @@ impl Client {
|
||||||
*self.on_new_input_device.borrow_mut() = Some(cb(f));
|
*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) {
|
pub fn set_double_click_interval(&self, usec: u64) {
|
||||||
self.send(&ClientMessage::SetDoubleClickIntervalUsec { usec });
|
self.send(&ClientMessage::SetDoubleClickIntervalUsec { usec });
|
||||||
}
|
}
|
||||||
|
|
@ -1258,7 +1270,9 @@ impl Client {
|
||||||
run_cb("new input device", &handler, device);
|
run_cb("new input device", &handler, device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerMessage::DelInputDevice { .. } => {}
|
ServerMessage::DelInputDevice { device } => {
|
||||||
|
self.on_switch_event.borrow_mut().remove(&device);
|
||||||
|
}
|
||||||
ServerMessage::ConnectorConnect { device } => {
|
ServerMessage::ConnectorConnect { device } => {
|
||||||
let handler = self.on_connector_connected.borrow_mut().clone();
|
let handler = self.on_connector_connected.borrow_mut().clone();
|
||||||
if let Some(handler) = handler {
|
if let Some(handler) = handler {
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
input::{
|
input::{
|
||||||
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
|
acceleration::AccelProfile, capability::Capability, FocusFollowsMouseMode, InputDevice,
|
||||||
Seat,
|
Seat, SwitchEvent,
|
||||||
},
|
},
|
||||||
keyboard::{mods::Modifiers, syms::KeySym, Keymap},
|
keyboard::{mods::Modifiers, syms::KeySym, Keymap},
|
||||||
logging::LogLevel,
|
logging::LogLevel,
|
||||||
|
|
@ -83,6 +83,11 @@ pub enum ServerMessage {
|
||||||
effective_mods: Modifiers,
|
effective_mods: Modifiers,
|
||||||
sym: KeySym,
|
sym: KeySym,
|
||||||
},
|
},
|
||||||
|
SwitchEvent {
|
||||||
|
seat: Seat,
|
||||||
|
input_device: InputDevice,
|
||||||
|
event: SwitchEvent,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,11 @@ impl InputDevice {
|
||||||
pub fn devnode(self) -> String {
|
pub fn devnode(self) -> String {
|
||||||
get!(String::new()).input_device_devnode(self)
|
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.
|
/// A seat.
|
||||||
|
|
@ -479,3 +484,26 @@ pub fn set_double_click_distance(distance: i32) {
|
||||||
pub fn disable_default_seat() {
|
pub fn disable_default_seat() {
|
||||||
get!().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,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
- Add support for wp-drm-lease-v1.
|
- Add support for wp-drm-lease-v1.
|
||||||
- Focus-follows-mouse can now be disabled.
|
- Focus-follows-mouse can now be disabled.
|
||||||
- Add support for pointer-gestures-unstable-v1.
|
- Add support for pointer-gestures-unstable-v1.
|
||||||
|
- Configs can now handle switch events (laptop lid closed/opened).
|
||||||
|
|
||||||
# 1.1.0 (2024-04-22)
|
# 1.1.0 (2024-04-22)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
libinput::consts::DeviceCapability,
|
libinput::consts::DeviceCapability,
|
||||||
video::drm::{ConnectorType, DrmConnector, DrmError, DrmVersion},
|
video::drm::{ConnectorType, DrmConnector, DrmError, DrmVersion},
|
||||||
},
|
},
|
||||||
jay_config::video::GfxApi,
|
jay_config::{input::SwitchEvent, video::GfxApi},
|
||||||
std::{
|
std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
error::Error,
|
error::Error,
|
||||||
|
|
@ -312,6 +312,11 @@ pub enum InputEvent {
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
cancelled: bool,
|
cancelled: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SwitchEvent {
|
||||||
|
time_usec: u64,
|
||||||
|
event: SwitchEvent,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DrmEvent {
|
pub enum DrmEvent {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,14 @@ use {
|
||||||
consts::{
|
consts::{
|
||||||
LIBINPUT_BUTTON_STATE_PRESSED, LIBINPUT_KEY_STATE_PRESSED,
|
LIBINPUT_BUTTON_STATE_PRESSED, LIBINPUT_KEY_STATE_PRESSED,
|
||||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
|
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,
|
event::LibInputEvent,
|
||||||
},
|
},
|
||||||
utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt},
|
utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt},
|
||||||
},
|
},
|
||||||
|
jay_config::input::SwitchEvent,
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
uapi::c,
|
uapi::c,
|
||||||
};
|
};
|
||||||
|
|
@ -99,6 +102,7 @@ impl MetalBackend {
|
||||||
c::LIBINPUT_EVENT_GESTURE_PINCH_END => self.handle_gesture_pinch_end(event),
|
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_BEGIN => self.handle_gesture_hold_begin(event),
|
||||||
c::LIBINPUT_EVENT_GESTURE_HOLD_END => self.handle_gesture_hold_end(event),
|
c::LIBINPUT_EVENT_GESTURE_HOLD_END => self.handle_gesture_hold_end(event),
|
||||||
|
c::LIBINPUT_EVENT_SWITCH_TOGGLE => self.handle_switch_toggle(event),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -297,4 +301,23 @@ impl MetalBackend {
|
||||||
cancelled: event.cancelled(),
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
jay_seat_events::{
|
jay_seat_events::{
|
||||||
Axis120, AxisFrame, AxisInverted, AxisPx, AxisSource, AxisStop, Button, HoldBegin,
|
Axis120, AxisFrame, AxisInverted, AxisPx, AxisSource, AxisStop, Button, HoldBegin,
|
||||||
HoldEnd, Key, Modifiers, PinchBegin, PinchEnd, PinchUpdate, PointerAbs, PointerRel,
|
HoldEnd, Key, Modifiers, PinchBegin, PinchEnd, PinchUpdate, PointerAbs, PointerRel,
|
||||||
SwipeBegin, SwipeEnd, SwipeUpdate,
|
SwipeBegin, SwipeEnd, SwipeUpdate, SwitchEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -324,6 +324,26 @@ async fn run(seat_test: Rc<SeatTest>) {
|
||||||
println!();
|
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;
|
pending::<()>().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use {
|
||||||
ipc::{InitMessage, ServerFeature, ServerMessage, V1InitMessage},
|
ipc::{InitMessage, ServerFeature, ServerMessage, V1InitMessage},
|
||||||
ConfigEntry, VERSION,
|
ConfigEntry, VERSION,
|
||||||
},
|
},
|
||||||
input::{InputDevice, Seat},
|
input::{InputDevice, Seat, SwitchEvent},
|
||||||
keyboard::{mods::Modifiers, syms::KeySym},
|
keyboard::{mods::Modifiers, syms::KeySym},
|
||||||
video::{Connector, DrmDevice},
|
video::{Connector, DrmDevice},
|
||||||
},
|
},
|
||||||
|
|
@ -144,6 +144,14 @@ impl ConfigProxy {
|
||||||
pub fn idle(&self) {
|
pub fn idle(&self) {
|
||||||
self.send(&ServerMessage::Idle);
|
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 {
|
impl Drop for ConfigProxy {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::KeyState,
|
backend::{InputDeviceId, KeyState},
|
||||||
client::Client,
|
client::Client,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
ifs::wl_seat::{wl_pointer::PendingScroll, SeatId},
|
ifs::wl_seat::{wl_pointer::PendingScroll, SeatId},
|
||||||
|
|
@ -220,6 +220,22 @@ impl JaySeatEvents {
|
||||||
cancelled: cancelled as _,
|
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 {
|
impl JaySeatEventsRequestHandler for JaySeatEvents {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{ConnectorId, InputEvent, KeyState, AXIS_120},
|
backend::{ConnectorId, InputDeviceId, InputEvent, KeyState, AXIS_120},
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
config::InvokedShortcut,
|
config::InvokedShortcut,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
|
@ -37,9 +37,12 @@ use {
|
||||||
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
xkbcommon::{KeyboardState, XkbState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||||
},
|
},
|
||||||
isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt},
|
isnt::std_1::primitive::{IsntSlice2Ext, IsntSliceExt},
|
||||||
jay_config::keyboard::{
|
jay_config::{
|
||||||
mods::{Modifiers, CAPS, NUM, RELEASE},
|
input::SwitchEvent,
|
||||||
syms::{KeySym, SYM_Escape},
|
keyboard::{
|
||||||
|
mods::{Modifiers, CAPS, NUM, RELEASE},
|
||||||
|
syms::{KeySym, SYM_Escape},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
smallvec::SmallVec,
|
smallvec::SmallVec,
|
||||||
std::{cell::RefCell, collections::hash_map::Entry, rc::Rc},
|
std::{cell::RefCell, collections::hash_map::Entry, rc::Rc},
|
||||||
|
|
@ -200,7 +203,8 @@ impl WlSeatGlobal {
|
||||||
| InputEvent::PinchUpdate { time_usec, .. }
|
| InputEvent::PinchUpdate { time_usec, .. }
|
||||||
| InputEvent::PinchEnd { time_usec, .. }
|
| InputEvent::PinchEnd { time_usec, .. }
|
||||||
| InputEvent::HoldBegin { 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);
|
self.last_input_usec.set(time_usec);
|
||||||
if self.idle_notifications.is_not_empty() {
|
if self.idle_notifications.is_not_empty() {
|
||||||
for (_, notification) in self.idle_notifications.lock().drain() {
|
for (_, notification) in self.idle_notifications.lock().drain() {
|
||||||
|
|
@ -299,6 +303,9 @@ impl WlSeatGlobal {
|
||||||
time_usec,
|
time_usec,
|
||||||
cancelled,
|
cancelled,
|
||||||
} => self.hold_end(time_usec, cancelled),
|
} => self.hold_end(time_usec, cancelled),
|
||||||
|
InputEvent::SwitchEvent { time_usec, event } => {
|
||||||
|
self.switch_event(dev.device.id(), time_usec, event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,6 +511,15 @@ impl WlSeatGlobal {
|
||||||
self.gesture_owner.hold_end(self, time_usec, cancelled)
|
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>(
|
pub(super) fn key_event<F>(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
time_usec: u64,
|
time_usec: u64,
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||||
ServerMessage::DevicesEnumerated => {}
|
ServerMessage::DevicesEnumerated => {}
|
||||||
ServerMessage::InterestReady { .. } => {}
|
ServerMessage::InterestReady { .. } => {}
|
||||||
ServerMessage::Features { .. } => {}
|
ServerMessage::Features { .. } => {}
|
||||||
|
ServerMessage::SwitchEvent { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::libinput::{
|
crate::libinput::{
|
||||||
consts::{ButtonState, EventType, KeyState, PointerAxis},
|
consts::{ButtonState, EventType, KeyState, PointerAxis, Switch, SwitchState},
|
||||||
device::LibInputDevice,
|
device::LibInputDevice,
|
||||||
sys::{
|
sys::{
|
||||||
libinput_event, libinput_event_destroy, libinput_event_gesture,
|
libinput_event, libinput_event_destroy, libinput_event_gesture,
|
||||||
|
|
@ -10,14 +10,17 @@ use {
|
||||||
libinput_event_gesture_get_finger_count, libinput_event_gesture_get_scale,
|
libinput_event_gesture_get_finger_count, libinput_event_gesture_get_scale,
|
||||||
libinput_event_gesture_get_time_usec, libinput_event_get_device,
|
libinput_event_gesture_get_time_usec, libinput_event_get_device,
|
||||||
libinput_event_get_gesture_event, libinput_event_get_keyboard_event,
|
libinput_event_get_gesture_event, libinput_event_get_keyboard_event,
|
||||||
libinput_event_get_pointer_event, libinput_event_get_type, libinput_event_keyboard,
|
libinput_event_get_pointer_event, libinput_event_get_switch_event,
|
||||||
libinput_event_keyboard_get_key, libinput_event_keyboard_get_key_state,
|
libinput_event_get_type, libinput_event_keyboard, libinput_event_keyboard_get_key,
|
||||||
libinput_event_keyboard_get_time_usec, libinput_event_pointer,
|
libinput_event_keyboard_get_key_state, libinput_event_keyboard_get_time_usec,
|
||||||
libinput_event_pointer_get_button, libinput_event_pointer_get_button_state,
|
libinput_event_pointer, libinput_event_pointer_get_button,
|
||||||
libinput_event_pointer_get_dx, libinput_event_pointer_get_dx_unaccelerated,
|
libinput_event_pointer_get_button_state, libinput_event_pointer_get_dx,
|
||||||
libinput_event_pointer_get_dy, libinput_event_pointer_get_dy_unaccelerated,
|
libinput_event_pointer_get_dx_unaccelerated, libinput_event_pointer_get_dy,
|
||||||
libinput_event_pointer_get_scroll_value, libinput_event_pointer_get_scroll_value_v120,
|
libinput_event_pointer_get_dy_unaccelerated, libinput_event_pointer_get_scroll_value,
|
||||||
libinput_event_pointer_get_time_usec, libinput_event_pointer_has_axis,
|
libinput_event_pointer_get_scroll_value_v120, libinput_event_pointer_get_time_usec,
|
||||||
|
libinput_event_pointer_has_axis, libinput_event_switch,
|
||||||
|
libinput_event_switch_get_switch, libinput_event_switch_get_switch_state,
|
||||||
|
libinput_event_switch_get_time_usec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::marker::PhantomData,
|
std::marker::PhantomData,
|
||||||
|
|
@ -43,6 +46,11 @@ pub struct LibInputEventGesture<'a> {
|
||||||
pub(super) _phantom: PhantomData<&'a ()>,
|
pub(super) _phantom: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LibInputEventSwitch<'a> {
|
||||||
|
pub(super) event: *mut libinput_event_switch,
|
||||||
|
pub(super) _phantom: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Drop for LibInputEvent<'a> {
|
impl<'a> Drop for LibInputEvent<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -98,6 +106,18 @@ impl<'a> LibInputEvent<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn switch_event(&self) -> Option<LibInputEventSwitch> {
|
||||||
|
let res = unsafe { libinput_event_get_switch_event(self.event) };
|
||||||
|
if res.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(LibInputEventSwitch {
|
||||||
|
event: res,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LibInputEventKeyboard<'a> {
|
impl<'a> LibInputEventKeyboard<'a> {
|
||||||
|
|
@ -194,3 +214,17 @@ impl<'a> LibInputEventGesture<'a> {
|
||||||
unsafe { libinput_event_gesture_get_angle_delta(self.event) }
|
unsafe { libinput_event_gesture_get_angle_delta(self.event) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> LibInputEventSwitch<'a> {
|
||||||
|
pub fn time_usec(&self) -> u64 {
|
||||||
|
unsafe { libinput_event_switch_get_time_usec(self.event) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch(&self) -> Switch {
|
||||||
|
unsafe { Switch(libinput_event_switch_get_switch(self.event)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn switch_state(&self) -> SwitchState {
|
||||||
|
unsafe { SwitchState(libinput_event_switch_get_switch_state(self.event)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ pub struct libinput_event_keyboard(u8);
|
||||||
pub struct libinput_event_pointer(u8);
|
pub struct libinput_event_pointer(u8);
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct libinput_event_gesture(u8);
|
pub struct libinput_event_gesture(u8);
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct libinput_event_switch(u8);
|
||||||
|
|
||||||
#[link(name = "input")]
|
#[link(name = "input")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -155,6 +157,15 @@ extern "C" {
|
||||||
pub fn libinput_event_gesture_get_dy_unaccelerated(event: *mut libinput_event_gesture) -> f64;
|
pub fn libinput_event_gesture_get_dy_unaccelerated(event: *mut libinput_event_gesture) -> f64;
|
||||||
pub fn libinput_event_gesture_get_scale(event: *mut libinput_event_gesture) -> f64;
|
pub fn libinput_event_gesture_get_scale(event: *mut libinput_event_gesture) -> f64;
|
||||||
pub fn libinput_event_gesture_get_angle_delta(event: *mut libinput_event_gesture) -> f64;
|
pub fn libinput_event_gesture_get_angle_delta(event: *mut libinput_event_gesture) -> f64;
|
||||||
|
|
||||||
|
pub fn libinput_event_get_switch_event(
|
||||||
|
event: *mut libinput_event,
|
||||||
|
) -> *mut libinput_event_switch;
|
||||||
|
pub fn libinput_event_switch_get_switch(event: *mut libinput_event_switch) -> libinput_switch;
|
||||||
|
pub fn libinput_event_switch_get_switch_state(
|
||||||
|
event: *mut libinput_event_switch,
|
||||||
|
) -> libinput_switch_state;
|
||||||
|
pub fn libinput_event_switch_get_time_usec(event: *mut libinput_event_switch) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@ use {
|
||||||
},
|
},
|
||||||
toml::{self},
|
toml::{self},
|
||||||
},
|
},
|
||||||
|
ahash::AHashMap,
|
||||||
jay_config::{
|
jay_config::{
|
||||||
input::acceleration::AccelProfile,
|
input::{acceleration::AccelProfile, SwitchEvent},
|
||||||
keyboard::{mods::Modifiers, Keymap, ModifiedKeySym},
|
keyboard::{mods::Modifiers, Keymap, ModifiedKeySym},
|
||||||
logging::LogLevel,
|
logging::LogLevel,
|
||||||
status::MessageFormat,
|
status::MessageFormat,
|
||||||
|
|
@ -244,6 +245,7 @@ pub struct Input {
|
||||||
pub px_per_wheel_scroll: Option<f64>,
|
pub px_per_wheel_scroll: Option<f64>,
|
||||||
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
||||||
pub keymap: Option<ConfigKeymap>,
|
pub keymap: Option<ConfigKeymap>,
|
||||||
|
pub switch_actions: AHashMap<SwitchEvent, Action>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use {
|
||||||
extractor::{bol, fltorint, opt, recover, str, val, Extractor, ExtractorError},
|
extractor::{bol, fltorint, opt, recover, str, val, Extractor, ExtractorError},
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
parsers::{
|
parsers::{
|
||||||
|
action::ActionParser,
|
||||||
input_match::{InputMatchParser, InputMatchParserError},
|
input_match::{InputMatchParser, InputMatchParserError},
|
||||||
keymap::KeymapParser,
|
keymap::KeymapParser,
|
||||||
},
|
},
|
||||||
|
|
@ -15,8 +16,12 @@ use {
|
||||||
toml_value::Value,
|
toml_value::Value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ahash::AHashMap,
|
||||||
indexmap::IndexMap,
|
indexmap::IndexMap,
|
||||||
jay_config::input::acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT},
|
jay_config::input::{
|
||||||
|
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT},
|
||||||
|
SwitchEvent,
|
||||||
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,7 +70,14 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
natural_scrolling,
|
natural_scrolling,
|
||||||
px_per_wheel_scroll,
|
px_per_wheel_scroll,
|
||||||
),
|
),
|
||||||
(transform_matrix, keymap),
|
(
|
||||||
|
transform_matrix,
|
||||||
|
keymap,
|
||||||
|
on_lid_opened_val,
|
||||||
|
on_lid_closed_val,
|
||||||
|
on_converted_to_laptop_val,
|
||||||
|
on_converted_to_tablet_val,
|
||||||
|
),
|
||||||
) = ext.extract((
|
) = ext.extract((
|
||||||
(
|
(
|
||||||
opt(str("tag")),
|
opt(str("tag")),
|
||||||
|
|
@ -79,7 +91,14 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
recover(opt(bol("natural-scrolling"))),
|
recover(opt(bol("natural-scrolling"))),
|
||||||
recover(opt(fltorint("px-per-wheel-scroll"))),
|
recover(opt(fltorint("px-per-wheel-scroll"))),
|
||||||
),
|
),
|
||||||
(recover(opt(val("transform-matrix"))), opt(val("keymap"))),
|
(
|
||||||
|
recover(opt(val("transform-matrix"))),
|
||||||
|
opt(val("keymap")),
|
||||||
|
opt(val("on-lid-opened")),
|
||||||
|
opt(val("on-lid-closed")),
|
||||||
|
opt(val("on-converted-to-laptop")),
|
||||||
|
opt(val("on-converted-to-tablet")),
|
||||||
|
),
|
||||||
))?;
|
))?;
|
||||||
let accel_profile = match accel_profile {
|
let accel_profile = match accel_profile {
|
||||||
None => None,
|
None => None,
|
||||||
|
|
@ -125,6 +144,38 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let mut switch_actions = AHashMap::new();
|
||||||
|
let mut parse_action = |val: Option<Spanned<&Value>>, name, event| {
|
||||||
|
if let Some(val) = val {
|
||||||
|
if !self.tag_ok {
|
||||||
|
log::warn!(
|
||||||
|
"{name} has no effect in this position: {}",
|
||||||
|
self.cx.error3(val.span)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match val.parse(&mut ActionParser(self.cx)) {
|
||||||
|
Ok(a) => {
|
||||||
|
switch_actions.insert(event, a);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not parse {name} action: {}", self.cx.error(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parse_action(on_lid_opened_val, "on-lid-opened", SwitchEvent::LidOpened);
|
||||||
|
parse_action(on_lid_closed_val, "on-lid-closed", SwitchEvent::LidClosed);
|
||||||
|
parse_action(
|
||||||
|
on_converted_to_laptop_val,
|
||||||
|
"on-converted-to-laptop",
|
||||||
|
SwitchEvent::ConvertedToLaptop,
|
||||||
|
);
|
||||||
|
parse_action(
|
||||||
|
on_converted_to_tablet_val,
|
||||||
|
"on-converted-to-tablet",
|
||||||
|
SwitchEvent::ConvertedToTablet,
|
||||||
|
);
|
||||||
Ok(Input {
|
Ok(Input {
|
||||||
tag: tag.despan_into(),
|
tag: tag.despan_into(),
|
||||||
match_: match_val.parse_map(&mut InputMatchParser(self.cx))?,
|
match_: match_val.parse_map(&mut InputMatchParser(self.cx))?,
|
||||||
|
|
@ -138,6 +189,7 @@ impl<'a> Parser for InputParser<'a> {
|
||||||
px_per_wheel_scroll: px_per_wheel_scroll.despan(),
|
px_per_wheel_scroll: px_per_wheel_scroll.despan(),
|
||||||
transform_matrix,
|
transform_matrix,
|
||||||
keymap,
|
keymap,
|
||||||
|
switch_actions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ use {
|
||||||
exec::{set_env, unset_env, Command},
|
exec::{set_env, unset_env, Command},
|
||||||
get_workspace,
|
get_workspace,
|
||||||
input::{
|
input::{
|
||||||
get_seat, input_devices, on_new_input_device, FocusFollowsMouseMode, InputDevice, Seat,
|
capability::CAP_SWITCH, get_seat, input_devices, on_new_input_device,
|
||||||
|
FocusFollowsMouseMode, InputDevice, Seat, SwitchEvent,
|
||||||
},
|
},
|
||||||
is_reload,
|
is_reload,
|
||||||
keyboard::{Keymap, ModifiedKeySym},
|
keyboard::{Keymap, ModifiedKeySym},
|
||||||
|
|
@ -559,6 +560,8 @@ impl Drop for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SwitchActions = Vec<(InputMatch, AHashMap<SwitchEvent, Box<dyn Fn()>>)>;
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn unbind_all(&self) {
|
fn unbind_all(&self) {
|
||||||
let mut binds = self.persistent.binds.borrow_mut();
|
let mut binds = self.persistent.binds.borrow_mut();
|
||||||
|
|
@ -681,6 +684,23 @@ impl State {
|
||||||
set_font(font);
|
set_font(font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_switch_device(self: &Rc<Self>, dev: InputDevice, actions: &Rc<SwitchActions>) {
|
||||||
|
if !dev.has_capability(CAP_SWITCH) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let state = self.clone();
|
||||||
|
let actions = actions.clone();
|
||||||
|
dev.on_switch_event(move |ev| {
|
||||||
|
for (match_, actions) in &*actions {
|
||||||
|
if match_.matches(dev, &state) {
|
||||||
|
if let Some(action) = actions.get(&ev) {
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash)]
|
#[derive(Eq, PartialEq, Hash)]
|
||||||
|
|
@ -700,7 +720,7 @@ struct PersistentState {
|
||||||
fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
|
fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
|
||||||
let mut path = PathBuf::from(config_dir());
|
let mut path = PathBuf::from(config_dir());
|
||||||
path.push("config.toml");
|
path.push("config.toml");
|
||||||
let config = match std::fs::read(&path) {
|
let mut config = match std::fs::read(&path) {
|
||||||
Ok(input) => match parse_config(&input, |e| {
|
Ok(input) => match parse_config(&input, |e| {
|
||||||
log::warn!("Error while parsing {}: {}", path.display(), Report::new(e))
|
log::warn!("Error while parsing {}: {}", path.display(), Report::new(e))
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -768,6 +788,17 @@ fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
|
||||||
keymaps,
|
keymaps,
|
||||||
});
|
});
|
||||||
state.set_status(&config.status);
|
state.set_status(&config.status);
|
||||||
|
let mut switch_actions = vec![];
|
||||||
|
for input in &mut config.inputs {
|
||||||
|
let mut actions = AHashMap::new();
|
||||||
|
for (event, action) in input.switch_actions.drain() {
|
||||||
|
actions.insert(event, action.into_fn(&state));
|
||||||
|
}
|
||||||
|
if actions.len() > 0 {
|
||||||
|
switch_actions.push((input.match_.clone(), actions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let switch_actions = Rc::new(switch_actions);
|
||||||
match config.on_graphics_initialized {
|
match config.on_graphics_initialized {
|
||||||
None => on_graphics_initialized(|| ()),
|
None => on_graphics_initialized(|| ()),
|
||||||
Some(a) => on_graphics_initialized(a.into_fn(&state)),
|
Some(a) => on_graphics_initialized(a.into_fn(&state)),
|
||||||
|
|
@ -863,14 +894,19 @@ fn load_config(initial_load: bool, persistent: &Rc<PersistentState>) {
|
||||||
});
|
});
|
||||||
on_new_input_device({
|
on_new_input_device({
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
|
let switch_actions = switch_actions.clone();
|
||||||
move |c| {
|
move |c| {
|
||||||
for input in &config.inputs {
|
for input in &config.inputs {
|
||||||
if input.match_.matches(c, &state) {
|
if input.match_.matches(c, &state) {
|
||||||
input.apply(c, &state);
|
input.apply(c, &state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state.handle_switch_device(c, &switch_actions);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
for c in jay_config::input::input_devices() {
|
||||||
|
state.handle_switch_device(c, &switch_actions);
|
||||||
|
}
|
||||||
persistent
|
persistent
|
||||||
.seat
|
.seat
|
||||||
.set_focus_follows_mouse_mode(match config.focus_follows_mouse {
|
.set_focus_follows_mouse_mode(match config.focus_follows_mouse {
|
||||||
|
|
|
||||||
|
|
@ -825,6 +825,22 @@
|
||||||
"keymap": {
|
"keymap": {
|
||||||
"description": "The keymap to use for this device.\n\nThis overrides the global keymap. The keymap becomes active when a key is pressed.\n\n- Example:\n\n ```toml\n [[inputs]]\n match.name = \"ZSA Technology Labs Inc ErgoDox EZ\"\n keymap.name = \"external\"\n ```\n",
|
"description": "The keymap to use for this device.\n\nThis overrides the global keymap. The keymap becomes active when a key is pressed.\n\n- Example:\n\n ```toml\n [[inputs]]\n match.name = \"ZSA Technology Labs Inc ErgoDox EZ\"\n keymap.name = \"external\"\n ```\n",
|
||||||
"$ref": "#/$defs/Keymap"
|
"$ref": "#/$defs/Keymap"
|
||||||
|
},
|
||||||
|
"on-lid-closed": {
|
||||||
|
"description": "An action to execute when the laptop lid is closed.\n\nThis should only be used in the top-level inputs array.\n\n- Example:\n\n ```toml\n [[inputs]]\n match.name = \"<switch name>\"\n on-lid-closed = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = false } }\n on-lid-opened = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = true } }\n ```\n",
|
||||||
|
"$ref": "#/$defs/Action"
|
||||||
|
},
|
||||||
|
"on-lid-opened": {
|
||||||
|
"description": "An action to execute when the laptop lid is opened.\n\nThis should only be used in the top-level inputs array.\n\n- Example:\n\n ```toml\n [[inputs]]\n match.name = \"<switch name>\"\n on-lid-closed = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = false } }\n on-lid-opened = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = true } }\n ```\n",
|
||||||
|
"$ref": "#/$defs/Action"
|
||||||
|
},
|
||||||
|
"on-converted-to-laptop": {
|
||||||
|
"description": "An action to execute when the convertible device is converted to a laptop.\n\nThis should only be used in the top-level inputs array.\n",
|
||||||
|
"$ref": "#/$defs/Action"
|
||||||
|
},
|
||||||
|
"on-converted-to-tablet": {
|
||||||
|
"description": "An action to execute when the convertible device is converted to a tablet.\n\nThis should only be used in the top-level inputs array.\n",
|
||||||
|
"$ref": "#/$defs/Action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -1635,6 +1635,56 @@ The table has the following fields:
|
||||||
|
|
||||||
The value of this field should be a [Keymap](#types-Keymap).
|
The value of this field should be a [Keymap](#types-Keymap).
|
||||||
|
|
||||||
|
- `on-lid-closed` (optional):
|
||||||
|
|
||||||
|
An action to execute when the laptop lid is closed.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```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 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
The value of this field should be a [Action](#types-Action).
|
||||||
|
|
||||||
|
- `on-lid-opened` (optional):
|
||||||
|
|
||||||
|
An action to execute when the laptop lid is opened.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```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 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
The value of this field should be a [Action](#types-Action).
|
||||||
|
|
||||||
|
- `on-converted-to-laptop` (optional):
|
||||||
|
|
||||||
|
An action to execute when the convertible device is converted to a laptop.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
The value of this field should be a [Action](#types-Action).
|
||||||
|
|
||||||
|
- `on-converted-to-tablet` (optional):
|
||||||
|
|
||||||
|
An action to execute when the convertible device is converted to a tablet.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
The value of this field should be a [Action](#types-Action).
|
||||||
|
|
||||||
|
|
||||||
<a name="types-InputMatch"></a>
|
<a name="types-InputMatch"></a>
|
||||||
### `InputMatch`
|
### `InputMatch`
|
||||||
|
|
|
||||||
|
|
@ -1239,6 +1239,52 @@ Input:
|
||||||
match.name = "ZSA Technology Labs Inc ErgoDox EZ"
|
match.name = "ZSA Technology Labs Inc ErgoDox EZ"
|
||||||
keymap.name = "external"
|
keymap.name = "external"
|
||||||
```
|
```
|
||||||
|
on-lid-closed:
|
||||||
|
ref: Action
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
An action to execute when the laptop lid is closed.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```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 } }
|
||||||
|
```
|
||||||
|
on-lid-opened:
|
||||||
|
ref: Action
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
An action to execute when the laptop lid is opened.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
```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 } }
|
||||||
|
```
|
||||||
|
on-converted-to-laptop:
|
||||||
|
ref: Action
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
An action to execute when the convertible device is converted to a laptop.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
on-converted-to-tablet:
|
||||||
|
ref: Action
|
||||||
|
required: false
|
||||||
|
description: |
|
||||||
|
An action to execute when the convertible device is converted to a tablet.
|
||||||
|
|
||||||
|
This should only be used in the top-level inputs array.
|
||||||
|
|
||||||
|
|
||||||
AccelProfile:
|
AccelProfile:
|
||||||
|
|
|
||||||
|
|
@ -125,3 +125,10 @@ event hold_end {
|
||||||
time_usec: pod(u64),
|
time_usec: pod(u64),
|
||||||
cancelled: i32,
|
cancelled: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event switch_event {
|
||||||
|
seat: u32,
|
||||||
|
time_usec: pod(u64),
|
||||||
|
input_device: u32,
|
||||||
|
event: u32,
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue