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

feat(linux): allow configuring output device bus type #1239

Merged
merged 4 commits into from
Sep 15, 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: 12 additions & 2 deletions cfg_samples/kanata.kbd
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,16 @@ If you need help, please feel welcome to ask in the GitHub discussions.
;;
;; linux-unicode-termination space

;; Kanata on Linux needs to declare a "bus type" for its evdev output device.
;; The options are USB and I8042. The default is I8042.
;; Using USB can break disable-touchpad-while-typing on Wayland.
;; But using I8042 appears to break some other scenarios. Thus it is configurable.
;;
;; Examples:
;;
;; linux-output-device-bus-type USB
;; linux-output-device-bus-type I8042

;; There is an optional configuration entry for Windows to help mitigate strange
;; behaviour of AltGr if your layout uses that. Uncomment one of the items below
;; to change what kanata does with the key.
Expand Down Expand Up @@ -708,7 +718,7 @@ If you need help, please feel welcome to ask in the GitHub discussions.
;;
;; The command takes two extra arguments at the beginning `<log_level>`,
;; and `<error_log_level>`. `<log_level>` controls where the name
;; of the command is logged, as well as the success message and command
;; of the command is logged, as well as the success message and command
;; stdout and stderr.
;;
;; `<error_log_level>` is only used if there is a failure executing the initial
Expand All @@ -729,7 +739,7 @@ If you need help, please feel welcome to ask in the GitHub discussions.
;; of the command and treats it as an S-Expression, similarly to `macro`.
;; However, only delays, keys, chords, and chorded lists are supported.
;; Other actions are not.
;;
;;
;; bash: type date-time as YYYY-MM-DD HH:MM
;; cmd-output-keys bash -c "date +'%F %R' | sed 's/./& /g' | sed 's/:/S-;/g' | sed 's/\(.\{20\}\)\(.*\)/\(\1 spc \2\)/'"
)
Expand Down
18 changes: 18 additions & 0 deletions docs/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,24 @@ changing their behavior as well.
)
----

[[linux-only-linux-output-device-bus-type]]
=== Linux only: linux-output-device-bus-type
<<table-of-contents,Back to ToC>>

Kanata on Linux needs to declare a "bus type" for its evdev output device.
The options are `USB` and `I8042`, with the default as `I8042`.
Using USB can https://github.com/jtroo/kanata/pull/661[break disable-touchpad-while-typing on Wayland].
But using I8042 appears to break https://github.com/jtroo/kanata/issues/1131[some other scenarios].
Thus the output bus type is configurable.

.Example:
[source]
----
(defcfg
linux-output-device-bus-type USB
)
----

[[macos-only-macos-dev-names-include]]
=== macOS only: macos-dev-names-include
<<table-of-contents,Back to ToC>>
Expand Down
32 changes: 24 additions & 8 deletions parser/src/cfg/defcfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,15 @@ use crate::{anyhow_expr, anyhow_span, bail, bail_expr, bail_span};
#[cfg(any(target_os = "linux", target_os = "unknown"))]
#[derive(Debug, Clone)]
pub struct CfgLinuxOptions {
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_dev: Vec<String>,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_dev_names_include: Option<Vec<String>>,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_dev_names_exclude: Option<Vec<String>>,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_continue_if_no_devs_found: bool,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_unicode_u_code: crate::keys::OsCode,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_unicode_termination: UnicodeTermination,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_x11_repeat_delay_rate: Option<KeyRepeatSettings>,
#[cfg(any(target_os = "linux", target_os = "unknown"))]
pub linux_use_trackpoint_property: bool,
pub linux_output_bus_type: LinuxCfgOutputBusType,
}
#[cfg(any(target_os = "linux", target_os = "unknown"))]
impl Default for CfgLinuxOptions {
Expand All @@ -40,9 +33,16 @@ impl Default for CfgLinuxOptions {
linux_unicode_termination: UnicodeTermination::Enter,
linux_x11_repeat_delay_rate: None,
linux_use_trackpoint_property: false,
linux_output_bus_type: LinuxCfgOutputBusType::BusI8042,
}
}
}
#[cfg(any(target_os = "linux", target_os = "unknown"))]
#[derive(Debug, Clone, Copy)]
pub enum LinuxCfgOutputBusType {
BusUsb,
BusI8042,
}

