From 6976120fab9927f7b1b8277ddaac1fbeaf849cc7 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 27 May 2024 22:57:51 +0700 Subject: [PATCH 01/18] dep: add color error message support --- parser/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parser/Cargo.toml b/parser/Cargo.toml index f2116c914..b5ac56eef 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -27,6 +27,8 @@ thiserror = "1.0.38" # binary. kanata-keyberon = { path = "../keyberon" } bytemuck = "1.15.0" +colored = "2.1.0" +num-format = "0.4.4" [features] cmd = [] From 677fae9cf58785a82083cfb89956ab580dfa783f Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 00:35:33 +0700 Subject: [PATCH 02/18] dep: add support for custom colors in error messages --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 92b899b1d..100da29a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ rustc-hash = "1.1.0" simplelog = "0.12.0" serde_json = { version = "1", features = ["std"], default_features = false, optional = true } time = "0.3.36" +colored = "2.1.0" # kanata-keyberon = "0.161.0" # kanata-parser = "0.161.0" # kanata-tcp-protocol = "0.161.0" From c16cdcd87928af4e927cb050cb211d4cb26c0e22 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 00:36:02 +0700 Subject: [PATCH 03/18] dep: add WinAPI string conversion helpers --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 100da29a6..282ca76d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -102,6 +102,7 @@ windows-sys = { version = "0.52.0", features = [ "Wdk_System", "Wdk_System_SystemServices", ], optional=true } +widestring = "1.1.0" native-windows-gui = { version = "1.0.13", default_features = false} regex = { version = "1.10.4", optional = true } kanata-interception = { version = "0.2.0", optional = true } From 7d23585f22692e644ad859c02a2b8cd9178b68d3 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 01:09:22 +0700 Subject: [PATCH 04/18] doc: add Windows message config config sample --- cfg_samples/win-msg/insert-date.ahk | 43 +++++++++++++++++++++++++++++ cfg_samples/win-msg/win-msg.kbd | 17 ++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 cfg_samples/win-msg/insert-date.ahk create mode 100644 cfg_samples/win-msg/win-msg.kbd diff --git a/cfg_samples/win-msg/insert-date.ahk b/cfg_samples/win-msg/insert-date.ahk new file mode 100644 index 000000000..2953fb756 --- /dev/null +++ b/cfg_samples/win-msg/insert-date.ahk @@ -0,0 +1,43 @@ +#Requires AutoHotkey v2.0 +Persistent true +listen_to_Kanata1() +listen_to_Kanata1() { + static msgIDtxt := "kanata_4117d2917ccb4678a7a8c71a5ff898ed" ; must be set to the same value in Kanata + static msgID := DllCall("RegisterWindowMessage", "Str",msgIDtxt), MSGFLT_ALLOW := 1 + if winID_self:=WinExist(A_ScriptHwnd) { ; need to allow some messages through due to AHK running with UIA access https://stackoverflow.com/questions/40122964/cross-process-postmessage-uipi-restrictions-and-uiaccess-true + isRes := DllCall("ChangeWindowMessageFilterEx" ; learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changewindowmessagefilterex?redirectedfrom=MSDN + , "Ptr",winID_self ;i HWND hwnd handle to the window whose UIPI message filter is to be modified + ,"UInt",msgID ;i UINT message message that the message filter allows through or blocks + ,"UInt",MSGFLT_ALLOW ;i DWORD action + , "Ptr",0) ;io opt PCHANGEFILTERSTRUCT pChangeFilterStruct + } + OnMessage(msgID, setnv_mode, MaxThreads:=1) + setnv_mode(wParam, lParam, msgID, hwnd) { + if wParam == 1 { + curtime := FormatTime(,"dddd MMMM d, yyyy H:mm:ss") + } else if wParam == 2 { + curtime := FormatTime(,"yy") + } else { + curtime := "✗ wParam=" wParam " lParam=" lParam + } + SetKeyDelay(-1, 0) + SendEvent(curtime) + } +} + +listen_to_Kanata2() +listen_to_Kanata2() { + static msgIDtxt := "kanata_your_custom_message_string_unique_id" ; must be set to the same value in Kanata + static msgID := DllCall("RegisterWindowMessage", "Str",msgIDtxt), MSGFLT_ALLOW := 1 + if winID_self:=WinExist(A_ScriptHwnd) { ; need to allow some messages through due to AHK running with UIA access https://stackoverflow.com/questions/40122964/cross-process-postmessage-uipi-restrictions-and-uiaccess-true + isRes := DllCall("ChangeWindowMessageFilterEx" ; learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changewindowmessagefilterex?redirectedfrom=MSDN + , "Ptr",winID_self ;i HWND hwnd handle to the window whose UIPI message filter is to be modified + ,"UInt",msgID ;i UINT message message that the message filter allows through or blocks + ,"UInt",MSGFLT_ALLOW ;i DWORD action + , "Ptr",0) ;io opt PCHANGEFILTERSTRUCT pChangeFilterStruct + } + OnMessage(msgID, setnv_mode, MaxThreads:=1) + setnv_mode(wParam, lParam, msgID, hwnd) { + SendInput("@kanata_your_custom_message_string_unique_id Unknown wParam=" wParam "lParam=" lParam) + } +} diff --git a/cfg_samples/win-msg/win-msg.kbd b/cfg_samples/win-msg/win-msg.kbd new file mode 100644 index 000000000..83c4b7f4d --- /dev/null +++ b/cfg_samples/win-msg/win-msg.kbd @@ -0,0 +1,17 @@ +#| +|# +(defcfg + process-unmapped-keys yes + log-layer-changes yes + danger-enable-cmd yes +) +(defsrc 1 2 3 4 5 6 7 8 9 0) +(deflayermap (win-msg) 1 1 2 2 +3 (msg❖async 1 ) ;; print date in the ‘dddd MMMM d, yyyy H:mm:ss’ format +4 (win-post-msg 2 ) ;; print date in the ‘yy’ format +5 (win-post-msg 3 ) ;; print error ‘✗ wParam=3 lParam=0’ +6 (msg❖async 3 0 "" "kanata_your_custom_message_string_unique_id") ;; print long message +8 lrld +9 lrld-prev +0 lrld-next +) From bf98b2753bad86b715c354af71be4ca01de40d30 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 01:43:58 +0700 Subject: [PATCH 05/18] doc: update config.adoc --- docs/config.adoc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/config.adoc b/docs/config.adoc index 213db400b..536cb9b10 100644 --- a/docs/config.adoc +++ b/docs/config.adoc @@ -2509,6 +2509,36 @@ they are an arbitrary length and can be very long. ) ---- +[[windows-only-send-message]] +=== Windows only: send-message +<> + +`msg❖async` or `win-post-msg` command allows sharing 2 numbers with any app you control +via Windows system messages mechanism. For example, you can set your AutoHotkey script to print + +- a short date if Kanata sends it `1`, and +- a long date if it sends `2` + +The command accepts at most 5 optional parameters (order sensitive!): +[cols="1,1"] +|=== +|Name | Default +|numeric arg #1 |`0` +|numeric arg #2 |`0` +|target window title |`\AutoHotkey.ahk` +|shared message string id |`kanata_4117d2917ccb4678a7a8c71a5ff898ed` +|target window class |`AutoHotkey` +|=== + +Window title and class are currently **ignored** and the messages are posted to all the windows. +Parameters are order sensitive, so if you want to skip the 3rd title string, set it to an empty `""`. + +See https://github.com/jtroo/kanata/blob/main/cfg_samples/win-msg/win-msg.kbd[example config] for more details. +Requires https://www.autohotkey.com/download/[AutoHotkey v2] and a running +https://github.com/jtroo/kanata/blob/main/cfg_samples/win-msg/insert-date.kbd[example script]. +See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagew[PostMessageW] for more +API details. + [[windows-only-tray-icon]] === Windows only: tray-icon <> From 9664003959d79f1357caf487fd812de8ceed1af8 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 01:59:45 +0700 Subject: [PATCH 06/18] test: add tests for Windows messages --- parser/src/cfg/tests.rs | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 9381d63d9..7d4cb7ea7 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -1954,3 +1954,51 @@ fn disallow_whitespace_in_tooltip_size() { "; parse_cfg(source).map(|_| ()).expect_err("fails"); } + + +#[test] +fn win_message_ok() { + let source = r#" +(defcfg) +(defsrc 3 4 5 6 7) +(deflayermap (win-msg) +3 (msg❖async 1 ) +4 (win-post-msg 2 ) +5 (win-post-msg 3 ) +6 (msg❖async 3 0 "" "kanata_your_custom_message_string_unique_id") +) +"#; + parse_cfg(source) + .map_err(|e| eprintln!("{:?}", miette::Error::from(e))) + .expect("parse succeeds"); +} + +#[test] +fn win_message_wrong_number_value() { + let source = " +(defcfg) +(defsrc 1) +(deflayer base (msg❖async -1)) +"; + parse_cfg(source).map(|_| ()).expect_err("fails"); +} + +#[test] +fn win_message_wrong_number_type() { + let source = r#" +(defcfg) +(defsrc 1) +(deflayer base (msg❖async "a" )) +"#; + parse_cfg(source).map(|_| ()).expect_err("fails"); +} + +#[test] +fn win_message_too_many_args() { + let source = r#" +(defcfg) +(defsrc 1) +(deflayer base (msg❖async 0 1 "a" "b" "c" 5 )) +"#; + parse_cfg(source).map(|_| ()).expect_err("fails"); +} From 3cdc1b5b23aaebd09f0bc5dff630e72234a97c3b Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:00:20 +0700 Subject: [PATCH 07/18] parse(win): add WinSend/Post message actions --- parser/src/cfg/list_actions.rs | 8 ++++++++ parser/src/custom_action.rs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/parser/src/cfg/list_actions.rs b/parser/src/cfg/list_actions.rs index 243f6991f..de8c525da 100644 --- a/parser/src/cfg/list_actions.rs +++ b/parser/src/cfg/list_actions.rs @@ -86,6 +86,10 @@ pub const DYNAMIC_MACRO_PLAY: &str = "dynamic-macro-play"; pub const ARBITRARY_CODE: &str = "arbitrary-code"; pub const CMD: &str = "cmd"; pub const PUSH_MESSAGE: &str = "push-msg"; +pub const SEND_WMSG_SYNC: &str = "win-send-msg"; +pub const SEND_WMSG_SYNC_A: &str = "msg❖sync"; +pub const SEND_WMSG_ASYNC: &str = "win-post-msg"; +pub const SEND_WMSG_ASYNC_A: &str = "msg❖async"; pub const CMD_OUTPUT_KEYS: &str = "cmd-output-keys"; pub const FORK: &str = "fork"; pub const CAPS_WORD: &str = "caps-word"; @@ -197,6 +201,10 @@ pub fn is_list_action(ac: &str) -> bool { CMD, CMD_OUTPUT_KEYS, PUSH_MESSAGE, + SEND_WMSG_SYNC, + SEND_WMSG_ASYNC, + SEND_WMSG_SYNC_A, + SEND_WMSG_ASYNC_A, FORK, CAPS_WORD, CAPS_WORD_A, diff --git a/parser/src/custom_action.rs b/parser/src/custom_action.rs index 491e53a95..7b008bec5 100644 --- a/parser/src/custom_action.rs +++ b/parser/src/custom_action.rs @@ -3,6 +3,7 @@ //! When adding a new custom action, the macro section of the config.adoc documentation may need to //! be updated, to include the new action to the documented list of supported actions in macro. +use crate::cfg::{WinMsg}; use anyhow::{anyhow, Result}; use core::fmt; use kanata_keyberon::key_code::KeyCode; @@ -14,6 +15,8 @@ pub enum CustomAction { Cmd(Vec), CmdOutputKeys(Vec), PushMessage(Vec), + WinSendMessage(WinMsg), + WinPostMessage(WinMsg), Unicode(char), Mouse(Btn), MouseTap(Btn), From 7f0ccbe7c31f7e6cd9e3e96758a7192d9bf3ce84 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:00:55 +0700 Subject: [PATCH 08/18] parse(win): add window message custom action parser --- parser/src/cfg/mod.rs | 8 +++ parser/src/cfg/windows.rs | 103 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 parser/src/cfg/windows.rs diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index b77ec7ad9..a378d2069 100755 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -1693,6 +1693,10 @@ fn parse_action_list(ac: &[SExpr], s: &ParserState) -> Result<&'static KanataAct CMD => parse_cmd(&ac[1..], s, CmdType::Standard), CMD_OUTPUT_KEYS => parse_cmd(&ac[1..], s, CmdType::OutputKeys), PUSH_MESSAGE => parse_push_message(&ac[1..], s), + SEND_WMSG_SYNC => win_send_message(&ac[1..], s, SEND_WMSG_SYNC), + SEND_WMSG_SYNC_A => win_send_message(&ac[1..], s, SEND_WMSG_SYNC_A), + SEND_WMSG_ASYNC => win_post_message(&ac[1..], s, SEND_WMSG_ASYNC), + SEND_WMSG_ASYNC_A => win_post_message(&ac[1..], s, SEND_WMSG_ASYNC_A), FORK => parse_fork(&ac[1..], s), CAPS_WORD | CAPS_WORD_A => { parse_caps_word(&ac[1..], CapsWordRepressBehaviour::Overwrite, s) @@ -2299,6 +2303,10 @@ fn parse_push_message(ac_params: &[SExpr], s: &ParserState) -> Result<&'static K let message = to_simple_expr(ac_params, s); custom(CustomAction::PushMessage(message), &s.a) } +#[cfg(any(target_os = "windows", target_os = "unknown"))] +pub mod windows; +#[cfg(any(target_os = "windows", target_os = "unknown"))] +pub use windows::*; fn to_simple_expr(params: &[SExpr], s: &ParserState) -> Vec { let mut result: Vec = Vec::new(); diff --git a/parser/src/cfg/windows.rs b/parser/src/cfg/windows.rs new file mode 100644 index 000000000..5a3d84efb --- /dev/null +++ b/parser/src/cfg/windows.rs @@ -0,0 +1,103 @@ +use crate::cfg::error::*; + +use crate::cfg::custom; +use crate::cfg::KanataAction; +use crate::cfg::ParseError; +use crate::cfg::ParserState; +use crate::cfg::SExpr; +use crate::cfg::str_ext::TrimAtomQuotes; +use crate::custom_action::CustomAction; +use std::ops::Deref; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WinMsgSid(String); +impl Default for WinMsgSid { + fn default() -> Self {Self("kanata_4117d2917ccb4678a7a8c71a5ff898ed".to_string())} //TODO: replace with str +} +impl Into for WinMsgSid { + fn into(self) -> String {self.0} } +impl Deref for WinMsgSid {type Target = String; fn deref(&self) -> &Self::Target {&self.0}} +impl AsRef for WinMsgSid + where T: ?Sized, ::Target: AsRef, { + fn as_ref(&self) -> &T { + self.deref().as_ref() + } +} +impl From for WinMsgSid { + fn from(s: String) -> Self {WinMsgSid(s )} } +impl From<&str> for WinMsgSid { + fn from(s: &str ) -> Self {WinMsgSid(s.to_string())} } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct WinMsgTarget { + win_class: String, + win_name : String, +} +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] +pub struct WinMsg { + pub win_tgt : WinMsgTarget, + pub msg_sid : WinMsgSid, + pub argu : usize, + pub argi : isize, +} +impl Default for WinMsgTarget { + fn default() -> Self { Self { + win_class : "AutoHotkey".to_string(), //TODO: replace with str + win_name : "\\AutoHotkey.ahk".to_string(), } } +} + +use colored::*; +use num_format::{Locale, ToFormattedString}; +pub fn to_win_msg(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result { + const ERR_MSG: &str = "expects at most 5 parameters: 2 message numeric arguments, target window title, shared message string id, target window class"; + let cmd_name = cmd_name.blue().bold(); + if ac_params.len() > 5 {bail!("{} {}",cmd_name,ERR_MSG);} + let mut win_tgt:WinMsgTarget = Default::default(); + let mut msg_sid = Default::default(); + let mut argu = Default::default(); + let mut argi = Default::default(); + if ac_params.len() > 0 { let arg = &ac_params[0]; + if let Some(a) = arg.atom(s.vars()) { + argu = match str::parse::(a.trim_atom_quotes()) { + Ok(argu) => argu, + Err(_) => bail_expr!(&arg, "invalid numeric argument, expected {}–{}. {} {}", + usize::MIN.to_formatted_string(&Locale::en).blue(),usize::MAX.to_formatted_string(&Locale::en).blue(),cmd_name,ERR_MSG), + } + } else {bail!("{ERR_MSG}");} + } + if ac_params.len() > 1 { let arg = &ac_params[1]; + if let Some(a) = arg.atom(s.vars()) { + argi = match str::parse::(a.trim_atom_quotes()) { + Ok(argi) => argi, + Err(_) => bail_expr!(&arg, "invalid numeric argument, expected {}–{}. {} {}", + isize::MIN.to_formatted_string(&Locale::en).blue(),isize::MAX.to_formatted_string(&Locale::en).blue(),cmd_name,ERR_MSG), + } + } else {bail!("{ERR_MSG}");} + } + if ac_params.len() > 2 { let arg = &ac_params[2]; + if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); + if ! a.is_empty() {win_tgt.win_name = a.to_string();} + } else {bail_expr!(&arg, "invalid target window {}. {} {}","file name".blue(),cmd_name,ERR_MSG)} + } + if ac_params.len() > 3 { let arg = &ac_params[3]; + if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); + if ! a.is_empty() {msg_sid = a.into();} + } else {bail_expr!(&arg, "invalid message shared {}. {} {}","string id".blue(),cmd_name,ERR_MSG)} + } + if ac_params.len() > 4 { let arg = &ac_params[4]; + if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); + if ! a.is_empty() {win_tgt.win_class = a.to_string();} + } else {bail_expr!(&arg, "invalid target window {}. {} {}","class".blue(),cmd_name,ERR_MSG)} + } + Ok(WinMsg{win_tgt,msg_sid,argu,argi}) +} + +pub fn win_send_message(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result<&'static KanataAction> { + let win_msg = to_win_msg(ac_params, s, cmd_name)?; + log::trace!("win_msg = {:?}",win_msg); + custom(CustomAction::WinSendMessage(win_msg), &s.a) +} +pub fn win_post_message(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result<&'static KanataAction> { + let win_msg = to_win_msg(ac_params, s, cmd_name)?; + log::trace!("win_msg = {:?}",win_msg); + custom(CustomAction::WinPostMessage(win_msg), &s.a) +} From 3cb41699d4410c3ed80342bc6161605a2b39d2d7 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:01:21 +0700 Subject: [PATCH 09/18] feat(win): add custom actions to send messages on Windows --- src/kanata/mod.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index 365d93303..b0ced7f42 100755 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -51,6 +51,8 @@ use cmd::*; mod windows; #[cfg(target_os = "windows")] pub use windows::*; +#[cfg(all(target_os = "windows"))] +use windows_sys::Win32::Foundation::{HWND,WPARAM,LPARAM}; #[cfg(target_os = "linux")] mod linux; @@ -1323,6 +1325,43 @@ impl Kanata { PUSH_MESSAGE ); } + CustomAction::WinSendMessage(_win_msg) => { + #[cfg(target_os = "windows")] { + // log::trace!("Sent a message {_win_msg:?}"); + log::warn!("Sending a message isn't implemented yet"); + } + #[cfg(not(target_os = "windows"))] + log::warn!( + "{} or {} was used, but this only works on Windows.", + SEND_WMSG_SYNC,SEND_WMSG_SYNC_A + ); + } + CustomAction::WinPostMessage(_win_msg) => { + #[cfg(target_os = "windows")] { + log::trace!("Posted a message {_win_msg:?}"); + use windows_sys::Win32::UI::WindowsAndMessaging::HWND_BROADCAST; + use windows_sys::Win32::UI::WindowsAndMessaging::{RegisterWindowMessageW,PostMessageW,}; + use windows_sys::core::PCWSTR; + use colored::*; + use widestring::{U16Str,WideChar,u16cstr, + U16CString,U16CStr, // 0 U16/U32-CString wide version of the standard CString type + Utf16Str , // no0 UTF-16 encoded, growable owned string + }; + log::debug!("Action PostMessage (async)"); + if let Ok(val_w16cs) = U16CString::from_str(_win_msg.msg_sid.clone()) { + let msg_txt:PCWSTR = val_w16cs.into_raw(); + let msg_id = unsafe{RegisterWindowMessageW(msg_txt)}; + let ret = unsafe{PostMessageW(HWND_BROADCAST, msg_id, _win_msg.argu, _win_msg.argi)}; + if ret == 0 {log::error!("Failed to post a message: {_win_msg:?}, OS error# {ret}");} + // TODO: call GetLastError to get error content + } else {log::error!("Failed to parse {} into a Windows string",_win_msg.msg_sid.to_string().blue());} + } + #[cfg(not(target_os = "windows"))] + log::warn!( + "{} or {} was used, but this only works on Windows.", + SEND_WMSG_ASYNC,SEND_WMSG_ASYNC_A + ); + } CustomAction::FakeKey { coord, action } => { let (x, y) = (coord.x, coord.y); log::debug!( From 070264091f7d14f1add254cd8e1c30e0929c9322 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:06:07 +0700 Subject: [PATCH 10/18] cargo fmt and clippy --- parser/src/cfg/tests.rs | 1 - parser/src/cfg/windows.rs | 181 +++++++++++++++++++++++++++--------- parser/src/custom_action.rs | 2 +- src/kanata/mod.rs | 69 +++++++++----- 4 files changed, 181 insertions(+), 72 deletions(-) diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 7d4cb7ea7..4390f1a43 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -1955,7 +1955,6 @@ fn disallow_whitespace_in_tooltip_size() { parse_cfg(source).map(|_| ()).expect_err("fails"); } - #[test] fn win_message_ok() { let source = r#" diff --git a/parser/src/cfg/windows.rs b/parser/src/cfg/windows.rs index 5a3d84efb..dbdcb02dd 100644 --- a/parser/src/cfg/windows.rs +++ b/parser/src/cfg/windows.rs @@ -1,48 +1,70 @@ use crate::cfg::error::*; use crate::cfg::custom; +use crate::cfg::str_ext::TrimAtomQuotes; use crate::cfg::KanataAction; use crate::cfg::ParseError; use crate::cfg::ParserState; use crate::cfg::SExpr; -use crate::cfg::str_ext::TrimAtomQuotes; use crate::custom_action::CustomAction; use std::ops::Deref; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct WinMsgSid(String); impl Default for WinMsgSid { - fn default() -> Self {Self("kanata_4117d2917ccb4678a7a8c71a5ff898ed".to_string())} //TODO: replace with str + fn default() -> Self { + Self("kanata_4117d2917ccb4678a7a8c71a5ff898ed".to_string()) + } //TODO: replace with str +} +impl From for String { + fn from(val: WinMsgSid) -> Self { + val.0 + } +} +impl Deref for WinMsgSid { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } } -impl Into for WinMsgSid { - fn into(self) -> String {self.0} } -impl Deref for WinMsgSid {type Target = String; fn deref(&self) -> &Self::Target {&self.0}} impl AsRef for WinMsgSid - where T: ?Sized, ::Target: AsRef, { +where + T: ?Sized, + ::Target: AsRef, +{ fn as_ref(&self) -> &T { self.deref().as_ref() } } impl From for WinMsgSid { - fn from(s: String) -> Self {WinMsgSid(s )} } + fn from(s: String) -> Self { + WinMsgSid(s) + } +} impl From<&str> for WinMsgSid { - fn from(s: &str ) -> Self {WinMsgSid(s.to_string())} } + fn from(s: &str) -> Self { + WinMsgSid(s.to_string()) + } +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct WinMsgTarget { win_class: String, - win_name : String, + win_name: String, } #[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] pub struct WinMsg { - pub win_tgt : WinMsgTarget, - pub msg_sid : WinMsgSid, - pub argu : usize, - pub argi : isize, + pub win_tgt: WinMsgTarget, + pub msg_sid: WinMsgSid, + pub argu: usize, + pub argi: isize, } impl Default for WinMsgTarget { - fn default() -> Self { Self { - win_class : "AutoHotkey".to_string(), //TODO: replace with str - win_name : "\\AutoHotkey.ahk".to_string(), } } + fn default() -> Self { + Self { + win_class: "AutoHotkey".to_string(), //TODO: replace with str + win_name: "\\AutoHotkey.ahk".to_string(), + } + } } use colored::*; @@ -50,54 +72,123 @@ use num_format::{Locale, ToFormattedString}; pub fn to_win_msg(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result { const ERR_MSG: &str = "expects at most 5 parameters: 2 message numeric arguments, target window title, shared message string id, target window class"; let cmd_name = cmd_name.blue().bold(); - if ac_params.len() > 5 {bail!("{} {}",cmd_name,ERR_MSG);} - let mut win_tgt:WinMsgTarget = Default::default(); + if ac_params.len() > 5 { + bail!("{} {}", cmd_name, ERR_MSG); + } + let mut win_tgt: WinMsgTarget = Default::default(); let mut msg_sid = Default::default(); - let mut argu = Default::default(); - let mut argi = Default::default(); - if ac_params.len() > 0 { let arg = &ac_params[0]; + let mut argu = Default::default(); + let mut argi = Default::default(); + if !ac_params.is_empty() { + let arg = &ac_params[0]; if let Some(a) = arg.atom(s.vars()) { argu = match str::parse::(a.trim_atom_quotes()) { Ok(argu) => argu, - Err(_) => bail_expr!(&arg, "invalid numeric argument, expected {}–{}. {} {}", - usize::MIN.to_formatted_string(&Locale::en).blue(),usize::MAX.to_formatted_string(&Locale::en).blue(),cmd_name,ERR_MSG), + Err(_) => bail_expr!( + &arg, + "invalid numeric argument, expected {}–{}. {} {}", + usize::MIN.to_formatted_string(&Locale::en).blue(), + usize::MAX.to_formatted_string(&Locale::en).blue(), + cmd_name, + ERR_MSG + ), } - } else {bail!("{ERR_MSG}");} + } else { + bail!("{ERR_MSG}"); + } } - if ac_params.len() > 1 { let arg = &ac_params[1]; + if ac_params.len() > 1 { + let arg = &ac_params[1]; if let Some(a) = arg.atom(s.vars()) { argi = match str::parse::(a.trim_atom_quotes()) { Ok(argi) => argi, - Err(_) => bail_expr!(&arg, "invalid numeric argument, expected {}–{}. {} {}", - isize::MIN.to_formatted_string(&Locale::en).blue(),isize::MAX.to_formatted_string(&Locale::en).blue(),cmd_name,ERR_MSG), + Err(_) => bail_expr!( + &arg, + "invalid numeric argument, expected {}–{}. {} {}", + isize::MIN.to_formatted_string(&Locale::en).blue(), + isize::MAX.to_formatted_string(&Locale::en).blue(), + cmd_name, + ERR_MSG + ), } - } else {bail!("{ERR_MSG}");} + } else { + bail!("{ERR_MSG}"); + } } - if ac_params.len() > 2 { let arg = &ac_params[2]; - if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); - if ! a.is_empty() {win_tgt.win_name = a.to_string();} - } else {bail_expr!(&arg, "invalid target window {}. {} {}","file name".blue(),cmd_name,ERR_MSG)} + if ac_params.len() > 2 { + let arg = &ac_params[2]; + if let Some(a) = arg.atom(s.vars()) { + let a = a.trim_atom_quotes(); + if !a.is_empty() { + win_tgt.win_name = a.to_string(); + } + } else { + bail_expr!( + &arg, + "invalid target window {}. {} {}", + "file name".blue(), + cmd_name, + ERR_MSG + ) + } } - if ac_params.len() > 3 { let arg = &ac_params[3]; - if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); - if ! a.is_empty() {msg_sid = a.into();} - } else {bail_expr!(&arg, "invalid message shared {}. {} {}","string id".blue(),cmd_name,ERR_MSG)} + if ac_params.len() > 3 { + let arg = &ac_params[3]; + if let Some(a) = arg.atom(s.vars()) { + let a = a.trim_atom_quotes(); + if !a.is_empty() { + msg_sid = a.into(); + } + } else { + bail_expr!( + &arg, + "invalid message shared {}. {} {}", + "string id".blue(), + cmd_name, + ERR_MSG + ) + } } - if ac_params.len() > 4 { let arg = &ac_params[4]; - if let Some(a) = arg.atom(s.vars()) {let a = a.trim_atom_quotes(); - if ! a.is_empty() {win_tgt.win_class = a.to_string();} - } else {bail_expr!(&arg, "invalid target window {}. {} {}","class".blue(),cmd_name,ERR_MSG)} + if ac_params.len() > 4 { + let arg = &ac_params[4]; + if let Some(a) = arg.atom(s.vars()) { + let a = a.trim_atom_quotes(); + if !a.is_empty() { + win_tgt.win_class = a.to_string(); + } + } else { + bail_expr!( + &arg, + "invalid target window {}. {} {}", + "class".blue(), + cmd_name, + ERR_MSG + ) + } } - Ok(WinMsg{win_tgt,msg_sid,argu,argi}) + Ok(WinMsg { + win_tgt, + msg_sid, + argu, + argi, + }) } -pub fn win_send_message(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result<&'static KanataAction> { +pub fn win_send_message( + ac_params: &[SExpr], + s: &ParserState, + cmd_name: &str, +) -> Result<&'static KanataAction> { let win_msg = to_win_msg(ac_params, s, cmd_name)?; - log::trace!("win_msg = {:?}",win_msg); + log::trace!("win_msg = {:?}", win_msg); custom(CustomAction::WinSendMessage(win_msg), &s.a) } -pub fn win_post_message(ac_params: &[SExpr], s: &ParserState, cmd_name: &str) -> Result<&'static KanataAction> { +pub fn win_post_message( + ac_params: &[SExpr], + s: &ParserState, + cmd_name: &str, +) -> Result<&'static KanataAction> { let win_msg = to_win_msg(ac_params, s, cmd_name)?; - log::trace!("win_msg = {:?}",win_msg); + log::trace!("win_msg = {:?}", win_msg); custom(CustomAction::WinPostMessage(win_msg), &s.a) } diff --git a/parser/src/custom_action.rs b/parser/src/custom_action.rs index 7b008bec5..c8eb2be57 100644 --- a/parser/src/custom_action.rs +++ b/parser/src/custom_action.rs @@ -3,7 +3,7 @@ //! When adding a new custom action, the macro section of the config.adoc documentation may need to //! be updated, to include the new action to the documented list of supported actions in macro. -use crate::cfg::{WinMsg}; +use crate::cfg::WinMsg; use anyhow::{anyhow, Result}; use core::fmt; use kanata_keyberon::key_code::KeyCode; diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index b0ced7f42..a877489f9 100755 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -51,8 +51,6 @@ use cmd::*; mod windows; #[cfg(target_os = "windows")] pub use windows::*; -#[cfg(all(target_os = "windows"))] -use windows_sys::Win32::Foundation::{HWND,WPARAM,LPARAM}; #[cfg(target_os = "linux")] mod linux; @@ -1326,40 +1324,61 @@ impl Kanata { ); } CustomAction::WinSendMessage(_win_msg) => { - #[cfg(target_os = "windows")] { - // log::trace!("Sent a message {_win_msg:?}"); - log::warn!("Sending a message isn't implemented yet"); + #[cfg(target_os = "windows")] + { + // log::trace!("Sent a message {_win_msg:?}"); + log::warn!("Sending a message isn't implemented yet"); } #[cfg(not(target_os = "windows"))] log::warn!( "{} or {} was used, but this only works on Windows.", - SEND_WMSG_SYNC,SEND_WMSG_SYNC_A + SEND_WMSG_SYNC, + SEND_WMSG_SYNC_A ); } CustomAction::WinPostMessage(_win_msg) => { - #[cfg(target_os = "windows")] { - log::trace!("Posted a message {_win_msg:?}"); - use windows_sys::Win32::UI::WindowsAndMessaging::HWND_BROADCAST; - use windows_sys::Win32::UI::WindowsAndMessaging::{RegisterWindowMessageW,PostMessageW,}; - use windows_sys::core::PCWSTR; - use colored::*; - use widestring::{U16Str,WideChar,u16cstr, - U16CString,U16CStr, // 0 U16/U32-CString wide version of the standard CString type - Utf16Str , // no0 UTF-16 encoded, growable owned string - }; - log::debug!("Action PostMessage (async)"); - if let Ok(val_w16cs) = U16CString::from_str(_win_msg.msg_sid.clone()) { - let msg_txt:PCWSTR = val_w16cs.into_raw(); - let msg_id = unsafe{RegisterWindowMessageW(msg_txt)}; - let ret = unsafe{PostMessageW(HWND_BROADCAST, msg_id, _win_msg.argu, _win_msg.argi)}; - if ret == 0 {log::error!("Failed to post a message: {_win_msg:?}, OS error# {ret}");} - // TODO: call GetLastError to get error content - } else {log::error!("Failed to parse {} into a Windows string",_win_msg.msg_sid.to_string().blue());} + #[cfg(target_os = "windows")] + { + log::trace!("Posted a message {_win_msg:?}"); + use colored::*; + use widestring::{ + U16CString, + }; + use windows_sys::core::PCWSTR; + use windows_sys::Win32::UI::WindowsAndMessaging::HWND_BROADCAST; + use windows_sys::Win32::UI::WindowsAndMessaging::{ + PostMessageW, RegisterWindowMessageW, + }; + log::debug!("Action PostMessage (async)"); + if let Ok(val_w16cs) = + U16CString::from_str(_win_msg.msg_sid.clone()) + { + let msg_txt: PCWSTR = val_w16cs.into_raw(); + let msg_id = unsafe { RegisterWindowMessageW(msg_txt) }; + let ret = unsafe { + PostMessageW( + HWND_BROADCAST, + msg_id, + _win_msg.argu, + _win_msg.argi, + ) + }; + if ret == 0 { + log::error!("Failed to post a message: {_win_msg:?}, OS error# {ret}"); + } + // TODO: call GetLastError to get error content + } else { + log::error!( + "Failed to parse {} into a Windows string", + _win_msg.msg_sid.to_string().blue() + ); + } } #[cfg(not(target_os = "windows"))] log::warn!( "{} or {} was used, but this only works on Windows.", - SEND_WMSG_ASYNC,SEND_WMSG_ASYNC_A + SEND_WMSG_ASYNC, + SEND_WMSG_ASYNC_A ); } CustomAction::FakeKey { coord, action } => { From 538930eeb7fa23ab2fa1a73ffe04db3ae76485d5 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:34:49 +0700 Subject: [PATCH 11/18] dep: update Windows-sys feature use --- Cargo.toml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 282ca76d8..8e312c19c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,23 +85,10 @@ winapi = { version = "0.3.9", features = [ "mmsystem", ] } windows-sys = { version = "0.52.0", features = [ - "Win32_Devices_DeviceAndDriverInstallation", - "Win32_Devices_Usb", "Win32_Foundation", - "Win32_Graphics_Gdi", - "Win32_Security", - "Win32_System_Diagnostics_Debug", - "Win32_System_Registry", - "Win32_System_Threading", - "Win32_UI_Controls", - "Win32_UI_Shell", - "Win32_UI_HiDpi", "Win32_UI_WindowsAndMessaging", - "Win32_System_SystemInformation", - "Wdk", - "Wdk_System", - "Wdk_System_SystemServices", -], optional=true } +]} + widestring = "1.1.0" native-windows-gui = { version = "1.0.13", default_features = false} regex = { version = "1.10.4", optional = true } @@ -132,7 +119,20 @@ wasm = [ "instant/wasm-bindgen" ] gui = ["win_manifest","kanata-parser/gui", "win_sendinput_send_scancodes","win_llhook_read_scancodes", "muldiv","strip-ansi-escapes","open", - "dep:windows-sys", + "windows-sys/Win32_Devices_DeviceAndDriverInstallation", + "windows-sys/Win32_Devices_Usb", + "windows-sys/Win32_Graphics_Gdi", + "windows-sys/Win32_Security", + "windows-sys/Win32_System_Diagnostics_Debug", + "windows-sys/Win32_System_Registry", + "windows-sys/Win32_System_Threading", + "windows-sys/Win32_UI_Controls", + "windows-sys/Win32_UI_Shell", + "windows-sys/Win32_UI_HiDpi", + "windows-sys/Win32_System_SystemInformation", + "windows-sys/Wdk", + "windows-sys/Wdk_System", + "windows-sys/Wdk_System_SystemServices", "winapi/processthreadsapi", "native-windows-gui/tray-notification","native-windows-gui/message-window","native-windows-gui/menu","native-windows-gui/cursor","native-windows-gui/high-dpi","native-windows-gui/embed-resource","native-windows-gui/image-decoder","native-windows-gui/notice","native-windows-gui/animation-timer", ] From 5ddc311175e0d0ce3e65d596e50101bb732d9d51 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Mon, 27 May 2024 22:57:56 +0700 Subject: [PATCH 12/18] dep: update lock file --- Cargo.lock | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index b6c990905..84e40cd79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,6 +86,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -229,6 +235,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -575,6 +591,7 @@ version = "1.7.0-prerelease" dependencies = [ "anyhow", "clap", + "colored", "core-graphics", "dirs", "embed-resource", @@ -606,6 +623,7 @@ dependencies = [ "simplelog", "strip-ansi-escapes", "time", + "widestring", "winapi", "windows-sys 0.52.0", ] @@ -648,10 +666,12 @@ version = "0.161.0" dependencies = [ "anyhow", "bytemuck", + "colored", "itertools", "kanata-keyberon", "log", "miette", + "num-format", "once_cell", "parking_lot", "patricia_tree", @@ -885,6 +905,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + [[package]] name = "num_enum" version = "0.6.1" From 02fcb3bb8d52bfa7ec457c7227ab4546dd6f267e Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:47:15 +0700 Subject: [PATCH 13/18] cargo fmt --- src/kanata/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index a877489f9..9a480ea22 100755 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -1341,9 +1341,7 @@ impl Kanata { { log::trace!("Posted a message {_win_msg:?}"); use colored::*; - use widestring::{ - U16CString, - }; + use widestring::U16CString; use windows_sys::core::PCWSTR; use windows_sys::Win32::UI::WindowsAndMessaging::HWND_BROADCAST; use windows_sys::Win32::UI::WindowsAndMessaging::{ From da3b6e0c70f5937c54aaf607d3c7a01cf6315053 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:49:29 +0700 Subject: [PATCH 14/18] exclude windows messages from mac/linux parsers --- parser/src/cfg/mod.rs | 4 ++++ parser/src/custom_action.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index a378d2069..f70208fe9 100755 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -1693,9 +1693,13 @@ fn parse_action_list(ac: &[SExpr], s: &ParserState) -> Result<&'static KanataAct CMD => parse_cmd(&ac[1..], s, CmdType::Standard), CMD_OUTPUT_KEYS => parse_cmd(&ac[1..], s, CmdType::OutputKeys), PUSH_MESSAGE => parse_push_message(&ac[1..], s), + #[cfg(any(target_os = "windows", target_os = "unknown"))] SEND_WMSG_SYNC => win_send_message(&ac[1..], s, SEND_WMSG_SYNC), + #[cfg(any(target_os = "windows", target_os = "unknown"))] SEND_WMSG_SYNC_A => win_send_message(&ac[1..], s, SEND_WMSG_SYNC_A), + #[cfg(any(target_os = "windows", target_os = "unknown"))] SEND_WMSG_ASYNC => win_post_message(&ac[1..], s, SEND_WMSG_ASYNC), + #[cfg(any(target_os = "windows", target_os = "unknown"))] SEND_WMSG_ASYNC_A => win_post_message(&ac[1..], s, SEND_WMSG_ASYNC_A), FORK => parse_fork(&ac[1..], s), CAPS_WORD | CAPS_WORD_A => { diff --git a/parser/src/custom_action.rs b/parser/src/custom_action.rs index c8eb2be57..358371d81 100644 --- a/parser/src/custom_action.rs +++ b/parser/src/custom_action.rs @@ -3,6 +3,7 @@ //! When adding a new custom action, the macro section of the config.adoc documentation may need to //! be updated, to include the new action to the documented list of supported actions in macro. +#[cfg(any(target_os = "windows", target_os = "unknown"))] use crate::cfg::WinMsg; use anyhow::{anyhow, Result}; use core::fmt; @@ -15,7 +16,9 @@ pub enum CustomAction { Cmd(Vec), CmdOutputKeys(Vec), PushMessage(Vec), + #[cfg(any(target_os = "windows", target_os = "unknown"))] WinSendMessage(WinMsg), + #[cfg(any(target_os = "windows", target_os = "unknown"))] WinPostMessage(WinMsg), Unicode(char), Mouse(Btn), From 4d4f9425be41ebb80431738413d722458f8ebabb Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 02:57:48 +0700 Subject: [PATCH 15/18] add dummy WinMsg types outside of Windows --- parser/src/cfg/linux.rs | 2 ++ parser/src/cfg/macos.rs | 2 ++ parser/src/cfg/mod.rs | 8 ++++++++ parser/src/custom_action.rs | 3 --- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 parser/src/cfg/linux.rs create mode 100644 parser/src/cfg/macos.rs diff --git a/parser/src/cfg/linux.rs b/parser/src/cfg/linux.rs new file mode 100644 index 000000000..5e0740386 --- /dev/null +++ b/parser/src/cfg/linux.rs @@ -0,0 +1,2 @@ +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] +pub struct WinMsg {} diff --git a/parser/src/cfg/macos.rs b/parser/src/cfg/macos.rs new file mode 100644 index 000000000..5e0740386 --- /dev/null +++ b/parser/src/cfg/macos.rs @@ -0,0 +1,2 @@ +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] +pub struct WinMsg {} diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index f70208fe9..f9bb7b523 100755 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -2311,6 +2311,14 @@ fn parse_push_message(ac_params: &[SExpr], s: &ParserState) -> Result<&'static K pub mod windows; #[cfg(any(target_os = "windows", target_os = "unknown"))] pub use windows::*; +#[cfg(any(target_os = "linux"))] +pub mod linux; +#[cfg(any(target_os = "linux"))] +pub use linux::*; +#[cfg(any(target_os = "macos"))] +pub mod macos; +#[cfg(any(target_os = "macos"))] +pub use macos::*; fn to_simple_expr(params: &[SExpr], s: &ParserState) -> Vec { let mut result: Vec = Vec::new(); diff --git a/parser/src/custom_action.rs b/parser/src/custom_action.rs index 358371d81..c8eb2be57 100644 --- a/parser/src/custom_action.rs +++ b/parser/src/custom_action.rs @@ -3,7 +3,6 @@ //! When adding a new custom action, the macro section of the config.adoc documentation may need to //! be updated, to include the new action to the documented list of supported actions in macro. -#[cfg(any(target_os = "windows", target_os = "unknown"))] use crate::cfg::WinMsg; use anyhow::{anyhow, Result}; use core::fmt; @@ -16,9 +15,7 @@ pub enum CustomAction { Cmd(Vec), CmdOutputKeys(Vec), PushMessage(Vec), - #[cfg(any(target_os = "windows", target_os = "unknown"))] WinSendMessage(WinMsg), - #[cfg(any(target_os = "windows", target_os = "unknown"))] WinPostMessage(WinMsg), Unicode(char), Mouse(Btn), From c3b7e3d0d148b9be1e90ac3cdd790528cd7281b9 Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 03:01:44 +0700 Subject: [PATCH 16/18] test test cfg --- parser/src/cfg/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 4390f1a43..5e3f8a1f1 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -1955,6 +1955,7 @@ fn disallow_whitespace_in_tooltip_size() { parse_cfg(source).map(|_| ()).expect_err("fails"); } +#[cfg(any(target_os = "windows", target_os = "unknown"))] #[test] fn win_message_ok() { let source = r#" @@ -1972,6 +1973,7 @@ fn win_message_ok() { .expect("parse succeeds"); } +#[cfg(any(target_os = "windows", target_os = "unknown"))] #[test] fn win_message_wrong_number_value() { let source = " @@ -1982,6 +1984,7 @@ fn win_message_wrong_number_value() { parse_cfg(source).map(|_| ()).expect_err("fails"); } +#[cfg(any(target_os = "windows", target_os = "unknown"))] #[test] fn win_message_wrong_number_type() { let source = r#" @@ -1992,6 +1995,7 @@ fn win_message_wrong_number_type() { parse_cfg(source).map(|_| ()).expect_err("fails"); } +#[cfg(any(target_os = "windows", target_os = "unknown"))] #[test] fn win_message_too_many_args() { let source = r#" From 447225609c99672a3b4a83648fd7760a7c84df6b Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 03:05:09 +0700 Subject: [PATCH 17/18] clippy --- parser/src/cfg/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index f9bb7b523..c949ccdf3 100755 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -2311,13 +2311,13 @@ fn parse_push_message(ac_params: &[SExpr], s: &ParserState) -> Result<&'static K pub mod windows; #[cfg(any(target_os = "windows", target_os = "unknown"))] pub use windows::*; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] pub mod linux; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] pub use linux::*; -#[cfg(any(target_os = "macos"))] +#[cfg(target_os = "macos")] pub mod macos; -#[cfg(any(target_os = "macos"))] +#[cfg(target_os = "macos")] pub use macos::*; fn to_simple_expr(params: &[SExpr], s: &ParserState) -> Vec { From cdfc2714af7fbbe6c03490d7303f6cbf85ea818a Mon Sep 17 00:00:00 2001 From: eugenesvk Date: Tue, 28 May 2024 23:05:09 +0700 Subject: [PATCH 18/18] doc: fix a typo --- docs/config.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.adoc b/docs/config.adoc index 536cb9b10..78499a67a 100644 --- a/docs/config.adoc +++ b/docs/config.adoc @@ -2535,7 +2535,7 @@ Parameters are order sensitive, so if you want to skip the 3rd title string, set See https://github.com/jtroo/kanata/blob/main/cfg_samples/win-msg/win-msg.kbd[example config] for more details. Requires https://www.autohotkey.com/download/[AutoHotkey v2] and a running -https://github.com/jtroo/kanata/blob/main/cfg_samples/win-msg/insert-date.kbd[example script]. +https://github.com/jtroo/kanata/blob/main/cfg_samples/win-msg/insert-date.ahk[example script]. See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagew[PostMessageW] for more API details.