Skip to content

Commit

Permalink
feat: alias-to-trigger-on-load, allow-hardware-repeat, --quiet
Browse files Browse the repository at this point in the history
- Add option to ignore hardware repeat events
- Add abiity to execute a given alias at startup
- Add a README on how to convert .adoc to .html
- Add a cfg_sample for learning the Colemak layout
- Add --quiet command line option
  • Loading branch information
loops authored Oct 14, 2024
1 parent 356d54a commit 310aaa0
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 4 deletions.
63 changes: 63 additions & 0 deletions cfg_samples/colemak.kbd
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
;;
;; Learn Colemak, a few keys at a time.
;;
;; The "j" key moves around the keyboard each step,
;; until you reach the full Colemak layout.
;;
;; To select the layout for your current step, press the
;; letter "m" and the number of your current step, as a chord.
;;
;; Check out: https://dreymar.colemak.org/tarmak-intro.html
;; and: https://colemak.com
;;

(defsrc
q w e r t y u i o p
a s d f g h j k l ;
z x c v b n m
)

(deflayer colemak_j1
_ _ j _ _ _ _ _ _ _
_ _ _ _ _ _ n e _ _
_ _ _ _ _ k _
)

(deflayer colemak_j2
_ _ f _ g _ _ _ _ _
_ _ _ t j _ n e _ _
_ _ _ _ _ k _
)

(deflayer colemak_j3
_ _ f j g _ _ _ _ _
_ r s t d _ n e _ _
_ _ _ _ _ k _
)

(deflayer colemak_j4
_ _ f p g j _ _ y ;
_ r s t d _ n e _ o
_ _ _ _ _ k _
)

(deflayer colemak
_ _ f p g j l u y ;
_ r s t d _ n e i o
_ _ _ _ _ k _
)

(defcfg
process-unmapped-keys yes
concurrent-tap-hold yes
allow-hardware-repeat no
)

(defchordsv2-experimental
(m 1) (layer-switch colemak_j1) 300 all-released ()
(m 2) (layer-switch colemak_j2) 300 all-released ()
(m 3) (layer-switch colemak_j3) 300 all-released ()
(m 4) (layer-switch colemak_j4) 300 all-released ()
(m 5) (layer-switch colemak) 300 all-released ()
)

6 changes: 6 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

### Converting ".adoc" to html

To generate html from the these documentation files, use ["asciidoctor"](https://asciidoctor.org)
(they are not fully compatible with the separate "asciidoc" project)

54 changes: 54 additions & 0 deletions docs/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2327,6 +2327,60 @@ when activated by the override which is important to consider for your use cases
)
----

[[allow-hardware-repeat]]
=== allow-hardware-repeat
<<table-of-contents,Back to ToC>>

By default, any repeat-key events generated by the physical keyboard (or operating system)
will be passed through to the application. On Linux, under Wayland, this is wasted effort
since the DE handles key-repeat on its own. Such events can also be distracting when
debugging your configuration with evtest, etc.

Setting this option to "false" will cause such events to be dropped, and not passed through.
This is primarily meant for Linux, but may find some use on Mac. It is not implemented on
Windows, and will be silently ignored.

.Example:
[source]
----
(defcfg
allow-hardware-repeat false
)
----

[[alias-to-trigger-on-load]]
=== alias-to-trigger-on-load
<<table-of-contents,Back to ToC>>

Select an alias to execute when first starting, and after each
live-reload of the config. You can use this to run external
commands, or to stack layers (with layer-while-held).

The name of an alias, without a leading "@", is expected as a
parameter. The example below will beep at startup (assuming
your system has a beep command), and will already be blocking
the swapped "i" and "o" keys.

.Example:
[source]
----
(defcfg
alias-to-trigger-on-load S
danger-enable-cmd yes
)
(deffakekeys B (layer-while-held block))
(defalias
P (on-press toggle-vkey B)
S (macro @P (cmd beep))
)
(defsrc i o p )
(deflayer base o i @P )
(deflayer block • • _ )
----

