From a450ee18faf34929d05cf9603a6f0ae0250086f4 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 31 Jan 2021 18:09:03 +0100 Subject: [PATCH] First implementation of x11 source --- Cargo.lock | 184 ++++++++------- espanso-detect/Cargo.toml | 2 +- espanso-detect/build.rs | 10 +- espanso-detect/src/evdev/README.md | 2 + espanso-detect/src/lib.rs | 3 + espanso-detect/src/win32/mod.rs | 4 +- espanso-detect/src/x11/mod.rs | 359 +++++++++++++++++++++++++++++ espanso-detect/src/x11/native.cpp | 345 +++++++++++++++++++++++++++ espanso-detect/src/x11/native.h | 66 ++++++ espanso-ui/build.rs | 10 +- espanso/src/main.rs | 53 +++-- 11 files changed, 910 insertions(+), 128 deletions(-) create mode 100644 espanso-detect/src/evdev/README.md create mode 100644 espanso-detect/src/x11/mod.rs create mode 100644 espanso-detect/src/x11/native.cpp create mode 100644 espanso-detect/src/x11/native.h diff --git a/Cargo.lock b/Cargo.lock index 6ec0232..3f3b53d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,317 +4,315 @@ name = "anyhow" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "libc 0.2.84 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time", + "winapi", ] [[package]] name = "enum-as-inner" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ - "heck 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "espanso" version = "1.0.0" dependencies = [ - "espanso-detect 0.1.0", - "espanso-ui 0.1.0", - "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "simplelog 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "espanso-detect", + "espanso-ui", + "maplit", + "simplelog", ] [[package]] name = "espanso-detect" version = "0.1.0" dependencies = [ - "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "enum-as-inner 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "widestring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "enum-as-inner", + "lazycell", + "log", + "widestring", ] [[package]] name = "espanso-ui" version = "0.1.0" dependencies = [ - "anyhow 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.123 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", - "widestring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "cc", + "lazycell", + "log", + "serde", + "serde_json", + "thiserror", + "widestring", ] [[package]] name = "heck" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ - "unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-traits" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" dependencies = [ - "serde_derive 1.0.123 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ - "itoa 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.123 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "simplelog" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc0ffd69814a9b251d43afcabf96dad1b29f5028378056257be9e3fecc9f720" dependencies = [ - "chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "log", + "termcolor", ] [[package]] name = "syn" version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "termcolor" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "thiserror" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ - "thiserror-impl 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ - "libc 0.2.84 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "wasi", + "winapi", ] [[package]] name = "unicode-segmentation" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "widestring" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum anyhow 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" -"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -"checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" -"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -"checksum chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -"checksum enum-as-inner 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" -"checksum heck 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" -"checksum itoa 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" -"checksum lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -"checksum libc 0.2.84 (registry+https://github.com/rust-lang/crates.io-index)" = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" -"checksum log 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -"checksum num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -"checksum num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -"checksum proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -"checksum quote 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum serde 1.0.123 (registry+https://github.com/rust-lang/crates.io-index)" = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" -"checksum serde_derive 1.0.123 (registry+https://github.com/rust-lang/crates.io-index)" = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" -"checksum serde_json 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)" = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" -"checksum simplelog 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bc0ffd69814a9b251d43afcabf96dad1b29f5028378056257be9e3fecc9f720" -"checksum syn 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" -"checksum termcolor 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -"checksum thiserror 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" -"checksum thiserror-impl 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" -"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -"checksum unicode-segmentation 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" -"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" -"checksum widestring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" -"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/espanso-detect/Cargo.toml b/espanso-detect/Cargo.toml index 52cee9b..3a1e5d0 100644 --- a/espanso-detect/Cargo.toml +++ b/espanso-detect/Cargo.toml @@ -7,10 +7,10 @@ build="build.rs" [dependencies] log = "0.4.14" +lazycell = "1.3.0" [target.'cfg(windows)'.dependencies] widestring = "0.4.3" -lazycell = "1.3.0" [build-dependencies] cc = "1.0.66" diff --git a/espanso-detect/build.rs b/espanso-detect/build.rs index 9f1c2a2..291ab70 100644 --- a/espanso-detect/build.rs +++ b/espanso-detect/build.rs @@ -35,11 +35,17 @@ fn cc_config() { #[cfg(target_os = "linux")] fn cc_config() { + println!("cargo:rerun-if-changed=src/x11/native.cpp"); + println!("cargo:rerun-if-changed=src/x11/native.h"); + cc::Build::new() + .cpp(true) + .include("src/x11/native.h") + .file("src/x11/native.cpp") + .compile("espansodetect"); println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/"); - println!("cargo:rustc-link-lib=static=linuxbridge"); + println!("cargo:rustc-link-lib=static=espansodetect"); println!("cargo:rustc-link-lib=dylib=X11"); println!("cargo:rustc-link-lib=dylib=Xtst"); - println!("cargo:rustc-link-lib=dylib=xdo"); } #[cfg(target_os = "macos")] diff --git a/espanso-detect/src/evdev/README.md b/espanso-detect/src/evdev/README.md new file mode 100644 index 0000000..1dc0077 --- /dev/null +++ b/espanso-detect/src/evdev/README.md @@ -0,0 +1,2 @@ +This is a great starting point for wayland support: +https://github.com/xkbcommon/libxkbcommon/blob/master/tools/interactive-evdev.c \ No newline at end of file diff --git a/espanso-detect/src/lib.rs b/espanso-detect/src/lib.rs index 5b23648..7f6fa97 100644 --- a/espanso-detect/src/lib.rs +++ b/espanso-detect/src/lib.rs @@ -21,3 +21,6 @@ pub mod event; #[cfg(target_os = "windows")] pub mod win32; + +#[cfg(target_os = "linux")] +pub mod x11; \ No newline at end of file diff --git a/espanso-detect/src/win32/mod.rs b/espanso-detect/src/win32/mod.rs index c20cf83..6d1ee33 100644 --- a/espanso-detect/src/win32/mod.rs +++ b/espanso-detect/src/win32/mod.rs @@ -91,7 +91,7 @@ impl Win32Source { let handle = unsafe { detect_initialize(self as *const Win32Source) }; if handle.is_null() { - panic!("Unable to initialize Win32EventLoop"); + panic!("Unable to initialize Win32Source"); } self.handle = handle; @@ -135,7 +135,7 @@ impl Drop for Win32Source { let result = unsafe { detect_destroy(self.handle) }; if result != 0 { - error!("Win32EventLoop destruction returned non-zero code"); + error!("Win32Source destruction returned non-zero code"); } } } diff --git a/espanso-detect/src/x11/mod.rs b/espanso-detect/src/x11/mod.rs new file mode 100644 index 0000000..9971ded --- /dev/null +++ b/espanso-detect/src/x11/mod.rs @@ -0,0 +1,359 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +use std::{ + ffi::{c_void, CStr}, +}; + +use lazycell::LazyCell; +use log::{error, trace, warn}; + +use crate::event::Status::*; +use crate::event::Variant::*; +use crate::event::{InputEvent, Key, KeyboardEvent, Variant}; +use crate::event::{Key::*, MouseButton, MouseEvent}; + +const INPUT_EVENT_TYPE_KEYBOARD: i32 = 1; +const INPUT_EVENT_TYPE_MOUSE: i32 = 2; + +const INPUT_STATUS_PRESSED: i32 = 1; +const INPUT_STATUS_RELEASED: i32 = 2; + +const INPUT_MOUSE_LEFT_BUTTON: i32 = 1; +const INPUT_MOUSE_RIGHT_BUTTON: i32 = 3; +const INPUT_MOUSE_MIDDLE_BUTTON: i32 = 2; +const INPUT_MOUSE_BUTTON_1: i32 = 9; +const INPUT_MOUSE_BUTTON_2: i32 = 8; + +// Take a look at the native.h header file for an explanation of the fields +#[repr(C)] +pub struct RawInputEvent { + pub event_type: i32, + + pub buffer: [u8; 24], + pub buffer_len: i32, + + pub key_sym: i32, + pub key_code: i32, + pub status: i32, +} + +#[allow(improper_ctypes)] +#[link(name = "espansodetect", kind = "static")] +extern "C" { + pub fn detect_check_x11() -> i32; + + pub fn detect_initialize(_self: *const X11Source, error_code: *mut i32) -> *mut c_void; + + pub fn detect_eventloop( + window: *const c_void, + event_callback: extern "C" fn(_self: *mut X11Source, event: RawInputEvent), + ) -> i32; + + pub fn detect_destroy(window: *const c_void) -> i32; +} + +pub type X11SourceCallback = Box; +pub struct X11Source { + handle: *mut c_void, + callback: LazyCell, +} + +#[allow(clippy::new_without_default)] +impl X11Source { + pub fn new() -> X11Source { + Self { + handle: std::ptr::null_mut(), + callback: LazyCell::new(), + } + } + + pub fn is_compatible() -> bool { + unsafe { detect_check_x11() != 0 } + } + + pub fn initialize(&mut self) { + let mut error_code = 0; + let handle = unsafe { detect_initialize(self as *const X11Source, &mut error_code) }; + + if handle.is_null() { + match error_code { + -1 => panic!("Unable to initialize X11Source, cannot open displays"), + -2 => panic!("Unable to initialize X11Source, X Record Extension is not installed"), + -3 => panic!("Unable to initialize X11Source, X Keyboard Extension is not installed"), + -4 => panic!("Unable to initialize X11Source, cannot initialize record range"), + -5 => panic!("Unable to initialize X11Source, cannot initialize XRecord context"), + -6 => panic!("Unable to initialize X11Source, cannot enable XRecord context"), + _ => panic!("Unable to initialize X11Source, unknown error"), + } + } + + self.handle = handle; + } + + pub fn eventloop(&self, event_callback: X11SourceCallback) { + if self.handle.is_null() { + panic!("Attempt to start X11Source eventloop without initialization"); + } + + if self.callback.fill(event_callback).is_err() { + panic!("Unable to set X11Source event callback"); + } + + extern "C" fn callback(_self: *mut X11Source, event: RawInputEvent) { + let event: Option = event.into(); + if let Some(callback) = unsafe { (*_self).callback.borrow() } { + if let Some(event) = event { + callback(event) + } else { + trace!("Unable to convert raw event to input event"); + } + } + } + + let error_code = unsafe { detect_eventloop(self.handle, callback) }; + + if error_code <= 0 { + panic!("X11Source eventloop returned a negative error code"); + } + } +} + +impl Drop for X11Source { + fn drop(&mut self) { + if self.handle.is_null() { + error!("X11Source destruction cannot be performed, handle is null"); + return; + } + + let result = unsafe { detect_destroy(self.handle) }; + + if result != 0 { + error!("X11Source destruction returned non-zero code"); + } + } +} + +impl From for Option { + fn from(raw: RawInputEvent) -> Option { + let status = match raw.status { + INPUT_STATUS_RELEASED => Released, + INPUT_STATUS_PRESSED => Pressed, + _ => Pressed, + }; + + match raw.event_type { + // Keyboard events + INPUT_EVENT_TYPE_KEYBOARD => { + let (key, variant) = key_sym_to_key(raw.key_sym); + let value = if raw.buffer_len > 0 { + let raw_string_result = + CStr::from_bytes_with_nul(&raw.buffer[..((raw.buffer_len + 1) as usize)]); + match raw_string_result { + Ok(c_string) => { + let string_result = c_string.to_str(); + match string_result { + Ok(value) => Some(value.to_string()), + Err(err) => { + warn!("char conversion error: {}", err); + None + } + } + } + Err(err) => { + warn!("Received malformed char: {}", err); + None + } + } + } else { + None + }; + + return Some(InputEvent::Keyboard(KeyboardEvent { + key, + value, + status, + variant, + })); + } + // Mouse events + INPUT_EVENT_TYPE_MOUSE => { + let button = raw_to_mouse_button(raw.key_code); + + if let Some(button) = button { + return Some(InputEvent::Mouse(MouseEvent { button, status })); + } + } + _ => {} + } + + None + } +} + +// Mappings from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values +// TODO: might need to add also the variants +fn key_sym_to_key(key_sym: i32) -> (Key, Option) { + match key_sym { + // Modifiers + 0xFFE9 => (Alt, Some(Left)), + 0xFFEA => (Alt, Some(Right)), + 0xFFE5 => (CapsLock, None), + 0xFFE3 => (Control, Some(Left)), + 0xFFE4 => (Control, Some(Right)), + 0xFFE7 | 0xFFEB => (Meta, Some(Left)), + 0xFFE8 | 0xFFEC => (Meta, Some(Right)), + 0xFF7F => (NumLock, None), + 0xFFE1 => (Shift, Some(Left)), + 0xFFE2 => (Shift, Some(Right)), + + // Whitespace + 0xFF0D => (Enter, None), + 0xFF09 => (Tab, None), + 0x20 => (Space, None), + + // Navigation + 0xFF54 => (ArrowDown, None), + 0xFF51 => (ArrowLeft, None), + 0xFF53 => (ArrowRight, None), + 0xFF52 => (ArrowUp, None), + 0xFF57 => (End, None), + 0xFF50 => (Home, None), + 0xFF56 => (PageDown, None), + 0xFF55 => (PageUp, None), + + // Editing keys + 0xFF08 => (Backspace, None), + + // Function keys + 0xFFBE => (F1, None), + 0xFFBF => (F2, None), + 0xFFC0 => (F3, None), + 0xFFC1 => (F4, None), + 0xFFC2 => (F5, None), + 0xFFC3 => (F6, None), + 0xFFC4 => (F7, None), + 0xFFC5 => (F8, None), + 0xFFC6 => (F9, None), + 0xFFC7 => (F10, None), + 0xFFC8 => (F11, None), + 0xFFC9 => (F12, None), + 0xFFCA => (F13, None), + 0xFFCB => (F14, None), + 0xFFCC => (F15, None), + 0xFFCD => (F16, None), + 0xFFCE => (F17, None), + 0xFFCF => (F18, None), + 0xFFD0 => (F19, None), + 0xFFD1 => (F20, None), + + // Other keys, includes the raw code provided by the operating system + _ => (Other(key_sym), None), + } +} + +fn raw_to_mouse_button(raw: i32) -> Option { + match raw { + INPUT_MOUSE_LEFT_BUTTON => Some(MouseButton::Left), + INPUT_MOUSE_RIGHT_BUTTON => Some(MouseButton::Right), + INPUT_MOUSE_MIDDLE_BUTTON => Some(MouseButton::Middle), + INPUT_MOUSE_BUTTON_1 => Some(MouseButton::Button1), + INPUT_MOUSE_BUTTON_2 => Some(MouseButton::Button2), + _ => None, + } +} + +#[cfg(test)] +mod tests { + use std::ffi::CString; + + use super::*; + + fn default_raw_input_event() -> RawInputEvent { + RawInputEvent { + event_type: INPUT_EVENT_TYPE_KEYBOARD, + buffer: [0; 24], + buffer_len: 0, + key_code: 0, + key_sym: 0, + status: INPUT_STATUS_PRESSED, + } + } + + #[test] + fn raw_to_input_event_keyboard_works_correctly() { + let c_string = CString::new("k".to_string()).unwrap(); + let mut buffer: [u8; 24] = [0; 24]; + buffer[..1].copy_from_slice(c_string.as_bytes()); + + let mut raw = default_raw_input_event(); + raw.buffer = buffer; + raw.buffer_len = 1; + raw.status = INPUT_STATUS_RELEASED; + raw.key_sym = 0x4B; + + let result: Option = raw.into(); + assert_eq!( + result.unwrap(), + InputEvent::Keyboard(KeyboardEvent { + key: Other(0x4B), + status: Released, + value: Some("k".to_string()), + variant: None, + }) + ); + } + + #[test] + fn raw_to_input_event_mouse_works_correctly() { + let mut raw = default_raw_input_event(); + raw.event_type = INPUT_EVENT_TYPE_MOUSE; + raw.status = INPUT_STATUS_RELEASED; + raw.key_code = INPUT_MOUSE_RIGHT_BUTTON; + + let result: Option = raw.into(); + assert_eq!( + result.unwrap(), + InputEvent::Mouse(MouseEvent { + status: Released, + button: MouseButton::Right, + }) + ); + } + + #[test] + fn raw_to_input_invalid_buffer() { + let buffer: [u8; 24] = [123; 24]; + + let mut raw = default_raw_input_event(); + raw.buffer = buffer; + raw.buffer_len = 5; + + let result: Option = raw.into(); + assert!(result.unwrap().into_keyboard().unwrap().value.is_none()); + } + + #[test] + fn raw_to_input_event_returns_none_when_missing_type() { + let mut raw = default_raw_input_event(); + raw.event_type = 0; + let result: Option = raw.into(); + assert!(result.is_none()); + } +} \ No newline at end of file diff --git a/espanso-detect/src/x11/native.cpp b/espanso-detect/src/x11/native.cpp new file mode 100644 index 0000000..e8436af --- /dev/null +++ b/espanso-detect/src/x11/native.cpp @@ -0,0 +1,345 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +/* +This code uses the X11 Record Extension to receive keyboard +events. Documentation of this library can be found here: +https://www.x.org/releases/X11R7.6/doc/libXtst/recordlib.html +We will refer to this extension as RE from now on. +*/ + +#include "native.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +This struct is needed to receive events from the RE. +The funny thing is: it's not defined there, it should though. +The only place this is mentioned is the libxnee library, +so check that out if you need a reference. +*/ +typedef union +{ + unsigned char type; + xEvent event; + xResourceReq req; + xGenericReply reply; + xError error; + xConnSetupPrefix setup; +} XRecordDatum; + +typedef struct +{ + // Connections to the X server, RE recommends 2 connections: + // one for recording control and one for reading the recorded data. + Display *data_disp; + Display *ctrl_disp; + XRecordRange *record_range; + XRecordContext x_context; + + void *rust_instance; + EventCallback event_callback; +} DetectContext; + +void detect_event_callback(XPointer, XRecordInterceptData *); +int detect_error_callback(Display *display, XErrorEvent *error); + +int32_t detect_check_x11() +{ + Display *check_disp = XOpenDisplay(NULL); + + if (!check_disp) + { + return 0; + } + + XCloseDisplay(check_disp); + return 1; +} + +void *detect_initialize(void *_rust_instance, int32_t *error_code) +{ + setlocale(LC_ALL, ""); + + std::unique_ptr context; + context.reset(new DetectContext()); + context->rust_instance = _rust_instance; + + // Open the connections to the X server. + // RE recommends to open 2 connections to the X server: + // one for the recording control and one to read the protocol + // data. + context->ctrl_disp = XOpenDisplay(NULL); + context->data_disp = XOpenDisplay(NULL); + + if (!context->ctrl_disp || !context->data_disp) + { // Display error + *error_code = -1; + return nullptr; + } + + // We must set the ctrl_disp to sync mode, or, when we the enable + // context in data_disp, there will be a fatal X error. + XSynchronize(context->ctrl_disp, True); + + int dummy; + + // Make sure the X RE is installed in this system. + if (!XRecordQueryVersion(context->ctrl_disp, &dummy, &dummy)) + { + *error_code = -2; + return nullptr; + } + + // Make sure the X Keyboard Extension is installed + if (!XkbQueryExtension(context->ctrl_disp, &dummy, &dummy, &dummy, &dummy, &dummy)) + { + *error_code = -3; + return nullptr; + } + + // Initialize the record range, that is the kind of events we want to track. + context->record_range = XRecordAllocRange(); + if (!context->record_range) + { + *error_code = -4; + return nullptr; + } + context->record_range->device_events.first = KeyPress; + context->record_range->device_events.last = ButtonRelease; + + // We want to get the keys from all clients + XRecordClientSpec client_spec; + client_spec = XRecordAllClients; + + // Initialize the context + context->x_context = XRecordCreateContext(context->ctrl_disp, 0, &client_spec, 1, &context->record_range, 1); + if (!context->x_context) + { + *error_code = -5; + return nullptr; + } + + if (!XRecordEnableContextAsync(context->data_disp, context->x_context, detect_event_callback, (XPointer)context.get())) + { + *error_code = -6; + return nullptr; + } + + // Setup a custom error handler + XSetErrorHandler(&detect_error_callback); + + // Note: We might never get a MappingNotify event if the + // modifier and keymap information was never cached in Xlib. + // The next line makes sure that this happens initially. + XKeysymToKeycode(context->ctrl_disp, XK_F1); + + // Release the unique_ptr to avoid freeing the context right-away. + return context.release(); +} + +int32_t detect_eventloop(void *_context, EventCallback _callback) +{ + DetectContext *context = (DetectContext *)_context; + if (!context) + { + return -1; + } + context->event_callback = _callback; + + bool running = true; + + int ctrl_fd = XConnectionNumber(context->ctrl_disp); + int data_fd = XConnectionNumber(context->data_disp); + + while (running) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(ctrl_fd, &fds); + FD_SET(data_fd, &fds); + timeval timeout; + timeout.tv_sec = 2; + timeout.tv_usec = 0; + select(max(ctrl_fd, data_fd) + 1, + &fds, NULL, NULL, &timeout); + + if (FD_ISSET(data_fd, &fds)) + { + XRecordProcessReplies(context->data_disp); + } + if (FD_ISSET(ctrl_fd, &fds)) + { + XEvent event; + XNextEvent(context->ctrl_disp, &event); + if (event.type == MappingNotify) + { + XMappingEvent *e = (XMappingEvent *)&event; + if (e->request == MappingKeyboard) + { + XRefreshKeyboardMapping(e); + } + } + } + } + + return 1; +} + +int32_t detect_destroy(void *_context) +{ + DetectContext *context = (DetectContext *)_context; + if (!context) + { + return -1; + } + + XRecordDisableContext(context->ctrl_disp, context->x_context); + XRecordFreeContext(context->ctrl_disp, context->x_context); + XFree(context->record_range); + XCloseDisplay(context->data_disp); + XCloseDisplay(context->ctrl_disp); + delete context; + + return 1; +} + +void detect_event_callback(XPointer p, XRecordInterceptData *hook) +{ + DetectContext *context = (DetectContext *)p; + if (!context) + { + return; + } + + // Make sure the event comes from the X11 server + if (hook->category != XRecordFromServer) + { + XRecordFreeData(hook); + return; + } + + // Cast the event payload to a XRecordDatum, needed later to access the fields + // This struct was hard to find and understand. Turn's out that all the + // required data are included in the "event" field of this structure. + // The funny thing is that it's not a XEvent as one might expect, + // but a xEvent, a very different beast defined in the Xproto.h header. + // I suggest you to look at that header if you want to understand where the + // upcoming field where taken from. + XRecordDatum *data = (XRecordDatum *)hook->data; + + int event_type = data->type; + int key_code = data->event.u.u.detail; + + // In order to convert the key_code into the corresponding string, + // we need to synthesize an artificial XKeyEvent, to feed later to the + // XLookupString function. + XKeyEvent raw_event; + raw_event.display = context->ctrl_disp; + raw_event.window = data->event.u.focus.window; + raw_event.root = XDefaultRootWindow(context->ctrl_disp); + raw_event.subwindow = None; + raw_event.time = data->event.u.keyButtonPointer.time; + raw_event.x = 1; + raw_event.y = 1; + raw_event.x_root = 1; + raw_event.y_root = 1; + raw_event.same_screen = True; + raw_event.keycode = key_code; + raw_event.state = data->event.u.keyButtonPointer.state; + raw_event.type = event_type; + + InputEvent event = {}; + + // Extract the corresponding chars. + int res = XLookupString(&raw_event, event.buffer, sizeof(event.buffer) - 1, NULL, NULL); + if (res > 0) + { + event.buffer_len = res; + } + else + { + memset(event.buffer, 0, sizeof(event.buffer)); + event.buffer_len = 0; + } + KeySym key_sym = XLookupKeysym(&raw_event, 0); + + switch (event_type) + { + case KeyPress: + { + event.event_type = INPUT_EVENT_TYPE_KEYBOARD; + event.key_code = key_code; + event.key_sym = key_sym; + event.status = INPUT_STATUS_PRESSED; + break; + } + case KeyRelease: + { + event.event_type = INPUT_EVENT_TYPE_KEYBOARD; + event.key_code = key_code; + event.key_sym = key_sym; + event.status = INPUT_STATUS_RELEASED; + break; + } + case ButtonPress: + { + event.event_type = INPUT_EVENT_TYPE_MOUSE; + event.key_code = key_code; + event.status = INPUT_STATUS_PRESSED; + break; + } + case ButtonRelease: + { + event.event_type = INPUT_EVENT_TYPE_MOUSE; + event.key_code = key_code; + event.status = INPUT_STATUS_RELEASED; + break; + } + } + + if (event.event_type != 0 && context->event_callback) + { + context->event_callback(context->rust_instance, event); + } + + XRecordFreeData(hook); +} + +int detect_error_callback(Display *, XErrorEvent *error) +{ + fprintf(stderr, "X11 Reported an error, code: %d, request_code: %d, minor_code: %d\n", error->error_code, error->request_code, error->minor_code); + return 0; +} \ No newline at end of file diff --git a/espanso-detect/src/x11/native.h b/espanso-detect/src/x11/native.h new file mode 100644 index 0000000..8e31b13 --- /dev/null +++ b/espanso-detect/src/x11/native.h @@ -0,0 +1,66 @@ +/* + * This file is part of espanso. + * + * Copyright (C) 2019-2021 Federico Terzi + * + * espanso is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * espanso is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with espanso. If not, see . + */ + +#ifndef ESPANSO_DETECT_H +#define ESPANSO_DETECT_H + +#include + +#define INPUT_EVENT_TYPE_KEYBOARD 1 +#define INPUT_EVENT_TYPE_MOUSE 2 + +#define INPUT_STATUS_PRESSED 1 +#define INPUT_STATUS_RELEASED 2 + +typedef struct +{ + // Keyboard or Mouse event + int32_t event_type; + + // Contains the string corresponding to the key, if any + char buffer[24]; + // Length of the extracted string. Equals 0 if no string is extracted + int32_t buffer_len; + + // Code of the pressed key. + int32_t key_sym; + + // Virtual key code of the pressed key in case of keyboard events + // Mouse button code otherwise. + int32_t key_code; + + // Pressed or Released status + int32_t status; +} InputEvent; + +typedef void (*EventCallback)(void *rust_istance, InputEvent data); + +// Check if a X11 context is available, returning a non-zero code if true. +extern "C" int32_t detect_check_x11(); + +// Initialize the XRecord API and return the context pointer +extern "C" void *detect_initialize(void *rust_istance, int32_t *error_code); + +// Run the event loop. Blocking call. +extern "C" int32_t detect_eventloop(void *context, EventCallback callback); + +// Unregister from the XRecord API and destroy the context. +extern "C" int32_t detect_destroy(void *context); + +#endif //ESPANSO_DETECT_H \ No newline at end of file diff --git a/espanso-ui/build.rs b/espanso-ui/build.rs index bc34a3e..e93d4ee 100644 --- a/espanso-ui/build.rs +++ b/espanso-ui/build.rs @@ -40,11 +40,11 @@ fn cc_config() { #[cfg(target_os = "linux")] fn cc_config() { - println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/"); - println!("cargo:rustc-link-lib=static=linuxbridge"); - println!("cargo:rustc-link-lib=dylib=X11"); - println!("cargo:rustc-link-lib=dylib=Xtst"); - println!("cargo:rustc-link-lib=dylib=xdo"); + // println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/"); + // println!("cargo:rustc-link-lib=static=linuxbridge"); + // println!("cargo:rustc-link-lib=dylib=X11"); + // println!("cargo:rustc-link-lib=dylib=Xtst"); + // println!("cargo:rustc-link-lib=dylib=xdo"); } #[cfg(target_os = "macos")] diff --git a/espanso/src/main.rs b/espanso/src/main.rs index f6d304e..3ffd131 100644 --- a/espanso/src/main.rs +++ b/espanso/src/main.rs @@ -25,15 +25,17 @@ fn main() { ), ]; - let (remote, mut eventloop) = espanso_ui::win32::create(espanso_ui::win32::Win32UIOptions { - show_icon: true, - icon_paths: &icon_paths, - notification_icon_path: r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png" - .to_string(), - }); + + // let (remote, mut eventloop) = espanso_ui::win32::create(espanso_ui::win32::Win32UIOptions { + // show_icon: true, + // icon_paths: &icon_paths, + // notification_icon_path: r"C:\Users\Freddy\Insync\Development\Espanso\Images\icongreensmall.png" + // .to_string(), + // }); - std::thread::spawn(move || { - let mut source = espanso_detect::win32::Win32Source::new(); + let handle = std::thread::spawn(move || { + //let mut source = espanso_detect::win32::Win32Source::new(); + let mut source = espanso_detect::x11::X11Source::new(); source.initialize(); source.eventloop(Box::new(move |event: InputEvent| { println!("ev {:?}", event); @@ -49,21 +51,22 @@ fn main() { })); }); - eventloop.initialize(); - eventloop.run(Box::new(move |event| { - println!("ui {:?}", event); - let menu = Menu::from(vec![ - MenuItem::Simple(SimpleMenuItem::new("open", "Open")), - MenuItem::Separator, - MenuItem::Sub(SubMenuItem::new( - "Sub", - vec![ - MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")), - MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")), - ], - )), - ]) - .unwrap(); - remote.show_context_menu(&menu); - })) + // eventloop.initialize(); + // eventloop.run(Box::new(move |event| { + // println!("ui {:?}", event); + // let menu = Menu::from(vec![ + // MenuItem::Simple(SimpleMenuItem::new("open", "Open")), + // MenuItem::Separator, + // MenuItem::Sub(SubMenuItem::new( + // "Sub", + // vec![ + // MenuItem::Simple(SimpleMenuItem::new("sub1", "Sub 1")), + // MenuItem::Simple(SimpleMenuItem::new("sub2", "Sub 2")), + // ], + // )), + // ]) + // .unwrap(); + // remote.show_context_menu(&menu); + // })) + handle.join(); }