#[cfg(any(
all(feature = "interception_driver", target_os = "windows"),
Expand Down Expand Up @@ -311,6 +311,22 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result<CfgOptions> {
parse_defcfg_val_bool(val, label)?
}
}
"linux-output-device-bus-type" => {
let bus_type = sexpr_to_str_or_err(val, label)?;
match bus_type {
"USB" | "I8042" => {},
_ => bail_expr!(val, "Invalid value for linux-output-device-bus-type.\nExpected one of: USB or I8042"),
};
#[cfg(any(target_os = "linux", target_os = "unknown"))]
{
let bus_type = match bus_type {
"USB" => LinuxCfgOutputBusType::BusUsb,
"I8042" => LinuxCfgOutputBusType::BusI8042,
_ => unreachable!("validated earlier"),
};
cfg.linux_opts.linux_output_bus_type = bus_type;
}
}
"windows-altgr" => {
#[cfg(any(target_os = "windows", target_os = "unknown"))]
{
Expand Down
31 changes: 31 additions & 0 deletions parser/src/cfg/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,8 @@ fn parse_all_defcfg() {
linux-unicode-u-code v
linux-unicode-termination space
linux-x11-repeat-delay-rate 400,50
linux-use-trackpoint-property yes
linux-output-device-bus-type USB
tray-icon symbols.ico
icon-match-layer-name no
tooltip-layer-changes yes
Expand All @@ -1389,6 +1391,35 @@ fn parse_all_defcfg() {
.expect("parses");
}

#[test]
fn parse_defcfg_linux_output_bus() {
let source = r#"
(defcfg linux-output-device-bus-type USB)
(defsrc a)
(deflayer base a)
"#;
parse_cfg(source)
.map_err(|e| eprintln!("{:?}", miette::Error::from(e)))
.expect("parses");
let source = r#"
(defcfg linux-output-device-bus-type I8042)
(defsrc a)
(deflayer base a)
"#;
parse_cfg(source)
.map_err(|e| eprintln!("{:?}", miette::Error::from(e)))
.expect("parses");
let source = r#"
(defcfg linux-output-device-bus-type INVALID)
(defsrc a)
(deflayer base a)
"#;
let err = parse_cfg(source).expect_err("should err");
assert!(err
.msg
.contains("Invalid value for linux-output-device-bus-type"));
}

#[test]
fn parse_unmod() {
let source = r#"
Expand Down
10 changes: 10 additions & 0 deletions src/kanata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ impl Kanata {
&args.symlink_path,
#[cfg(target_os = "linux")]
cfg.options.linux_opts.linux_use_trackpoint_property,
#[cfg(target_os = "linux")]
match cfg.options.linux_opts.linux_output_bus_type {
LinuxCfgOutputBusType::BusUsb => evdev::BusType::BUS_USB,
LinuxCfgOutputBusType::BusI8042 => evdev::BusType::BUS_I8042,
},
) {
Ok(kbd_out) => kbd_out,
Err(err) => {
Expand Down Expand Up @@ -421,6 +426,11 @@ impl Kanata {
&None,
#[cfg(target_os = "linux")]
cfg.options.linux_opts.linux_use_trackpoint_property,
#[cfg(target_os = "linux")]
match cfg.options.linux_opts.linux_output_bus_type {
LinuxCfgOutputBusType::BusUsb => evdev::BusType::BUS_USB,
LinuxCfgOutputBusType::BusI8042 => evdev::BusType::BUS_I8042,
},
) {
Ok(kbd_out) => kbd_out,
Err(err) => {
Expand Down
9 changes: 7 additions & 2 deletions src/oskbd/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#![cfg_attr(feature = "simulated_output", allow(dead_code, unused_imports))]

pub use evdev::BusType;
use evdev::{uinput, Device, EventType, InputEvent, PropType, RelativeAxisType};
use inotify::{Inotify, WatchMask};
use mio::{unix::SourceFd, Events, Interest, Poll, Token};
Expand Down Expand Up @@ -324,7 +325,11 @@ pub struct KbdOut {

#[cfg(all(not(feature = "simulated_output"), not(feature = "passthru_ahk")))]
impl KbdOut {
pub fn new(symlink_path: &Option<String>, trackpoint: bool) -> Result<Self, io::Error> {
pub fn new(
symlink_path: &Option<String>,
trackpoint: bool,
bus_type: BusType,
) -> Result<Self, io::Error> {
// Support pretty much every feature of a Keyboard or a Mouse in a VirtualDevice so that no event from the original input devices gets lost
// TODO investigate the rare possibility that a device is e.g. a Joystick and a Keyboard or a Mouse at the same time, which could lead to lost events

Expand All @@ -349,7 +354,7 @@ impl KbdOut {
.name("kanata")
// libinput's "disable while typing" feature don't work when bus_type
// is set to BUS_USB, but appears to work when it's set to BUS_I8042.
.input_id(evdev::InputId::new(evdev::BusType::BUS_I8042, 1, 1, 1))
.input_id(evdev::InputId::new(bus_type, 1, 1, 1))
.with_keys(&keys)?
.with_relative_axes(&relative_axes)?;
let device = if trackpoint {
Expand Down
6 changes: 5 additions & 1 deletion src/oskbd/simulated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,11 @@ impl KbdOut {
Self::new_actual()
}
#[cfg(target_os = "linux")]
pub fn new(_s: &Option<String>, _tp: bool) -> Result<Self, io::Error> {
pub fn new(
_s: &Option<String>,
_tp: bool,
_bustype: evdev::BusType,
) -> Result<Self, io::Error> {
Self::new_actual()
}
#[cfg(target_os = "linux")]
Expand Down
Loading