[[linux-only-linux-dev]]
=== Linux only: linux-dev
<<table-of-contents,Back to ToC>>
Expand Down
17 changes: 17 additions & 0 deletions parser/src/cfg/defcfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ impl Default for CfgOptionsGui {
pub struct CfgOptions {
pub process_unmapped_keys: bool,
pub block_unmapped_keys: bool,
pub allow_hardware_repeat: bool,
pub start_alias: Option<String>,
pub enable_cmd: bool,
pub sequence_timeout: u16,
pub sequence_input_mode: SequenceInputMode,
Expand Down Expand Up @@ -138,6 +140,8 @@ impl Default for CfgOptions {
Self {
process_unmapped_keys: false,
block_unmapped_keys: false,
allow_hardware_repeat: true,
start_alias: None,
enable_cmd: false,
sequence_timeout: 1000,
sequence_input_mode: SequenceInputMode::HiddenSuppressed,
Expand Down Expand Up @@ -631,6 +635,12 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result<CfgOptions> {
"block-unmapped-keys" => {
cfg.block_unmapped_keys = parse_defcfg_val_bool(val, label)?
}
"allow-hardware-repeat" => {
cfg.allow_hardware_repeat = parse_defcfg_val_bool(val, label)?
}
"alias-to-trigger-on-load" => {
cfg.start_alias = parse_defcfg_val_string(val, label)?
}
"danger-enable-cmd" => cfg.enable_cmd = parse_defcfg_val_bool(val, label)?,
"sequence-backtrack-modcancel" => {
cfg.sequence_backtrack_modcancel = parse_defcfg_val_bool(val, label)?
Expand Down Expand Up @@ -695,6 +705,13 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result<CfgOptions> {
}
}

fn parse_defcfg_val_string(expr: &SExpr, _label: &str) -> Result<Option<String>> {
match expr {
SExpr::Atom(v) => Ok(Some(v.t.clone())),
_ => Ok(None),
}
}

pub const FALSE_VALUES: [&str; 3] = ["no", "false", "0"];
pub const TRUE_VALUES: [&str; 3] = ["yes", "true", "1"];
pub const BOOLEAN_VALUES: [&str; 6] = ["yes", "true", "1", "no", "false", "0"];
Expand Down
13 changes: 13 additions & 0 deletions parser/src/cfg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ fn parse_cfg(p: &Path) -> MResult<Cfg> {
layout.bm().chords_v2 = icfg.chords_v2;
layout.bm().quick_tap_hold_timeout = icfg.options.concurrent_tap_hold;
layout.bm().oneshot.on_press_release_delay = icfg.options.rapid_event_delay;
if let Some(s) = icfg.start_action {
layout.bm().action_queue.push_front(Some(((1, 0), 0, s)));
}
let mut fake_keys: HashMap<String, usize> = s
.virtual_keys
.iter()
Expand Down Expand Up @@ -405,6 +408,7 @@ pub struct IntermediateCfg {
pub sequences: KeySeqsToFKeys,
pub overrides: Overrides,
pub chords_v2: Option<ChordsV2<'static, KanataCustom>>,
pub start_action: Option<&'static KanataAction>,
}

// A snapshot of enviroment variables, or an error message with an explanation
Expand Down Expand Up @@ -798,6 +802,14 @@ pub fn parse_cfg_raw_string(
.collect::<Vec<_>>();
parse_aliases(&alias_exprs, s, &env_vars)?;

let start_action = cfg
.start_alias
.as_ref()
.and_then(|start| s.aliases.get(start).copied());
if let (Some(_), None) = (cfg.start_alias.as_ref(), start_action) {
bail!("alias-to-trigger-on-load was given, but alias could not be found")
}

let mut klayers = parse_layers(s, &mut mapped_keys, &cfg)?;

resolve_chord_groups(&mut klayers, s)?;
Expand Down Expand Up @@ -874,6 +886,7 @@ pub fn parse_cfg_raw_string(
sequences,
overrides,
chords_v2,
start_action,
})
}

Expand Down
5 changes: 5 additions & 0 deletions src/kanata/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ impl Kanata {
info!("entering the event loop");

let k = kanata.lock();
let allow_hardware_repeat = k.allow_hardware_repeat;
let mut kbd_in = match KbdIn::new(
&k.kbd_in_paths,
k.continue_if_no_devices,
Expand Down Expand Up @@ -58,6 +59,10 @@ impl Kanata {

check_for_exit(&key_event);

if key_event.value == KeyValue::Repeat && !allow_hardware_repeat {
continue;
}

if key_event.value == KeyValue::Tap {
// Scroll event for sure. Only scroll events produce Tap.
if !handle_scroll(&kanata, in_event, key_event.code, &events)? {
Expand Down
5 changes: 5 additions & 0 deletions src/kanata/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ impl Kanata {
info!("entering the event loop");

let k = kanata.lock();
let allow_hardware_repeat = k.allow_hardware_repeat;
let mut kb = match KbdIn::new(k.include_names.clone()) {
Ok(kbd_in) => kbd_in,
Err(e) => bail!("failed to open keyboard device(s): {}", e),
Expand All @@ -40,6 +41,10 @@ impl Kanata {

check_for_exit(&key_event);

if key_event.value == KeyValue::Repeat && !allow_hardware_repeat {
continue;
}

if !MAPPED_KEYS.lock().contains(&key_event.code) {
log::debug!("{key_event:?} is not mapped");
let mut kanata = kanata.lock();
Expand Down
3 changes: 3 additions & 0 deletions src/kanata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ pub struct Kanata {
#[cfg(all(target_os = "windows", feature = "gui"))]
/// Various GUI-related options.
pub gui_opts: CfgOptionsGui,
pub allow_hardware_repeat: bool,
}

#[derive(PartialEq, Clone, Copy)]
Expand Down Expand Up @@ -405,6 +406,7 @@ impl Kanata {
tcp_server_address: args.tcp_server_address.clone(),
#[cfg(all(target_os = "windows", feature = "gui"))]
gui_opts: cfg.options.gui_opts,
allow_hardware_repeat: cfg.options.allow_hardware_repeat,
})
}

Expand Down Expand Up @@ -523,6 +525,7 @@ impl Kanata {
tcp_server_address: None,
#[cfg(all(target_os = "windows", feature = "gui"))]
gui_opts: cfg.options.gui_opts,
allow_hardware_repeat: cfg.options.allow_hardware_repeat,
})
}

Expand Down
13 changes: 9 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ kanata.kbd in the current working directory and
#[arg(short, long)]
list: bool,

/// Disable logging, except for errors. Takes precedent over debug and trace.
#[arg(short, long)]
quiet: bool,

/// Enable debug logging.
#[arg(short, long)]
debug: bool,
Expand Down Expand Up @@ -112,10 +116,11 @@ mod cli {

let cfg_paths = args.cfg.unwrap_or_else(default_cfg);

let log_lvl = match (args.debug, args.trace) {
(_, true) => LevelFilter::Trace,
(true, false) => LevelFilter::Debug,
(false, false) => LevelFilter::Info,
let log_lvl = match (args.debug, args.trace, args.quiet) {
(_, true, false) => LevelFilter::Trace,
(true, false, false) => LevelFilter::Debug,
(false, false, false) => LevelFilter::Info,
(_, _, true) => LevelFilter::Error,
};

let mut log_cfg = ConfigBuilder::new();
Expand Down

0 comments on commit 310aaa0

Please sign in to comment.