Compare commits

..

28 Commits

Author SHA1 Message Date
270cdca14f Add TOUCHPAD_TOGGLE for linux
Some checks failed
moparisthebest/rusty-keys/pipeline/head There was a failure building this commit
2023-09-05 23:36:12 -04:00
e9705db5ba Update systemd unit to restart always
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2022-04-29 08:08:50 -04:00
10096b2709 Exclude devices with a LEFT mouse button on linux
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-12-28 00:21:00 -05:00
e6f4653570 Exclude Yubico devices on Linux
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-12-12 22:29:45 -05:00
552cd50266 macOS support
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-10-09 01:39:10 -04:00
b0f9dfddf2 release all currently held down keys when any revert_default_key is released
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 02:27:39 -04:00
b0543d3f93 noop other identical keys
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 02:04:34 -04:00
527ab97a04 noop identical keys
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 01:50:24 -04:00
d0e38d0e55 Avoid index out of bounds on strange keys (Apple)
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 01:36:50 -04:00
8ffe640c4b Clean up unused warnings for all features
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 01:00:09 -04:00
bcea441630 Test compilation with each feature individually
Some checks are pending
moparisthebest/rusty-keys/pipeline/head Build queued...
2021-09-25 00:51:00 -04:00
17a8f0c995 make toml and serde optional, if not included, can hardcode config
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-25 00:45:29 -04:00
60a3f24c86 Make epoll and inotify optional dependencies enabled by default with the epoll_inotify feature
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-24 01:03:27 -04:00
c420323cdf light editorial code cleanup
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-24 00:27:10 -04:00
a454b2a2a1 fix comments and order of operations in input_device
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-24 00:13:14 -04:00
877a35861a Updated all package versions 2021-09-24 00:10:02 -04:00
9317d31153 update readme
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-23 23:29:56 -04:00
d785d341cb Rewrite linux mapper to use epoll instead of threads and blocking IO
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-23 23:18:33 -04:00
fa202be7da Determine keyboard devices by whether they support KEY_A or not
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-09-21 23:56:24 -04:00
95833e3a33 Support multiple revert_default_keys
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-04-03 17:15:38 -04:00
b1bb55766d Workaround for (buggy?) Monoprice Dark Matter Aether keyboard
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2021-03-02 23:57:26 -05:00
bd87beb211 Abandon travis-ci for jenkins
All checks were successful
moparisthebest/rusty-keys/pipeline/head This commit looks good
2020-11-26 18:24:53 -05:00
965c446b51 Remove powerpc64-unknown-linux-gnu travis build as it no longer exists 2020-07-11 13:21:10 -04:00
4a816737c7 Upgrade to all latest dependencies 2020-07-11 02:20:20 -04:00
95f9c731e9 Get rid of ancient and broken uinput-sys, proper refactoring to come 2020-07-11 02:05:25 -04:00
6c4e4392b4 Fix old todo thanks to new rust version 2020-07-11 00:59:35 -04:00
432e35cb6a Add travis-ci and appveyor builds 2020-07-11 00:49:03 -04:00
24786356c4 Cargo update and fix newly deprecated code usage 2020-07-11 00:09:43 -04:00
24 changed files with 1736 additions and 2203 deletions

46
.ci/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,46 @@
properties(
[
disableConcurrentBuilds()
]
)
node('linux && docker') {
try {
stage('Checkout') {
//branch name from Jenkins environment variables
echo "My branch is: ${env.BRANCH_NAME}"
// this doesn't grab tags pointing to this branch
//checkout scm
// this hack does... https://issues.jenkins.io/browse/JENKINS-45164
checkout([
$class: 'GitSCM',
branches: [[name: 'refs/heads/'+env.BRANCH_NAME]],
extensions: [[$class: 'CloneOption', noTags: false, shallow: false, depth: 0, reference: '']],
userRemoteConfigs: scm.userRemoteConfigs,
])
sh '''
set -euxo pipefail
git checkout "$BRANCH_NAME" --
git reset --hard "origin/$BRANCH_NAME"
'''
}
stage('Build + Deploy') {
sh '''
mkdir -p release
cp keymap.toml release
curl --compressed -sL https://code.moparisthebest.com/moparisthebest/self-ci/raw/branch/master/build-ci.sh | bash
'''
}
currentBuild.result = 'SUCCESS'
} catch (Exception err) {
currentBuild.result = 'FAILURE'
} finally {
stage('Email') {
step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: 'admin.jenkins@moparisthebest.com', sendToIndividuals: true])
}
deleteDir()
}
}

45
.ci/build.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash
set -exo pipefail
echo "starting build for TARGET $TARGET"
export CRATE_NAME=rusty-keys
DISABLE_TESTS=${DISABLE_TESTS:-0}
SUFFIX=""
echo "$TARGET" | grep -E '^x86_64-pc-windows-gnu$' >/dev/null && SUFFIX=".exe"
[ "$TARGET" == 'riscv64gc-unknown-linux-gnu' ] && echo 'riscv64gc-unknown-linux-gnu is not yet supported by inotify, skipping build...' && exit 0
# no main impl for these platforms
echo "$TARGET" | grep -E '(android|solaris$)' >/dev/null && DISABLE_TESTS=1
cross build --target $TARGET --release
# to check how they are built
file "target/$TARGET/release/rusty-keys$SUFFIX"
if [ $DISABLE_TESTS -ne 1 ]
then
# only going to run --help I guess
cross run --target $TARGET --release --bin rusty-keys -- -h
fi
# if this commit has a tag, upload artifact to release
strip "target/$TARGET/release/rusty-keys$SUFFIX" || true # if strip fails, it's fine
mkdir -p release
mv "target/$TARGET/release/rusty-keys$SUFFIX" "release/rusty-keys-$TARGET$SUFFIX"
if [ "$TARGET" == 'x86_64-unknown-linux-musl' ]
then
# for this arch only, we are going to build with each feature combo to test that the build succeeds, but not archive them
# the default for now is all features, so that's already tested above
cross build --target $TARGET --release --no-default-features
cross build --target $TARGET --release --no-default-features --features epoll_inotify
cross build --target $TARGET --release --no-default-features --features toml_serde
fi
echo 'build success!'
exit 0

232
Cargo.lock generated
View File

@ -1,249 +1,265 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.45"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
version = "0.1.10"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "core-foundation"
version = "0.6.4"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
dependencies = [
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.6.2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]]
name = "core-graphics"
version = "0.17.3"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"core-foundation",
"core-graphics-types",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"core-foundation",
"foreign-types",
"libc",
]
[[package]]
name = "epoll"
version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
dependencies = [
"bitflags",
"libc",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width",
]
[[package]]
name = "inotify"
version = "0.7.0"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5fc8f41dbaa9c8492a96c8afffda4f76896ee041d6a57606e70581b80c901f"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.3"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
]
[[package]]
name = "ioctl-sys"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.62"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
[[package]]
name = "nix"
version = "0.15.0"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]]
name = "proc-macro2"
version = "1.0.4"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.2"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "rusty-keys"
version = "0.0.3"
dependencies = [
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"uinput-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys",
"core-graphics",
"epoll",
"getopts",
"inotify",
"lazy_static",
"libc",
"nix",
"serde",
"toml",
"winapi",
]
[[package]]
name = "serde"
version = "1.0.101"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.101"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.5"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "toml"
version = "0.5.3"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "uinput-sys"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ioctl-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"serde",
]
[[package]]
name = "unicode-width"
version = "0.1.6"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "winapi"
version = "0.3.8"
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-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum ioctl-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2c4b26352496eaaa8ca7cfa9bd99e93419d3f7983dc6e99c2a35fe9e33504a"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
"checksum uinput-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9aabddd8174ccadd600afeab346bb276cb1db5fafcf6a7c5c5708b8cc4b2cac7"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -22,22 +22,26 @@ include = [
[dependencies]
getopts = "0.2.21"
toml = "0.5.3"
serde = { version = "1.0.101", features = ["derive"] }
toml = { version = "0.5.8", optional = true }
serde = { version = "1.0.130", features = ["derive"], optional = true }
#[target.'cfg(target_os="macos")'.dependencies]
core-graphics = "0.17"
core-foundation-sys = "0.6.2"
[target.'cfg(target_os="macos")'.dependencies]
core-graphics = "0.22"
core-foundation-sys = "0.8"
#rustkit = "0.0.1"
lazy_static = "1.4.0"
libc = "0.2"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser", "wincon"] }
winapi = { version = "0.3.9", features = ["winuser", "wincon"] }
lazy_static = "1.4.0"
[target.'cfg(target_os="linux")'.dependencies]
libc = "0.2.62"
nix = "0.15.0"
uinput-sys = "0.1.7"
inotify = { version = "0.7.0", default-features = false, features = [] }
libc = "0.2.102"
nix = "0.22.1"
epoll = { version = "4.3.1", optional = true }
inotify = { version = "0.9.3", default-features = false, features = [], optional = true }
[features]
default = ["epoll_inotify", "toml_serde"]
toml_serde = ["toml", "serde"]
epoll_inotify = ["epoll", "inotify"]

909
Events.h
View File

@ -1,909 +0,0 @@
/*
File: HIToolbox/Events.h
Contains: Event Manager Interfaces.
Copyright: © 1985-2008 by Apple Computer, Inc., all rights reserved
Bugs?: For bug reports, consult the following page on
the World Wide Web:
http://developer.apple.com/bugreporter/
*/
#ifndef __EVENTS__
#define __EVENTS__
#ifndef __APPLICATIONSERVICES__
#include <ApplicationServices/ApplicationServices.h>
#endif
#include <AvailabilityMacros.h>
#if PRAGMA_ONCE
#pragma once
#endif
#ifdef __cplusplus
extern "C" {
#endif
#pragma pack(push, 2)
typedef UInt16 EventKind;
typedef UInt16 EventMask;
enum {
nullEvent = 0,
mouseDown = 1,
mouseUp = 2,
keyDown = 3,
keyUp = 4,
autoKey = 5,
updateEvt = 6,
diskEvt = 7, /* Not sent in Carbon. See kEventClassVolume in CarbonEvents.h*/
activateEvt = 8,
osEvt = 15,
kHighLevelEvent = 23
};
enum {
mDownMask = 1 << mouseDown, /* mouse button pressed*/
mUpMask = 1 << mouseUp, /* mouse button released*/
keyDownMask = 1 << keyDown, /* key pressed*/
keyUpMask = 1 << keyUp, /* key released*/
autoKeyMask = 1 << autoKey, /* key repeatedly held down*/
updateMask = 1 << updateEvt, /* window needs updating*/
diskMask = 1 << diskEvt, /* disk inserted*/
activMask = 1 << activateEvt, /* activate/deactivate window*/
highLevelEventMask = 0x0400, /* high-level events (includes AppleEvents)*/
osMask = 1 << osEvt, /* operating system events (suspend, resume)*/
everyEvent = 0xFFFF /* all of the above*/
};
enum {
charCodeMask = 0x000000FF,
keyCodeMask = 0x0000FF00,
adbAddrMask = 0x00FF0000,
osEvtMessageMask = (UInt32)0xFF000000
};
enum {
/* OS event messages. Event (sub)code is in the high byte of the message field.*/
mouseMovedMessage = 0x00FA,
suspendResumeMessage = 0x0001
};
enum {
resumeFlag = 1 /* Bit 0 of message indicates resume vs suspend*/
};
#if CALL_NOT_IN_CARBON
/* convertClipboardFlag is not ever set under Carbon. This is because scrap conversion is */
/* not tied to suspend/resume events any longer. Your application should instead use the */
/* scrap promise mechanism and fulfill scrap requests only when your promise keeper proc */
/* is called. If you need to know if the scrap has changed, you can cache the last */
/* ScrapRef you received and compare it with the current ScrapRef */
enum {
convertClipboardFlag = 2 /* Bit 1 in resume message indicates clipboard change*/
};
#endif /* CALL_NOT_IN_CARBON */
/*
CARBON ALERT! BATTLESTATIONS!
The EventModifiers bits defined here are also used in the newer Carbon Event
key modifiers parameters. There are two main differences:
1) The Carbon key modifiers parameter is a UInt32, not a UInt16. Never try to
extract the key modifiers parameter from a Carbon Event into an EventModifiers
type. You will probably get your stack trashed.
2) The Carbon key modifiers is just that: key modifiers. That parameter will
never contain the button state bit.
*/
typedef UInt16 EventModifiers;
enum {
/* modifiers */
activeFlagBit = 0, /* activate? (activateEvt and mouseDown)*/
btnStateBit = 7, /* state of button?*/
cmdKeyBit = 8, /* command key down?*/
shiftKeyBit = 9, /* shift key down?*/
alphaLockBit = 10, /* alpha lock down?*/
optionKeyBit = 11, /* option key down?*/
controlKeyBit = 12, /* control key down?*/
rightShiftKeyBit = 13, /* right shift key down? Not supported on Mac OS X.*/
rightOptionKeyBit = 14, /* right Option key down? Not supported on Mac OS X.*/
rightControlKeyBit = 15 /* right Control key down? Not supported on Mac OS X.*/
};
enum {
activeFlag = 1 << activeFlagBit,
btnState = 1 << btnStateBit,
cmdKey = 1 << cmdKeyBit,
shiftKey = 1 << shiftKeyBit,
alphaLock = 1 << alphaLockBit,
optionKey = 1 << optionKeyBit,
controlKey = 1 << controlKeyBit,
rightShiftKey = 1 << rightShiftKeyBit, /* Not supported on Mac OS X.*/
rightOptionKey = 1 << rightOptionKeyBit, /* Not supported on Mac OS X.*/
rightControlKey = 1 << rightControlKeyBit /* Not supported on Mac OS X.*/
};
/* MacRoman character codes*/
enum {
kNullCharCode = 0,
kHomeCharCode = 1,
kEnterCharCode = 3,
kEndCharCode = 4,
kHelpCharCode = 5,
kBellCharCode = 7,
kBackspaceCharCode = 8,
kTabCharCode = 9,
kLineFeedCharCode = 10,
kVerticalTabCharCode = 11,
kPageUpCharCode = 11,
kFormFeedCharCode = 12,
kPageDownCharCode = 12,
kReturnCharCode = 13,
kFunctionKeyCharCode = 16,
kCommandCharCode = 17, /* glyph available only in system fonts*/
kCheckCharCode = 18, /* glyph available only in system fonts*/
kDiamondCharCode = 19, /* glyph available only in system fonts*/
kAppleLogoCharCode = 20, /* glyph available only in system fonts*/
kEscapeCharCode = 27,
kClearCharCode = 27,
kLeftArrowCharCode = 28,
kRightArrowCharCode = 29,
kUpArrowCharCode = 30,
kDownArrowCharCode = 31,
kSpaceCharCode = 32,
kDeleteCharCode = 127,
kBulletCharCode = 165,
kNonBreakingSpaceCharCode = 202
};
/* useful Unicode code points*/
enum {
kShiftUnicode = 0x21E7, /* Unicode UPWARDS WHITE ARROW*/
kControlUnicode = 0x2303, /* Unicode UP ARROWHEAD*/
kOptionUnicode = 0x2325, /* Unicode OPTION KEY*/
kCommandUnicode = 0x2318, /* Unicode PLACE OF INTEREST SIGN*/
kPencilUnicode = 0x270E, /* Unicode LOWER RIGHT PENCIL; actually pointed left until Mac OS X 10.3*/
kPencilLeftUnicode = 0xF802, /* Unicode LOWER LEFT PENCIL; available in Mac OS X 10.3 and later*/
kCheckUnicode = 0x2713, /* Unicode CHECK MARK*/
kDiamondUnicode = 0x25C6, /* Unicode BLACK DIAMOND*/
kBulletUnicode = 0x2022, /* Unicode BULLET*/
kAppleLogoUnicode = 0xF8FF /* Unicode APPLE LOGO*/
};
/*
* Summary:
* Virtual keycodes
*
* Discussion:
* These constants are the virtual keycodes defined originally in
* Inside Mac Volume V, pg. V-191. They identify physical keys on a
* keyboard. Those constants with "ANSI" in the name are labeled
* according to the key position on an ANSI-standard US keyboard.
* For example, kVK_ANSI_A indicates the virtual keycode for the key
* with the letter 'A' in the US keyboard layout. Other keyboard
* layouts may have the 'A' key label on a different physical key;
* in this case, pressing 'A' will generate a different virtual
* keycode.
*/
enum {
kVK_ANSI_A = 0x00,
kVK_ANSI_S = 0x01,
kVK_ANSI_D = 0x02,
kVK_ANSI_F = 0x03,
kVK_ANSI_H = 0x04,
kVK_ANSI_G = 0x05,
kVK_ANSI_Z = 0x06,
kVK_ANSI_X = 0x07,
kVK_ANSI_C = 0x08,
kVK_ANSI_V = 0x09,
kVK_ANSI_B = 0x0B,
kVK_ANSI_Q = 0x0C,
kVK_ANSI_W = 0x0D,
kVK_ANSI_E = 0x0E,
kVK_ANSI_R = 0x0F,
kVK_ANSI_Y = 0x10,
kVK_ANSI_T = 0x11,
kVK_ANSI_1 = 0x12,
kVK_ANSI_2 = 0x13,
kVK_ANSI_3 = 0x14,
kVK_ANSI_4 = 0x15,
kVK_ANSI_6 = 0x16,
kVK_ANSI_5 = 0x17,
kVK_ANSI_Equal = 0x18,
kVK_ANSI_9 = 0x19,
kVK_ANSI_7 = 0x1A,
kVK_ANSI_Minus = 0x1B,
kVK_ANSI_8 = 0x1C,
kVK_ANSI_0 = 0x1D,
kVK_ANSI_RightBracket = 0x1E,
kVK_ANSI_O = 0x1F,
kVK_ANSI_U = 0x20,
kVK_ANSI_LeftBracket = 0x21,
kVK_ANSI_I = 0x22,
kVK_ANSI_P = 0x23,
kVK_ANSI_L = 0x25,
kVK_ANSI_J = 0x26,
kVK_ANSI_Quote = 0x27,
kVK_ANSI_K = 0x28,
kVK_ANSI_Semicolon = 0x29,
kVK_ANSI_Backslash = 0x2A,
kVK_ANSI_Comma = 0x2B,
kVK_ANSI_Slash = 0x2C,
kVK_ANSI_N = 0x2D,
kVK_ANSI_M = 0x2E,
kVK_ANSI_Period = 0x2F,
kVK_ANSI_Grave = 0x32,
kVK_ANSI_KeypadDecimal = 0x41,
kVK_ANSI_KeypadMultiply = 0x43,
kVK_ANSI_KeypadPlus = 0x45,
kVK_ANSI_KeypadClear = 0x47,
kVK_ANSI_KeypadDivide = 0x4B,
kVK_ANSI_KeypadEnter = 0x4C,
kVK_ANSI_KeypadMinus = 0x4E,
kVK_ANSI_KeypadEquals = 0x51,
kVK_ANSI_Keypad0 = 0x52,
kVK_ANSI_Keypad1 = 0x53,
kVK_ANSI_Keypad2 = 0x54,
kVK_ANSI_Keypad3 = 0x55,
kVK_ANSI_Keypad4 = 0x56,
kVK_ANSI_Keypad5 = 0x57,
kVK_ANSI_Keypad6 = 0x58,
kVK_ANSI_Keypad7 = 0x59,
kVK_ANSI_Keypad8 = 0x5B,
kVK_ANSI_Keypad9 = 0x5C
};
/* keycodes for keys that are independent of keyboard layout*/
enum {
kVK_Return = 0x24,
kVK_Tab = 0x30,
kVK_Space = 0x31,
kVK_Delete = 0x33,
kVK_Escape = 0x35,
kVK_Command = 0x37,
kVK_Shift = 0x38,
kVK_CapsLock = 0x39,
kVK_Option = 0x3A,
kVK_Control = 0x3B,
kVK_RightCommand = 0x36,
kVK_RightShift = 0x3C,
kVK_RightOption = 0x3D,
kVK_RightControl = 0x3E,
kVK_Function = 0x3F,
kVK_F17 = 0x40,
kVK_VolumeUp = 0x48,
kVK_VolumeDown = 0x49,
kVK_Mute = 0x4A,
kVK_F18 = 0x4F,
kVK_F19 = 0x50,
kVK_F20 = 0x5A,
kVK_F5 = 0x60,
kVK_F6 = 0x61,
kVK_F7 = 0x62,
kVK_F3 = 0x63,
kVK_F8 = 0x64,
kVK_F9 = 0x65,
kVK_F11 = 0x67,
kVK_F13 = 0x69,
kVK_F16 = 0x6A,
kVK_F14 = 0x6B,
kVK_F10 = 0x6D,
kVK_F12 = 0x6F,
kVK_F15 = 0x71,
kVK_Help = 0x72,
kVK_Home = 0x73,
kVK_PageUp = 0x74,
kVK_ForwardDelete = 0x75,
kVK_F4 = 0x76,
kVK_End = 0x77,
kVK_F2 = 0x78,
kVK_PageDown = 0x79,
kVK_F1 = 0x7A,
kVK_LeftArrow = 0x7B,
kVK_RightArrow = 0x7C,
kVK_DownArrow = 0x7D,
kVK_UpArrow = 0x7E
};
/* ISO keyboards only*/
enum {
kVK_ISO_Section = 0x0A
};
/* JIS keyboards only*/
enum {
kVK_JIS_Yen = 0x5D,
kVK_JIS_Underscore = 0x5E,
kVK_JIS_KeypadComma = 0x5F,
kVK_JIS_Eisu = 0x66,
kVK_JIS_Kana = 0x68
};
struct EventRecord {
EventKind what;
unsigned long message;
UInt32 when;
Point where;
EventModifiers modifiers;
};
typedef struct EventRecord EventRecord;
typedef CALLBACK_API( void , FKEYProcPtr )(void);
typedef STACK_UPP_TYPE(FKEYProcPtr) FKEYUPP;
/*
* NewFKEYUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
/*
* DisposeFKEYUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
/*
* InvokeFKEYUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
#if !__LP64__
/*
* GetMouse() *** DEPRECATED ***
*
* Deprecated:
* Use HIGetMousePosition instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.5
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
GetMouse(Point * mouseLoc) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
#endif /* !__LP64__ */
/*
* Button() *** DEPRECATED ***
*
* Deprecated:
* Use GetCurrentButtonState or GetCurrentEventButtonState instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
Button(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
#if !__LP64__
/*
* StillDown()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
StillDown(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
/*
* WaitMouseUp()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
WaitMouseUp(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
/*
* KeyTranslate() *** DEPRECATED ***
*
* Deprecated:
* Use UCKeyTranslate instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern UInt32
KeyTranslate(
const void * transData,
UInt16 keycode,
UInt32 * state) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
/*
* GetCaretTime()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern UInt32
GetCaretTime(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#endif /* !__LP64__ */
/*
QuickTime 3.0 supports GetKeys() on unix and win32
But, on little endian machines you will have to be
careful about bit numberings and/or use a KeyMapByteArray
instead.
*/
#if TARGET_API_MAC_OS8
typedef UInt32 KeyMap[4];
#else
typedef BigEndianUInt32 KeyMap[4];
#endif /* TARGET_API_MAC_OS8 */
typedef UInt8 KeyMapByteArray[16];
/*
* GetKeys()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
GetKeys(KeyMap theKeys) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
/* Obsolete event types & masks */
enum {
networkEvt = 10,
driverEvt = 11,
app1Evt = 12,
app2Evt = 13,
app3Evt = 14,
app4Evt = 15,
networkMask = 0x0400,
driverMask = 0x0800,
app1Mask = 0x1000,
app2Mask = 0x2000,
app3Mask = 0x4000,
app4Mask = 0x8000
};
struct EvQEl {
QElemPtr qLink;
SInt16 qType;
EventKind evtQWhat; /* this part is identical to the EventRecord as defined above */
unsigned long evtQMessage;
UInt32 evtQWhen;
Point evtQWhere;
EventModifiers evtQModifiers;
};
typedef struct EvQEl EvQEl;
typedef EvQEl * EvQElPtr;
typedef CALLBACK_API( void , GetNextEventFilterProcPtr )(EventRecord *theEvent, Boolean *result);
typedef STACK_UPP_TYPE(GetNextEventFilterProcPtr) GetNextEventFilterUPP;
/*
* NewGetNextEventFilterUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
/*
* DisposeGetNextEventFilterUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
/*
* InvokeGetNextEventFilterUPP()
*
* Availability:
* Mac OS X: not available
* CarbonLib: not available
* Non-Carbon CFM: available as macro/inline
*/
typedef GetNextEventFilterUPP GNEFilterUPP;
#if !__LP64__
/*
* GetDblTime()
*
* Summary:
* Returns the maximum time (in units of 1/60th of a second) allowed
* between two consecutive mouse-down events in order for the second
* click to be considered a double-click.
*
* Discussion:
* In 64-bit applications, you may replace calls to this API with
* calls to NXClickTime (declared in
* <IOKit/hidsystem/event_status_driver.h>) or with +[NSEvent
* doubleClickInterval] (available in Mac OS X 10.6 and later).
*
* Mac OS X threading:
* Not thread safe
*
* Result:
* The maximum time between mouse-downs allowed for a double-click.
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern UInt32
GetDblTime(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
/*
* SetEventMask()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
SetEventMask(EventMask value) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
/*
* GetNextEvent() *** DEPRECATED ***
*
* Deprecated:
* Use ReceiveNextEvent instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
GetNextEvent(
EventMask eventMask,
EventRecord * theEvent) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
/*
* WaitNextEvent() *** DEPRECATED ***
*
* Deprecated:
* Use ReceiveNextEvent instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
WaitNextEvent(
EventMask eventMask,
EventRecord * theEvent,
UInt32 sleep,
RgnHandle mouseRgn) /* can be NULL */ AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
/*
* EventAvail() *** DEPRECATED ***
*
* Deprecated:
* Use FindSpecificEventInQueue instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
EventAvail(
EventMask eventMask,
EventRecord * theEvent) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
/*
* PostEvent() *** DEPRECATED ***
*
* Deprecated:
* Use PostEventToQueue or CGEventPost instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern OSErr
PostEvent(
EventKind eventNum,
UInt32 eventMsg) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
#endif /* !__LP64__ */
/*
* FlushEvents() *** DEPRECATED ***
*
* Deprecated:
* Use FlushEventsMatchingListFromQueue,
* FlushSpecificEventsFromQueue, or FlushEventQueue instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
FlushEvents(
EventMask whichMask,
EventMask stopMask) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
#if OLDROUTINENAMES
#define KeyTrans(transData, keycode, state) KeyTranslate(transData, keycode, state)
#endif /* OLDROUTINENAMES */
#if !__LP64__
/*
* KeyScript() *** DEPRECATED ***
*
* Deprecated:
* Use TISSelectInputSource API for positive verbs (ScriptCode).
* Use TSMDocument properties to restrict input sources:
* kTSMDocumentEnabledInputSourcesPropertyTag
* kTSMDocumentInputSourceOverridePropertyTag
*
* Summary:
* Switch to the specified script's default (last used) input source.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only] but deprecated in 10.5
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
KeyScript(short code) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5;
#endif /* !__LP64__ */
/*
* IsCmdChar() *** DEPRECATED ***
*
* Deprecated:
* Use IsUserCancelEventRef or CheckEventQueueForUserCancel instead.
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework but deprecated in 10.6
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern Boolean
IsCmdChar(
const EventRecord * event,
short test) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
/*
LowMem accessor functions previously in LowMem.h
*/
/*
* LMGetKeyThresh()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern SInt16
LMGetKeyThresh(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#if !__LP64__
/*
* LMSetKeyThresh()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
LMSetKeyThresh(SInt16 value) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#endif /* !__LP64__ */
/*
* LMGetKeyRepThresh()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern SInt16
LMGetKeyRepThresh(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#if !__LP64__
/*
* LMSetKeyRepThresh()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
LMSetKeyRepThresh(SInt16 value) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#endif /* !__LP64__ */
/*
* LMGetKbdLast()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern UInt8
LMGetKbdLast(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#if !__LP64__
/*
* LMSetKbdLast()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
LMSetKbdLast(UInt8 value) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#endif /* !__LP64__ */
/*
* LMGetKbdType()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern UInt8
LMGetKbdType(void) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#if !__LP64__
/*
* LMSetKbdType()
*
* Mac OS X threading:
* Not thread safe
*
* Availability:
* Mac OS X: in version 10.0 and later in Carbon.framework [32-bit only]
* CarbonLib: in CarbonLib 1.0 and later
* Non-Carbon CFM: in InterfaceLib 7.1 and later
*/
extern void
LMSetKbdType(UInt8 value) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER;
#endif /* !__LP64__ */
#pragma pack(pop)
#ifdef __cplusplus
}
#endif
#endif /* __EVENTS__ */

View File

@ -1,8 +1,11 @@
rusty-keys
======
uinput level keyboard mapper for linux, with advanced caps lock and shift swapping behavior
==========
This is the only keymapper I am aware of capable of implementing this layout:
[![Build Status](https://ci.moparisthe.best/job/moparisthebest/job/rusty-keys/job/master/badge/icon%3Fstyle=plastic)](https://ci.moparisthe.best/job/moparisthebest/job/rusty-keys/job/master/)
low level keyboard mapper for linux and windows, with advanced caps lock and shift swapping behavior
This is the only keymapper I am aware of capable of implementing this layout, which I call Unix Programmer's Dvorak, which has been my daily driver since 2014:
![Unix Programmer's Dvorak](https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg)
The Problem
@ -17,7 +20,7 @@ The Solution
2. Create a new keyboard input device with uinput, this looks identical to any other keyboard device to anything running on the box.
3. Read input_events from the real device, map them, send them to our created device.
This solution is what rusty-keys implements, it works in ttys, in X, in virtualbox even running windows or whatever,
This solution is what rusty-keys implements, it works in ttys, in X, in Wayland, in virtualbox even running windows or whatever,
on SDL games, it will work literally everywhere, because rusty-keys just creates a regular keyboard.
How to run
@ -49,6 +52,7 @@ How to install
--------------
* `cargo install rusty-keys`
* Arch Linux [rusty-keys](https://aur.archlinux.org/packages/rusty-keys/) [rusty-keys-git](https://aur.archlinux.org/packages/rusty-keys-git/)
* Download a static binary for your system from the [releases](https://code.moparisthebest.com/moparisthebest/rusty-keys/releases) section. [github mirror](https://github.com/moparisthebest/rusty-keys/releases)
License
-------

90
appveyor.yml Normal file
View File

@ -0,0 +1,90 @@
# Based on the "trust" template v0.1.2
# https://github.com/japaric/trust/tree/v0.1.2
environment:
global:
# TODO This is the Rust channel that build jobs will use by default but can be
# overridden on a case by case basis down below
RUST_VERSION: stable
# TODO Update this to match the name of your project.
CRATE_NAME: rusty-keys
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
# don't need
matrix:
# MinGW
- TARGET: i686-pc-windows-gnu
- TARGET: x86_64-pc-windows-gnu
# MSVC
- TARGET: i686-pc-windows-msvc
- TARGET: x86_64-pc-windows-msvc
# Testing other channels
- TARGET: x86_64-pc-windows-gnu
RUST_VERSION: nightly
- TARGET: x86_64-pc-windows-msvc
RUST_VERSION: nightly
install:
- ps: >-
If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
$Env:PATH += ';C:\msys64\mingw64\bin'
} ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
$Env:PATH += ';C:\msys64\mingw32\bin'
}
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -Vv
- cargo -V
# TODO This is the "test phase", tweak it as you see fit
test_script:
# we don't run the "test phase" when doing deploys
- if [%APPVEYOR_REPO_TAG%]==[false] (
cargo build --target %TARGET% --release &&
cargo run --target %TARGET% --release --bin rusty-keys -- -h
)
before_deploy:
# TODO Update this to build the artifacts that matter to you
- cargo rustc --target %TARGET% --release --bin rusty-keys -- -C lto
- ps: ci\before_deploy.ps1
deploy:
artifact: /rusty-keys-.*\.exe/
# TODO update `auth_token.secure`
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
# - Paste the output down here
auth_token:
secure: gyQW6TqUY94X8IpcQeezbngBQA/PROaCPpr8K+8IxGBG5gf2iHra2CLlp/QJJZYx
description: ''
on:
# TODO Here you can pick which targets will generate binary releases
# In this example, there are some targets that are tested using the stable
# and nightly channels. This condition makes sure there is only one release
# for such targets and that's generated using the stable channel
RUST_VERSION: stable
appveyor_repo_tag: true
provider: GitHub
cache:
- C:\Users\appveyor\.cargo\registry
- target
branches:
only:
# Release tags
- /^v\d+\.\d+\.\d+.*$/
- master
- dev
notifications:
- provider: Email
on_build_success: false
# Building is done in the test phase, so we disable Appveyor's build phase.
build: false

View File

@ -1,10 +0,0 @@
#!/bin/sh
# https://github.com/millerjs/modelm
# mount.cifs -o user=mopar,pass=,uid=1000,gid=1000,forceuid //mojave/mopar /mnt/mojave/
ssh mojave bash -s "$@" <<EOF
. .profile
cd /Users/mopar/IdeaProjects/rusty-keys
cargo "\$@"
EOF

View File

@ -1,76 +0,0 @@
#!/usr/bin/env python
# pressing all of these keys along with a number key representing the index of keymaps changes the layout
# ie, in this case pressing both and 0 would go QWERTY, while both and 1 would go dvorak
switch_layout_keys = ['LEFTSHIFT','RIGHTSHIFT']
# pressing QWERTY reverts to the index specified in revert_keymap_index for only the duration of the pressing
# used so QWERTY shortcuts like Ctrl+C still work
revert_default_key = 'LEFTCTRL'
revert_keymap_index = 0
# this is the default index to use when the program first starts
# in this case, 2 means modified Progammer Dvorak
default_keymap_index = 2
# these are keys that caps_lock doesn't modify by default, but that you would like it to, affects all keymaps
caps_lock_modify = """
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, PSLS,PAST,PMNS,
LBRC,RBRC,BSLS, P7, P8, P9,
SCLN,QUOT, P4, P5, P6, PPLS,
COMM,DOT, SLSH, P1, P2, P3,
P0, PDOT
"""
# these are the keymaps available, you can add as many as you want or re-order them, just be aware the mapping is
# always done from the first one to all subsequent ones, so you probably want to leave QWERTY or similar up top
keymaps = [
# default key layout, QWERTY in this case
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
""",
# Dvorak http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard
# https://www.moparisthebest.com/kbs/standard-dvorak-QwertySecondary.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, LBRC,RBRC,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, QUOT,COMM,DOT, P, Y, F, G, C, R, L, SLSH,EQL, BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4, P5, P6, PPLS,
LSFT,SCLN,Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
""",
# Unix Dvorak Programmer Dvorak - for unix developers who are switching from dvorak
# https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
^4:^GRV, ^7:1, LBRC:2, ^LBRC:3, ^RBRC:4, ^9:5, ^2:6, ^8:7, ^0:8, ^EQL:9, RBRC:0, ^1:^5, ^3:GRV, BSPC, INS, HOME,PGUP, NLCK, PSLS:^9, PAST:^0, PMNS:^4,
TAB, QUOT, COMM, DOT, P, Y, F, G, C, R, L, SLSH, EQL:^6, ^BSLS:BSLS, DEL, END, PGDN, P7:^A, P8:^B, P9:^C,
CAPS, A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4:^D, P5:^E, P6:^F, PPLS:COMM,
LSFT, SCLN, Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1:EQL, P2:X, P3:^SCLN,
LCTL, LGUI, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, P0:BSLS, PDOT:SCLN, PENT
""",
# Unix Dvorak Programmer Dvorak - for unix developers who are switching from dvorak - phone numpad
# https://www.moparisthebest.com/kbs/programmer-dvorak-QwertySecondary-NumpadPhone-NoSwap-StandardNums-SwapAt-SwapPipe.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
^4:^GRV, ^7:1, LBRC:2, ^LBRC:3, ^RBRC:4, ^9:5, ^2:6, ^8:7, ^0:8, ^EQL:9, RBRC:0, ^1:^5, ^3:GRV, BSPC, INS, HOME,PGUP, NLCK, PSLS:^9, PAST:^0, PMNS:^4,
TAB, QUOT, COMM, DOT, P, Y, F, G, C, R, L, SLSH, EQL:^6, ^BSLS:BSLS, DEL, END, PGDN, P1:^A, P2:^B, P3:^C,
CAPS, A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4:^D, P5:^E, P6:^F, PPLS:COMM,
LSFT, SCLN, Q, J, K, X, B, M, W, V, Z, RSFT, UP, P7:EQL, P8:X, P9:^SCLN,
LCTL, LGUI, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, P0:BSLS, PDOT:SCLN, PENT
""",
# Programmer Dvorak http://www.kaufmann.no/roland/dvorak/
# https://www.moparisthebest.com/kbs/programmer-dvorak-QwertySecondary-NumpadPhone-StrictSwap-StrictNums-StrictAt-StrictPipe.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
^4:^GRV, ^7:^5, LBRC:7, ^LBRC:5, ^RBRC:3, ^9:1, EQL:9, ^8:0, ^0:2, ^EQL:4, RBRC:6, ^1:8, ^3:GRV, BSPC, INS, HOME,PGUP, NLCK, PSLS:^9, PAST:^0, PMNS:^4,
TAB, SCLN, COMM, DOT, P, Y, F, G, C, R, L, SLSH, ^2:^6, BSLS, DEL, END, PGDN, P1:^A, P2:^B, P3:^C,
CAPS, A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4:^D, P5:^E, P6:^F, PPLS:COMM,
LSFT, QUOT, Q, J, K, X, B, M, W, V, Z, RSFT, UP, P7:EQL, P8:X, P9:^SCLN,
LCTL, LGUI, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, P0:BSLS, PDOT:SCLN, PENT
""",
]

View File

@ -3,9 +3,9 @@
# ie, in this case pressing both and 0 would go QWERTY, while both and 1 would go dvorak
switch_layout_keys = ['LEFTSHIFT','RIGHTSHIFT']
# pressing QWERTY reverts to the index specified in revert_keymap_index for only the duration of the pressing
# pressing any of these keys reverts to the index specified in revert_keymap_index for only the duration of the pressing
# used so QWERTY shortcuts like Ctrl+C still work
revert_default_key = 'LEFTCTRL'
revert_default_keys = ['LCTL','LGUI','LALT']
revert_keymap_index = 0
# this is the default index to use when the program first starts
@ -17,31 +17,31 @@ default_keymap_index = 2
keymaps = [
# default key layout, QWERTY in this case
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,TAB,
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,TAB,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
""",
# Dvorak http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard
# https://www.moparisthebest.com/kbs/standard-dvorak-QwertySecondary.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,TAB,
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, LBRC,RBRC,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, QUOT,COMM,DOT, P, Y, F, G, C, R, L, SLSH,EQL, BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4, P5, P6, PPLS,
LSFT,SCLN,Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1, P2, P3,
LCTL,TAB,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
""",
# Unix Programmer Dvorak - for unix developers who are switching from dvorak
# https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg
"""
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,TAB,
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
*^4:*^GRV, *^7:*1, *LBRC:*2, *^LBRC:*3, *^RBRC:*4, *^9:*5, *^2:*6, *^8:*7, *^0:*8, *^EQL:*9, *RBRC:*0, *^1:*^5, *^3:*GRV, BSPC, INS, HOME,PGUP, NLCK, *PSLS:*^9, *PAST:*^0, *PMNS:*^4,
TAB, *QUOT, *COMM, *DOT, P, Y, F, G, C, R, L, *SLSH, *EQL:*^6, *^BSLS, DEL, END, PGDN, *P7:^A, *P8:^B, *P9:^C,
CAPS, A, O, E, U, I, D, H, T, N, S, *MINS, ENT, *P4:^D, *P5:^E, *P6:^F, *PPLS:*COMM,
LSFT, *SCLN, Q, J, K, X, B, M, W, V, Z, RSFT, UP, *P1:*EQL, *P2:X, *P3:*^SCLN,
LCTL, TAB, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, *P0:*BSLS, *PDOT:*SCLN, PENT
LCTL, LGUI, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, *P0:*BSLS, *PDOT:*SCLN, PENT
""",
]

179
keys.txt
View File

@ -1,179 +0,0 @@
Finished dev [unoptimized + debuginfo] target(s) in 0.07s
Running `target/debug/rusty-keys`
chosen config file: keymap.toml
Created event tap...
KEY 53
KEY 18
KEY 19
KEY 20
KEY 21
KEY 23
KEY 22
KEY 26
KEY 28
KEY 25
KEY 29
KEY 27
KEY 24
KEY 51
KEY 48
KEY 12
KEY 13
KEY 14
KEY 15
KEY 17
KEY 16
KEY 32
KEY 34
KEY 31
KEY 35
KEY 33
KEY 30
KEY 36
KEY 59
KEY 59
KEY 0
KEY 1
KEY 2
KEY 3
KEY 5
KEY 4
KEY 38
KEY 40
KEY 37
KEY 41
KEY 39
KEY 50
KEY 56
KEY 56
KEY 42
KEY 6
KEY 7
KEY 8
KEY 9
KEY 11
KEY 45
KEY 46
KEY 43
KEY 47
KEY 44
KEY 60
KEY 60
KEY 67
KEY 58
KEY 58
KEY 49
KEY 122
KEY 120
KEY 99
KEY 118
KEY 96
KEY 97
KEY 98
KEY 100
KEY 101
KEY 109
KEY 71
KEY 107
KEY 89
KEY 91
KEY 92
KEY 78
KEY 107
KEY 86
KEY 87
KEY 88
KEY 69
KEY 83
KEY 84
KEY 85
KEY 82
KEY 65
KEY 10
KEY 103
KEY 111
KEY 76
KEY 62
KEY 62
KEY 75
KEY 105
KEY 61
KEY 61
KEY 113
KEY 115
KEY 126
KEY 116
KEY 123
KEY 124
KEY 119
KEY 125
KEY 121
KEY 114
KEY 117
KEY 105
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 54
KEY 113
KEY 54
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 71
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 55
KEY 55
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 55
KEY 55
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 54
KEY 54
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 113
KEY 110
KEY 71

120
out2.txt
View File

@ -1,120 +0,0 @@
KEY 0x0035
KEY 0x0012
KEY 0x0013
KEY 0x0014
KEY 0x0015
KEY 0x0017
KEY 0x0016
KEY 0x001A
KEY 0x001C
KEY 0x0019
KEY 0x001D
KEY 0x001B
KEY 0x0018
KEY 0x0033
KEY 0x0030
KEY 0x000C
KEY 0x000D
KEY 0x000E
KEY 0x000F
KEY 0x0011
KEY 0x0010
KEY 0x0020
KEY 0x0022
KEY 0x001F
KEY 0x0023
KEY 0x0021
KEY 0x001E
KEY 0x0024
KEY 0x003B
KEY 0x003B
KEY 0x0000
KEY 0x0001
KEY 0x0002
KEY 0x0003
KEY 0x0005
KEY 0x0004
KEY 0x0026
KEY 0x0028
KEY 0x0025
KEY 0x0029
KEY 0x0027
KEY 0x0032
KEY 0x0038
KEY 0x0038
KEY 0x002A
KEY 0x0006
KEY 0x0007
KEY 0x0008
KEY 0x0009
KEY 0x000B
KEY 0x002D
KEY 0x002E
KEY 0x002B
KEY 0x002F
KEY 0x002C
KEY 0x003C
KEY 0x003C
KEY 0x0043
KEY 0x003A
KEY 0x003A
KEY 0x0031
KEY 0x007A
KEY 0x0078
KEY 0x0063
KEY 0x0076
KEY 0x0060
KEY 0x0061
KEY 0x0062
KEY 0x0064
KEY 0x0065
KEY 0x006D
KEY 0x0047
KEY 0x006B
KEY 0x006B
KEY 0x0059
KEY 0x005B
KEY 0x005C
KEY 0x004E
KEY 0x0056
KEY 0x0057
KEY 0x0058
KEY 0x0045
KEY 0x0053
KEY 0x0054
KEY 0x0055
KEY 0x0052
KEY 0x0041
KEY 0x000A
KEY 0x0067
KEY 0x006F
KEY 0x004C
KEY 0x003E
KEY 0x003E
KEY 0x004B
KEY 0x0069
KEY 0x003D
KEY 0x003D
KEY 0x0071
KEY 0x0073
KEY 0x007E
KEY 0x0074
KEY 0x007B
KEY 0x007C
KEY 0x0077
KEY 0x007D
KEY 0x0079
KEY 0x0072
KEY 0x0075
KEY 0x0069
KEY 0x0047
KEY 0x0036
KEY 0x0036
KEY 0x0037
KEY 0x0037
KEY 0x0037
KEY 0x0037
KEY 0x0036
KEY 0x0036
KEY 0x006E
KEY 0x0047

View File

@ -3,15 +3,9 @@ use std::error;
use std::ffi;
use std::io;
#[cfg(target_os = "linux")]
use std::sync::mpsc;
#[cfg(target_os = "linux")]
use nix;
#[cfg(target_os = "linux")]
use libc;
/// UInput error.
#[derive(Debug)]
pub enum Error {
@ -23,15 +17,17 @@ pub enum Error {
Nul(ffi::NulError),
Io(io::Error),
#[cfg(feature = "toml_serde")]
Toml(toml::de::Error),
#[cfg(target_os = "linux")]
Send(mpsc::SendError<libc::input_event>),
/// The uinput file could not be found.
NotFound,
NotAKeyboard,
/// error reading input_event
ShortRead,
/// epoll already added
EpollAlreadyAdded,
}
impl From<ffi::NulError> for Error {
@ -53,41 +49,26 @@ impl From<io::Error> for Error {
}
}
#[cfg(target_os = "linux")]
impl From<mpsc::SendError<libc::input_event>> for Error {
fn from(value: mpsc::SendError<libc::input_event>) -> Self {
Error::Send(value)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str(error::Error::description(self))
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self {
#[cfg(target_os = "linux")]
&Error::Nix(ref err) =>
err.description(),
&Error::Nix(ref err) => err.fmt(f),
&Error::Nul(ref err) =>
err.description(),
&Error::Nul(ref err) => err.fmt(f),
&Error::Io(ref err) =>
err.description(),
&Error::Io(ref err) => err.fmt(f),
#[cfg(target_os = "linux")]
&Error::Send(ref err) =>
err.description(),
#[cfg(feature = "toml_serde")]
&Error::Toml(ref err) => err.fmt(f),
&Error::NotAKeyboard => f.write_str("This device file is not a keyboard"),
&Error::NotFound =>
"Device not found.",
&Error::ShortRead =>
"Error while reading from device file.",
&Error::ShortRead => f.write_str("Error while reading from device file."),
&Error::EpollAlreadyAdded => f.write_str("epoll already added, delete first"),
}
}
}
impl error::Error for Error {}

View File

@ -1,11 +1,12 @@
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;
use std::hash::Hash;
use std::convert::TryFrom;
use crate::{Error, Result};
#[cfg(feature = "toml_serde")]
use std::path::Path;
use crate::Result;
const INVERT_KEY_FLAG: char = '^';
const CAPS_MODIFY_KEY_FLAG: char = '*';
@ -14,7 +15,7 @@ const HALF_KEY_SEPARATOR: char = ':';
// nightly only...
//pub trait KeyCode = Into<usize> + TryFrom<usize> + Copy + Clone + Eq + Hash + Default + 'static;
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum KeyState {
DOWN,
UP,
@ -31,7 +32,7 @@ pub trait KeyEvent<T>
pub trait Keyboard<T, E, R = ()>
where
T: Into<usize>,
T: Into<usize> + Copy,
E: KeyEvent<T>,
{
fn send(&self, event: &mut E) -> Result<R>;
@ -42,11 +43,52 @@ pub trait Keyboard<T, E, R = ()>
fn right_shift_code(&self) -> T;
fn caps_lock_code(&self) -> T;
fn block_key(&self) -> Result<R>;
fn send_half_inverted_key(&self, half_inverted_key: &HalfInvertedKey<T>, event: &mut E, left_shift: bool, right_shift: bool, caps_lock: bool) -> Result<R> {
let value = event.value();
let mut invert_shift = half_inverted_key.invert_shift;
if value == KeyState::DOWN {
if caps_lock && half_inverted_key.capslock_nomodify {
invert_shift = !invert_shift;
}
if invert_shift {
let (shift_code, up_not_down) = if left_shift {
(self.left_shift_code(), true)
} else if right_shift {
(self.right_shift_code(), true)
} else {
(self.left_shift_code(), false)
};
self.send_mod_code_value(shift_code, up_not_down, event)?;
// SYN_REPORT after, then key, then key's SYN_REPORT
self.synchronize()?;
}
}
let ret = self.send_mod_code(half_inverted_key.code, event)?;
if value == KeyState::UP {
if caps_lock && half_inverted_key.capslock_nomodify {
invert_shift = !invert_shift;
}
if invert_shift {
let (shift_code, up_not_down) = if left_shift {
(self.left_shift_code(), false)
} else if right_shift {
(self.right_shift_code(), false)
} else {
(self.left_shift_code(), true)
};
// SYN_REPORT first after key, then shift, then key's SYN_REPORT which will be used for shift's
self.synchronize()?;
self.send_mod_code_value(shift_code, up_not_down, event)?;
}
}
Ok(ret)
}
}
pub trait KeyMapper<K, T, E, R>
where
T: Into<usize>,
T: Into<usize> + Copy,
E: KeyEvent<T>,
K: Keyboard<T, E, R>,
{
@ -63,7 +105,7 @@ pub struct KeyMaps<K, T, E, R = ()>
keymap_index_keys: HashMap<T, usize>,
switch_layout_keys: Vec<usize>,
key_state: [bool; KEY_MAX],
revert_default_key: T,
revert_default_keys: Vec<T>,
revert_keymap_index: usize,
// above do not change, below does
chosen_keymap_index: usize,
@ -120,6 +162,7 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
E: KeyEvent<T>,
K: Keyboard<T, E, R>,
{
#[cfg(feature = "toml_serde")]
pub fn from_cfg<P: AsRef<Path>>(key_map: &HashMap<&'static str, T>, path: P) -> KeyMaps<K, T, E, R> {
let key_map_config = parse_cfg(path).expect("provided config cannot be found/parsed");
KeyMaps::new(key_map, key_map_config)
@ -147,8 +190,14 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
let mut keymap = KeyMap::new();
let mut i: usize = 0;
for key_code in v {
// todo: if these are the same, do Noop instead
keymap.map(base_keymap[i], key_code);
// if it's a direct key and it's the same, don't do any mapping
if let Key::Direct(key) = key_code {
if base_keymap[i] != key {
keymap.map(base_keymap[i], key_code);
}
} else {
keymap.map(base_keymap[i], key_code);
}
i = i + 1;
if i > base_keymap.len() {
panic!("all keymaps must be the same length, keymap index 0 length: {}, index {} length: {},", base_keymap.len(), x, i);
@ -161,7 +210,9 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
let mut keymap = CodeKeyMap::new();
let mut i: usize = 0;
for key_code in v {
keymap.map(base_keymap[i], key_code);
if base_keymap[i] != key_code {
keymap.map(base_keymap[i], key_code);
}
i = i + 1;
if i > base_keymap.len() {
panic!("all keymaps must be the same length, keymap index 0 length: {}, index {} length: {},", base_keymap.len(), x, i);
@ -173,13 +224,27 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
//println!("keymaps: {:?}", keymaps);
//println!("keymap_index_keys: {:?}", keymap_index_keys);
let mut revert_default_keys = Vec::new();
if config.revert_default_key.is_some() {
revert_default_keys.push(parse_key(key_map, &config.revert_default_key.unwrap()));
}
if config.revert_default_keys.is_some() {
for revert_default_key in config.revert_default_keys.unwrap() {
let revert_default_key = parse_key(key_map, &revert_default_key);
if !revert_default_keys.contains(&revert_default_key) {
revert_default_keys.push(revert_default_key);
}
}
}
// revert_default_keys may be empty, but that's ok
KeyMaps {
keymaps: keymaps,
keymap_index_keys: keymap_index_keys,
switch_layout_keys: config.switch_layout_keys.iter().map(|k| parse_key(key_map, k).into()).collect(),
key_state: [false; KEY_MAX],
// todo: detect key state? at least CAPSLOCK...
revert_default_key: parse_key(key_map, &config.revert_default_key),
revert_default_keys,
revert_keymap_index: config.revert_keymap_index,
chosen_keymap_index: config.default_keymap_index,
current_keymap_index: config.default_keymap_index,
@ -190,7 +255,6 @@ impl<K, T, E, R> KeyMaps<K, T, E, R>
//impl KeyMapper for KeyMaps {
//impl KeyMaps {
pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
//println!("type: {} code: {} value: {}", event.type_, event.code, event.value);
let value = event.value();
if value != KeyState::OTHER {
// todo: index check here...
@ -199,7 +263,12 @@ pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
self.key_state[device.caps_lock_code().into()] = !self.key_state[device.caps_lock_code().into()];
}
} else {
self.key_state[event.code().into()] = value == KeyState::DOWN;
let idx = event.code().into();
if idx >= KEY_MAX {
// oh well, send it directly then
return device.send(event);
}
self.key_state[idx] = value == KeyState::DOWN;
}
let mut switch_layout_keys_pressed = true;
for layout_switch_key in self.switch_layout_keys.iter_mut() {
@ -217,11 +286,27 @@ pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
return device.block_key(); // we don't want to also send this keypress, so bail
}
}
if event.code() == self.revert_default_key {
if self.revert_default_keys.contains(&event.code()) {
match value {
// todo: ctrl+c will get c stuck because code c value 1 will be sent, but then we'll let go of ctrl, and code j value 0 is sent, so c is never released... fix that...
KeyState::DOWN => self.current_keymap_index = self.revert_keymap_index,
KeyState::UP => self.current_keymap_index = self.chosen_keymap_index,
KeyState::DOWN => {
// todo: should we release currently held keys and then press them back down here, kinda the opposite of below? not for now...
self.current_keymap_index = self.revert_keymap_index
},
KeyState::UP => {
self.current_keymap_index = self.chosen_keymap_index;
#[cfg(not(target_os = "macos"))] {
// need to release all currently held down keys, except this one, otherwise ctrl+c will get c stuck because code c value 1 will be sent, but then we'll let go of ctrl, and code j value 0 is sent, so c is never released
let orig_code = event.code();
for (idx, key_down) in self.key_state.iter_mut().enumerate() {
if *key_down {
device.send_mod_code_value(T::try_from(idx).unwrap_or_else(|_| panic!("cannot convert from usize to T ????")), true, event)?;
*key_down = false;
}
}
// todo: seems like we should not send this here, and instead just set the original code back, and pass it through the keymaps?
return device.send_mod_code_value(orig_code, true, event)
}
},
_ => () // do nothing for 2
}
}
@ -234,42 +319,16 @@ pub fn send_event(&mut self, mut event: &mut E, device: &K) -> Result<R> {
const KEY_MAX: usize = 249;
struct KeyMap<T: Into<usize> + Copy> {
//keymap: Vec<Key>,
keymap: [Key<T>; KEY_MAX],
}
impl<T: Into<usize> + Copy> KeyMap<T> {
pub fn new() -> Self {
//let mut keymap = [0u16; KEY_MAX];
//let mut keymap : [Box<KeyMapper>; KEY_MAX] = [Box::new(NOOP); KEY_MAX];
//let mut keymap : [Box<KeyMapper>; KEY_MAX] = [Box::new(0u16); KEY_MAX];
let keymap: [Key<T>; KEY_MAX] = [Key::Noop; KEY_MAX];
/*
let mut keymap: Vec<Key> = Vec::with_capacity(KEY_MAX);
#[allow(unused_variables)]
for x in 0..KEY_MAX {
keymap.push(Key::Noop);
}
*/
// which is rustier
/*
for x in 0..KEY_MAX {
keymap[x as usize] = x as u16;
}
for (x, v) in keymap.iter_mut().enumerate() {
*v = x as u16;
}
*/
//println!("keymap: {:?}", &keymap[..]);
KeyMap {
keymap: keymap
keymap: [Key::Noop; KEY_MAX]
}
}
/*
pub fn map(&mut self, from : u16, to: u16) {
self.keymap[from as usize] = to;
}
*/
pub fn map(&mut self, from: T, to: Key<T>) {
self.keymap[from.into()] = to;
}
@ -287,25 +346,18 @@ impl<K, T, E, R> KeyMapper<K, T, E, R> for KeyMap<T>
}
struct CodeKeyMap<T: Into<usize> + TryFrom<usize> + Copy + Default> {
//keymap: Vec<Key>,
keymap: [T; KEY_MAX],
}
impl<T: Into<usize> + TryFrom<usize> + Copy + Default> CodeKeyMap<T> {
pub fn new() -> Self {
let mut keymap = [T::default(); KEY_MAX];
// which is rustier
/*
for x in 0..KEY_MAX {
keymap[x as usize] = x as u16;
}
*/
for (x, v) in keymap.iter_mut().enumerate() {
*v = T::try_from(x).unwrap_or_else(|_| panic!("cannot convert from usize to T ????"));
}
//println!("keymap: {:?}", &keymap[..]);
CodeKeyMap {
keymap: keymap
keymap
}
}
@ -328,61 +380,15 @@ impl<K, T, E, R> KeyMapper<K, T, E, R> for CodeKeyMap<T>
// todo:capslock_nomodify is like a whole-key thing, not a half-key thing, split code/invert_shift to own struct, send into send_key from *InvertedKey, maybe anyway, consider it, maybe 1 char for whole key and another for half?
#[derive(Clone, Copy)]
struct HalfInvertedKey<T: Clone + Copy> {
code: T,
pub struct HalfInvertedKey<T: Clone + Copy> {
pub code: T,
// code this is describing
invert_shift: bool,
pub invert_shift: bool,
// true to invert shift for this code
capslock_nomodify: bool,
pub capslock_nomodify: bool,
// true means capslock does not normally modify this, but you would like it to
}
fn send_half_inverted_key<K, T, E, R>(half_inverted_key: &HalfInvertedKey<T>, event: &mut E, device: &K, left_shift: bool, right_shift: bool, caps_lock: bool) -> Result<R>
where
T: Into<usize> + Clone + Copy,
E: KeyEvent<T>,
K: Keyboard<T, E, R>,
{
let value = event.value();
let mut invert_shift = half_inverted_key.invert_shift;
if value == KeyState::DOWN {
if caps_lock && half_inverted_key.capslock_nomodify {
invert_shift = !invert_shift;
}
if invert_shift {
let (shift_code, up_not_down) = if left_shift {
(device.left_shift_code(), true)
} else if right_shift {
(device.right_shift_code(), true)
} else {
(device.left_shift_code(), false)
};
device.send_mod_code_value(shift_code, up_not_down, event)?;
// SYN_REPORT after, then key, then key's SYN_REPORT
device.synchronize()?;
}
}
let ret = device.send_mod_code(half_inverted_key.code, event)?;
if value == KeyState::UP {
if caps_lock && half_inverted_key.capslock_nomodify {
invert_shift = !invert_shift;
}
if invert_shift {
let (shift_code, up_not_down) = if left_shift {
(device.left_shift_code(), false)
} else if right_shift {
(device.right_shift_code(), false)
} else {
(device.left_shift_code(), true)
};
// SYN_REPORT first after key, then shift, then key's SYN_REPORT which will be used for shift's
device.synchronize()?;
device.send_mod_code_value(shift_code, up_not_down, event)?;
}
}
Ok(ret)
}
impl<K, T, E, R> KeyMapper<K, T, E, R> for HalfInvertedKey<T>
where
T: Into<usize> + Clone + Copy,
@ -393,7 +399,7 @@ impl<K, T, E, R> KeyMapper<K, T, E, R> for HalfInvertedKey<T>
let left_shift = key_state[device.left_shift_code().into()];
let right_shift = key_state[device.right_shift_code().into()];
let caps_lock = key_state[device.caps_lock_code().into()];
send_half_inverted_key(self, event, device, left_shift, right_shift, caps_lock)
device.send_half_inverted_key(self, event, left_shift, right_shift, caps_lock)
}
}
@ -430,34 +436,96 @@ impl<K, T, E, R> KeyMapper<K, T, E, R> for Key<T>
let right_shift = key_state[device.right_shift_code().into()];
let caps_lock = key_state[device.caps_lock_code().into()];
if caps_lock != (left_shift || right_shift) {
send_half_inverted_key(shift_half, event, device, left_shift, right_shift, caps_lock)
device.send_half_inverted_key(shift_half, event, left_shift, right_shift, caps_lock)
} else {
send_half_inverted_key(noshift_half, event, device, left_shift, right_shift, caps_lock)
device.send_half_inverted_key(noshift_half, event, left_shift, right_shift, caps_lock)
}
},
}
}
}
use std::path::Path;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[cfg(feature = "toml_serde")]
#[derive(serde::Deserialize, Debug)]
pub struct KeymapConfig {
switch_layout_keys: Vec<String>,
revert_default_key: String,
revert_default_key: Option<String>,
revert_default_keys: Option<Vec<String>>,
revert_keymap_index: usize,
default_keymap_index: usize,
keymaps: Vec<String>
}
#[cfg(feature = "toml_serde")]
fn parse_cfg<P: AsRef<Path>>(path: P) -> Result<KeymapConfig> {
let mut f = File::open(path)?;
use std::io::Read;
let mut f = std::fs::File::open(path)?;
let mut input = String::new();
f.read_to_string(&mut input)?;
//toml::from_str(&input)?
match toml::from_str(&input) {
Ok(toml) => Ok(toml),
Err(_) => Err(Error::NotFound) // todo: something better
toml::from_str(&input).map_err(|e| crate::Error::Toml(e))
}
#[cfg(not(feature = "toml_serde"))]
#[derive(Debug)]
pub struct KeymapConfig {
switch_layout_keys: Vec<&'static str>,
revert_default_key: Option<&'static str>,
revert_default_keys: Option<Vec<&'static str>>,
revert_keymap_index: usize,
default_keymap_index: usize,
keymaps: Vec<&'static str>
}
#[cfg(not(feature = "toml_serde"))]
impl Default for KeymapConfig {
fn default() -> Self {
KeymapConfig {
switch_layout_keys: vec!["LEFTSHIFT", "RIGHTSHIFT"],
// pressing any of these keys reverts to the index specified in revert_keymap_index for only the duration of the pressing
// used so QWERTY shortcuts like Ctrl+C still work
revert_default_keys: Some(vec!["LCTL", "LGUI", "LALT"]),
revert_keymap_index: 0,
// this is the default index to use when the program first starts
// in this case, 2 means Unix Programmer Dvorak
default_keymap_index: 2,
// these are the keymaps available, you can add as many as you want or re-order them, just be aware the mapping is
// always done from the first one to all subsequent ones, so you probably want to leave QWERTY or similar up top
keymaps: vec![
// default key layout, QWERTY in this case
r###"
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
"###,
// Dvorak http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard
// https://www.moparisthebest.com/kbs/standard-dvorak-QwertySecondary.svg
r###"
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, LBRC,RBRC,BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
TAB, QUOT,COMM,DOT, P, Y, F, G, C, R, L, SLSH,EQL, BSLS, DEL, END, PGDN, P7, P8, P9,
CAPS,A, O, E, U, I, D, H, T, N, S, MINS, ENT, P4, P5, P6, PPLS,
LSFT,SCLN,Q, J, K, X, B, M, W, V, Z, RSFT, UP, P1, P2, P3,
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
"###,
// Unix Programmer Dvorak - for unix developers who are switching from dvorak
// https://www.moparisthebest.com/kbs/programmer-dvorak-NoSecondary-NumpadStandard-NoSwap-StandardNums-SwapAt-SwapPipe.svg
r###"
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK,
*^4:*^GRV, *^7:*1, *LBRC:*2, *^LBRC:*3, *^RBRC:*4, *^9:*5, *^2:*6, *^8:*7, *^0:*8, *^EQL:*9, *RBRC:*0, *^1:*^5, *^3:*GRV, BSPC, INS, HOME,PGUP, NLCK, *PSLS:*^9, *PAST:*^0, *PMNS:*^4,
TAB, *QUOT, *COMM, *DOT, P, Y, F, G, C, R, L, *SLSH, *EQL:*^6, *^BSLS, DEL, END, PGDN, *P7:^A, *P8:^B, *P9:^C,
CAPS, A, O, E, U, I, D, H, T, N, S, *MINS, ENT, *P4:^D, *P5:^E, *P6:^F, *PPLS:*COMM,
LSFT, *SCLN, Q, J, K, X, B, M, W, V, Z, RSFT, UP, *P1:*EQL, *P2:X, *P3:*^SCLN,
LCTL, LGUI, LALT, SPC, RALT, RGUI, APP, RCTL, LEFT,DOWN,RGHT, *P0:*BSLS, *PDOT:*SCLN, PENT
"###,
],
revert_default_key: None, // use revert_default_keys instead
}
}
}

View File

@ -1,5 +1,6 @@
#![recursion_limit = "1000"]
pub const NAME: &'static str = env!("CARGO_PKG_NAME");
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub mod error;
@ -15,7 +16,6 @@ mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;
/*
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
@ -25,7 +25,3 @@ pub use linux::*;
mod macos;
#[cfg(target_os = "macos")]
pub use macos::*;
*/
mod macos;
pub use macos::*;

View File

@ -2,11 +2,42 @@ use std::path::Path;
use std::{mem, slice};
use std::ffi::CString;
use libc::c_int;
use nix::{self, fcntl, unistd, errno::Errno};
use nix::{self, fcntl, unistd, ioctl_write_ptr, ioctl_none};
use nix::sys::stat;
use uinput_sys::*;
use crate::{Result as Res, Device};
use crate::{Result, Device};
use std::collections::hash_map::Values;
use std::os::raw::c_char;
use crate::linux::device::codes::*;
ioctl_write_ptr!(ui_set_evbit, b'U', 100, c_int);
ioctl_write_ptr!(ui_set_keybit, b'U', 101, c_int);
ioctl_none!(ui_dev_create, b'U', 1);
pub const UINPUT_MAX_NAME_SIZE: c_int = 80;
pub const ABS_MAX: c_int = 0x3f;
pub const ABS_CNT: c_int = ABS_MAX + 1;
#[derive(Clone, Copy)]
#[repr(C)]
pub struct input_id {
pub bustype: u16,
pub vendor: u16,
pub product: u16,
pub version: u16,
}
#[repr(C)]
pub struct uinput_user_dev {
pub name: [c_char; UINPUT_MAX_NAME_SIZE as usize],
pub id: input_id,
pub ff_effects_max: u32,
pub absmax: [i32; ABS_CNT as usize],
pub absmin: [i32; ABS_CNT as usize],
pub absfuzz: [i32; ABS_CNT as usize],
pub absflat: [i32; ABS_CNT as usize],
}
/// Device builder.
pub struct Builder {
@ -17,7 +48,7 @@ pub struct Builder {
impl Builder {
/// Create a builder from the specified path.
pub fn open<P: AsRef<Path>>(path: P) -> Res<Self> {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
Ok(Builder {
fd: fcntl::open(path.as_ref(), fcntl::OFlag::O_WRONLY | fcntl::OFlag::O_NONBLOCK, stat::Mode::empty())?,
def: unsafe { mem::zeroed() },
@ -26,17 +57,17 @@ impl Builder {
}
/// Create a builder from `/dev/uinput`.
pub fn default() -> Res<Self> {
pub fn default() -> Result<Self> {
Builder::open("/dev/uinput")
}
/// Set the name.
pub fn name<T: AsRef<str>>(mut self, value: T) -> Res<Self> {
pub fn name<T: AsRef<str>>(mut self, value: T) -> Result<Self> {
let string = CString::new(value.as_ref())?;
let bytes = string.as_bytes_with_nul();
if bytes.len() > UINPUT_MAX_NAME_SIZE as usize {
Err(nix::Error::from_errno(Errno::EINVAL))?;
Err(nix::Error::EINVAL)?;
}
(&mut self.def.name)[..bytes.len()]
@ -69,164 +100,18 @@ impl Builder {
self
}
pub fn event(mut self, key_codes: Values<&str, u16>) -> Res<Self> {
pub fn event(mut self, key_codes: Values<&str, u16>) -> Result<Self> {
self.abs = None;
//let test_ev_key : c_int = EV_KEY as c_int;
unsafe {
//try!(Errno::result(ui_set_evbit(self.fd, EV_KEY)));
//try!(Errno::result(ui_set_keybit(self.fd, KEY_H)));
Errno::result(ui_set_evbit(self.fd, EV_KEY as i32))?;
//ui_set_keybit(self.fd, KEY_H as *const c_int)?;
ui_set_evbit(self.fd, EV_KEY as *const c_int)?;
for key_code in key_codes {
Errno::result(ui_set_keybit(self.fd, *key_code as i32))?;
ui_set_keybit(self.fd, *key_code as *const c_int)?;
}
//try!(ui_set_keybit(self.fd, &KEY_H));
}
Ok(self)
}
/*
/// Enable the given event.
pub fn event<T: Into<Event>>(mut self, value: T) -> Res<Self> {
self.abs = None;
match value.into() {
Event::All => {
try!(self.event(Event::Keyboard(event::Keyboard::All)))
.event(Event::Controller(event::Controller::All))
}
Event::Keyboard(value) => {
match value {
event::Keyboard::All => {
let mut builder = self;
for item in event::keyboard::Key::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::KeyPad::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Misc::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::InputAssist::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Function::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Braille::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Numeric::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::TouchPad::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Camera::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::keyboard::Attendant::iter_variants() {
builder = try!(builder.event(item));
}
Ok(builder)
}
value => {
unsafe {
try!(Errno::result(ui_set_evbit(self.fd, value.kind())));
try!(Errno::result(ui_set_keybit(self.fd, value.code())));
}
Ok(self)
}
}
}
Event::Controller(value) => {
match value {
event::Controller::All => {
let mut builder = self;
for item in event::controller::Misc::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::Mouse::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::JoyStick::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::GamePad::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::Digi::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::Wheel::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::DPad::iter_variants() {
builder = try!(builder.event(item));
}
for item in event::controller::TriggerHappy::iter_variants() {
builder = try!(builder.event(item));
}
Ok(builder)
}
value => {
unsafe {
try!(Errno::result(ui_set_evbit(self.fd, value.kind())));
try!(Errno::result(ui_set_keybit(self.fd, value.code())));
}
Ok(self)
}
}
}
Event::Relative(value) => {
unsafe {
try!(Errno::result(ui_set_evbit(self.fd, value.kind())));
try!(Errno::result(ui_set_relbit(self.fd, value.code())));
}
Ok(self)
}
Event::Absolute(value) => {
unsafe {
try!(Errno::result(ui_set_evbit(self.fd, value.kind())));
try!(Errno::result(ui_set_absbit(self.fd, value.code())));
}
self.abs = Some(value.code());
Ok(self)
}
}
}
*/
/// Set the maximum value for the previously enabled absolute event.
pub fn max(mut self, value: i32) -> Self {
self.def.absmax[self.abs.unwrap() as usize] = value;
@ -252,15 +137,13 @@ impl Builder {
}
/// Create the defined device.
pub fn create(self) -> Res<Device> {
pub fn create(self) -> Result<Device> {
unsafe {
let ptr = &self.def as *const _ as *const u8;
let size = mem::size_of_val(&self.def);
unistd::write(self.fd, slice::from_raw_parts(ptr, size))?;
//todo: try!(Errno::result(ui_dev_create(self.fd)));
// try1: Errno::result(ui_dev_create(self.fd)).unwrap();
Errno::result(ui_dev_create(self.fd))?;
ui_dev_create(self.fd)?;
}
Ok(Device::new(self.fd))

780
src/linux/device/codes.rs Normal file
View File

@ -0,0 +1,780 @@
use libc::{c_int};
pub const INPUT_PROP_POINTER: c_int = 0x00; /* needs a pointer */
pub const INPUT_PROP_DIRECT: c_int = 0x01; /* direct input devices */
pub const INPUT_PROP_BUTTONPAD: c_int = 0x02; /* has button: c_int = s under pad */
pub const INPUT_PROP_SEMI_MT: c_int = 0x03; /* touch rectangle only */
pub const INPUT_PROP_TOPBUTTONPAD: c_int = 0x04; /* softbuttons at top of pad */
pub const INPUT_PROP_POINTING_STICK: c_int = 0x05; /* is a pointing stick */
pub const INPUT_PROP_ACCELEROMETER: c_int = 0x06; /* has accelerometer */
pub const INPUT_PROP_MAX: c_int = 0x1f;
pub const INPUT_PROP_CNT: c_int = INPUT_PROP_MAX + 1;
/*
* Event types
*/
pub const EV_SYN: c_int = 0x00;
pub const EV_KEY: c_int = 0x01;
pub const EV_REL: c_int = 0x02;
pub const EV_ABS: c_int = 0x03;
pub const EV_MSC: c_int = 0x04;
pub const EV_SW: c_int = 0x05;
pub const EV_LED: c_int = 0x11;
pub const EV_SND: c_int = 0x12;
pub const EV_REP: c_int = 0x14;
pub const EV_FF: c_int = 0x15;
pub const EV_PWR: c_int = 0x16;
pub const EV_FF_STATUS: c_int = 0x17;
pub const EV_MAX: c_int = 0x1f;
pub const EV_CNT: c_int = EV_MAX + 1;
/*
* Synchronization events.
*/
pub const SYN_REPORT: c_int = 0;
pub const SYN_CONFIG: c_int = 1;
pub const SYN_MT_REPORT: c_int = 2;
pub const SYN_DROPPED: c_int = 3;
pub const SYN_MAX: c_int = 0xf;
pub const SYN_CNT: c_int = SYN_MAX + 1;
/*
* Keys and buttons
*
* Most of the keys/buttons are modeled after USB HUT 1.12 (see
* http://www.usb.org/developers/hidpage).
* Abbreviations in the comments:
* AC - Application Control
* AL - Application Launch Button
* SC - System Control
*/
pub const KEY_RESERVED: c_int = 0;
pub const KEY_ESC: c_int = 1;
pub const KEY_1: c_int = 2;
pub const KEY_2: c_int = 3;
pub const KEY_3: c_int = 4;
pub const KEY_4: c_int = 5;
pub const KEY_5: c_int = 6;
pub const KEY_6: c_int = 7;
pub const KEY_7: c_int = 8;
pub const KEY_8: c_int = 9;
pub const KEY_9: c_int = 10;
pub const KEY_10: c_int = 11;
pub const KEY_MINUS: c_int = 12;
pub const KEY_EQUAL: c_int = 13;
pub const KEY_BACKSPACE: c_int = 14;
pub const KEY_TAB: c_int = 15;
pub const KEY_Q: c_int = 16;
pub const KEY_W: c_int = 17;
pub const KEY_E: c_int = 18;
pub const KEY_R: c_int = 19;
pub const KEY_T: c_int = 20;
pub const KEY_Y: c_int = 21;
pub const KEY_U: c_int = 22;
pub const KEY_I: c_int = 23;
pub const KEY_O: c_int = 24;
pub const KEY_P: c_int = 25;
pub const KEY_LEFTBRACE: c_int = 26;
pub const KEY_RIGHTBRACE: c_int = 27;
pub const KEY_ENTER: c_int = 28;
pub const KEY_LEFTCTRL: c_int = 29;
pub const KEY_A: c_int = 30;
pub const KEY_S: c_int = 31;
pub const KEY_D: c_int = 32;
pub const KEY_F: c_int = 33;
pub const KEY_G: c_int = 34;
pub const KEY_H: c_int = 35;
pub const KEY_J: c_int = 36;
pub const KEY_K: c_int = 37;
pub const KEY_L: c_int = 38;
pub const KEY_SEMICOLON: c_int = 39;
pub const KEY_APOSTROPHE: c_int = 40;
pub const KEY_GRAVE: c_int = 41;
pub const KEY_LEFTSHIFT: c_int = 42;
pub const KEY_BACKSLASH: c_int = 43;
pub const KEY_Z: c_int = 44;
pub const KEY_X: c_int = 45;
pub const KEY_C: c_int = 46;
pub const KEY_V: c_int = 47;
pub const KEY_B: c_int = 48;
pub const KEY_N: c_int = 49;
pub const KEY_M: c_int = 50;
pub const KEY_COMMA: c_int = 51;
pub const KEY_DOT: c_int = 52;
pub const KEY_SLASH: c_int = 53;
pub const KEY_RIGHTSHIFT: c_int = 54;
pub const KEY_KPASTERISK: c_int = 55;
pub const KEY_LEFTALT: c_int = 56;
pub const KEY_SPACE: c_int = 57;
pub const KEY_CAPSLOCK: c_int = 58;
pub const KEY_F1: c_int = 59;
pub const KEY_F2: c_int = 60;
pub const KEY_F3: c_int = 61;
pub const KEY_F4: c_int = 62;
pub const KEY_F5: c_int = 63;
pub const KEY_F6: c_int = 64;
pub const KEY_F7: c_int = 65;
pub const KEY_F8: c_int = 66;
pub const KEY_F9: c_int = 67;
pub const KEY_F10: c_int = 68;
pub const KEY_NUMLOCK: c_int = 69;
pub const KEY_SCROLLLOCK: c_int = 70;
pub const KEY_KP7: c_int = 71;
pub const KEY_KP8: c_int = 72;
pub const KEY_KP9: c_int = 73;
pub const KEY_KPMINUS: c_int = 74;
pub const KEY_KP4: c_int = 75;
pub const KEY_KP5: c_int = 76;
pub const KEY_KP6: c_int = 77;
pub const KEY_KPPLUS: c_int = 78;
pub const KEY_KP1: c_int = 79;
pub const KEY_KP2: c_int = 80;
pub const KEY_KP3: c_int = 81;
pub const KEY_KP0: c_int = 82;
pub const KEY_KPDOT: c_int = 83;
pub const KEY_ZENKAKUHANKAKU: c_int = 85;
pub const KEY_102ND: c_int = 86;
pub const KEY_F11: c_int = 87;
pub const KEY_F12: c_int = 88;
pub const KEY_RO: c_int = 89;
pub const KEY_KATAKANA: c_int = 90;
pub const KEY_HIRAGANA: c_int = 91;
pub const KEY_HENKAN: c_int = 92;
pub const KEY_KATAKANAHIRAGANA: c_int = 93;
pub const KEY_MUHENKAN: c_int = 94;
pub const KEY_KPJPCOMMA: c_int = 95;
pub const KEY_KPENTER: c_int = 96;
pub const KEY_RIGHTCTRL: c_int = 97;
pub const KEY_KPSLASH: c_int = 98;
pub const KEY_SYSRQ: c_int = 99;
pub const KEY_RIGHTALT: c_int = 100;
pub const KEY_LINEFEED: c_int = 101;
pub const KEY_HOME: c_int = 102;
pub const KEY_UP: c_int = 103;
pub const KEY_PAGEUP: c_int = 104;
pub const KEY_LEFT: c_int = 105;
pub const KEY_RIGHT: c_int = 106;
pub const KEY_END: c_int = 107;
pub const KEY_DOWN: c_int = 108;
pub const KEY_PAGEDOWN: c_int = 109;
pub const KEY_INSERT: c_int = 110;
pub const KEY_DELETE: c_int = 111;
pub const KEY_MACRO: c_int = 112;
pub const KEY_MUTE: c_int = 113;
pub const KEY_VOLUMEDOWN: c_int = 114;
pub const KEY_VOLUMEUP: c_int = 115;
pub const KEY_POWER: c_int = 116; /* SC System Power Down */
pub const KEY_KPEQUAL: c_int = 117;
pub const KEY_KPPLUSMINUS: c_int = 118;
pub const KEY_PAUSE: c_int = 119;
pub const KEY_SCALE: c_int = 120; /* AL Compiz Scale : c_int = Expose */
pub const KEY_KPCOMMA: c_int = 121;
pub const KEY_HANGEUL: c_int = 122;
pub const KEY_HANGUEL: c_int = KEY_HANGEUL;
pub const KEY_HANJA: c_int = 123;
pub const KEY_YEN: c_int = 124;
pub const KEY_LEFTMETA: c_int = 125;
pub const KEY_RIGHTMETA: c_int = 126;
pub const KEY_COMPOSE: c_int = 127;
pub const KEY_STOP: c_int = 128; /* AC Stop */
pub const KEY_AGAIN: c_int = 129;
pub const KEY_PROPS: c_int = 130; /* AC Properties */
pub const KEY_UNDO: c_int = 131; /* AC Undo */
pub const KEY_FRONT: c_int = 132;
pub const KEY_COPY: c_int = 133; /* AC Copy */
pub const KEY_OPEN: c_int = 134; /* AC Open */
pub const KEY_PASTE: c_int = 135; /* AC Paste */
pub const KEY_FIND: c_int = 136; /* AC Search */
pub const KEY_CUT: c_int = 137; /* AC Cut */
pub const KEY_HELP: c_int = 138; /* AL Integrated Help Center */
pub const KEY_MENU: c_int = 139; /* Menu : c_int = show menu */
pub const KEY_CALC: c_int = 140; /* AL Calculator */
pub const KEY_SETUP: c_int = 141;
pub const KEY_SLEEP: c_int = 142; /* SC System Sleep */
pub const KEY_WAKEUP: c_int = 143; /* System Wake Up */
pub const KEY_FILE: c_int = 144; /* AL Local Machine Browser */
pub const KEY_SENDFILE: c_int = 145;
pub const KEY_DELETEFILE: c_int = 146;
pub const KEY_XFER: c_int = 147;
pub const KEY_PROG1: c_int = 148;
pub const KEY_PROG2: c_int = 149;
pub const KEY_WWW: c_int = 150; /* AL Internet Browser */
pub const KEY_MSDOS: c_int = 151;
pub const KEY_COFFEE: c_int = 152; /* AL Terminal Lock/Screensaver */
pub const KEY_SCREENLOCK: c_int = KEY_COFFEE;
pub const KEY_ROTATE_DISPLAY: c_int = 153; /* Display orientation for e.g. tablets */
pub const KEY_DIRECTION: c_int = KEY_ROTATE_DISPLAY;
pub const KEY_CYCLEWINDOWS: c_int = 154;
pub const KEY_MAIL: c_int = 155;
pub const KEY_BOOKMARKS: c_int = 156; /* AC Bookmarks */
pub const KEY_COMPUTER: c_int = 157;
pub const KEY_BACK: c_int = 158; /* AC Back */
pub const KEY_FORWARD: c_int = 159; /* AC Forward */
pub const KEY_CLOSECD: c_int = 160;
pub const KEY_EJECTCD: c_int = 161;
pub const KEY_EJECTCLOSECD: c_int = 162;
pub const KEY_NEXTSONG: c_int = 163;
pub const KEY_PLAYPAUSE: c_int = 164;
pub const KEY_PREVIOUSSONG: c_int = 165;
pub const KEY_STOPCD: c_int = 166;
pub const KEY_RECORD: c_int = 167;
pub const KEY_REWIND: c_int = 168;
pub const KEY_PHONE: c_int = 169; /* Media Select Telephone */
pub const KEY_ISO: c_int = 170;
pub const KEY_CONFIG: c_int = 171; /* AL Consumer Control Configuration */
pub const KEY_HOMEPAGE: c_int = 172; /* AC Home */
pub const KEY_REFRESH: c_int = 173; /* AC Refresh */
pub const KEY_EXIT: c_int = 174; /* AC Exit */
pub const KEY_MOVE: c_int = 175;
pub const KEY_EDIT: c_int = 176;
pub const KEY_SCROLLUP: c_int = 177;
pub const KEY_SCROLLDOWN: c_int = 178;
pub const KEY_KPLEFTPAREN: c_int = 179;
pub const KEY_KPRIGHTPAREN: c_int = 180;
pub const KEY_NEW: c_int = 181; /* AC New */
pub const KEY_REDO: c_int = 182; /* AC Redo/Repeat */
pub const KEY_F13: c_int = 183;
pub const KEY_F14: c_int = 184;
pub const KEY_F15: c_int = 185;
pub const KEY_F16: c_int = 186;
pub const KEY_F17: c_int = 187;
pub const KEY_F18: c_int = 188;
pub const KEY_F19: c_int = 189;
pub const KEY_F20: c_int = 190;
pub const KEY_F21: c_int = 191;
pub const KEY_F22: c_int = 192;
pub const KEY_F23: c_int = 193;
pub const KEY_F24: c_int = 194;
pub const KEY_PLAYCD: c_int = 200;
pub const KEY_PAUSECD: c_int = 201;
pub const KEY_PROG3: c_int = 202;
pub const KEY_PROG4: c_int = 203;
pub const KEY_DASHBOARD: c_int = 204; /* AL Dashboard */
pub const KEY_SUSPEND: c_int = 205;
pub const KEY_CLOSE: c_int = 206; /* AC Close */
pub const KEY_PLAY: c_int = 207;
pub const KEY_FASTFORWARD: c_int = 208;
pub const KEY_BASSBOOST: c_int = 209;
pub const KEY_PRINT: c_int = 210; /* AC Print */
pub const KEY_HP: c_int = 211;
pub const KEY_CAMERA: c_int = 212;
pub const KEY_SOUND: c_int = 213;
pub const KEY_QUESTION: c_int = 214;
pub const KEY_EMAIL: c_int = 215;
pub const KEY_CHAT: c_int = 216;
pub const KEY_SEARCH: c_int = 217;
pub const KEY_CONNECT: c_int = 218;
pub const KEY_FINANCE: c_int = 219; /* AL Checkbook/Finance */
pub const KEY_SPORT: c_int = 220;
pub const KEY_SHOP: c_int = 221;
pub const KEY_ALTERASE: c_int = 222;
pub const KEY_CANCEL: c_int = 223; /* AC Cancel */
pub const KEY_BRIGHTNESSDOWN: c_int = 224;
pub const KEY_BRIGHTNESSUP: c_int = 225;
pub const KEY_MEDIA: c_int = 226;
pub const KEY_SWITCHVIDEOMODE: c_int = 227; /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
pub const KEY_KBDILLUMTOGGLE: c_int = 228;
pub const KEY_KBDILLUMDOWN: c_int = 229;
pub const KEY_KBDILLUMUP: c_int = 230;
pub const KEY_SEND: c_int = 231; /* AC Send */
pub const KEY_REPLY: c_int = 232; /* AC Reply */
pub const KEY_FORWARDMAIL: c_int = 233; /* AC Forward Msg */
pub const KEY_SAVE: c_int = 234; /* AC Save */
pub const KEY_DOCUMENTS: c_int = 235;
pub const KEY_BATTERY: c_int = 236;
pub const KEY_BLUETOOTH: c_int = 237;
pub const KEY_WLAN: c_int = 238;
pub const KEY_UWB: c_int = 239;
pub const KEY_UNKNOWN: c_int = 240;
pub const KEY_VIDEO_NEXT: c_int = 241; /* drive next video source */
pub const KEY_VIDEO_PREV: c_int = 242; /* drive previous video source */
pub const KEY_BRIGHTNESS_CYCLE: c_int = 243; /* brightness up, after max is min */
pub const KEY_BRIGHTNESS_AUTO: c_int = 244; /* Set Auto Brightness: manual brightness control is off, rely on ambient */
pub const KEY_BRIGHTNESS_ZERO: c_int = KEY_BRIGHTNESS_AUTO;
pub const KEY_DISPLAY_OFF: c_int = 245; /* display device to off state */
pub const KEY_WWAN: c_int = 246; /* Wireless WAN : c_int = LTE, UMTS, GSM, etc. */
pub const KEY_WIMAX: c_int = KEY_WWAN;
pub const KEY_RFKILL: c_int = 247; /* Key that controls all radios */
pub const KEY_MICMUTE: c_int = 248; /* Mute / unmute the microphone */
/* Code 255 is reserved for special needs of AT keyboard driver */
pub const BTN_MISC: c_int = 0x100;
pub const BTN_0: c_int = 0x100;
pub const BTN_1: c_int = 0x101;
pub const BTN_2: c_int = 0x102;
pub const BTN_3: c_int = 0x103;
pub const BTN_4: c_int = 0x104;
pub const BTN_5: c_int = 0x105;
pub const BTN_6: c_int = 0x106;
pub const BTN_7: c_int = 0x107;
pub const BTN_8: c_int = 0x108;
pub const BTN_9: c_int = 0x109;
pub const BTN_MOUSE: c_int = 0x110;
pub const BTN_LEFT: c_int = 0x110;
pub const BTN_RIGHT: c_int = 0x111;
pub const BTN_MIDDLE: c_int = 0x112;
pub const BTN_SIDE: c_int = 0x113;
pub const BTN_EXTRA: c_int = 0x114;
pub const BTN_FORWARD: c_int = 0x115;
pub const BTN_BACK: c_int = 0x116;
pub const BTN_TASK: c_int = 0x117;
pub const BTN_JOYSTICK: c_int = 0x120;
pub const BTN_TRIGGER: c_int = 0x120;
pub const BTN_THUMB: c_int = 0x121;
pub const BTN_THUMB2: c_int = 0x122;
pub const BTN_TOP: c_int = 0x123;
pub const BTN_TOP2: c_int = 0x124;
pub const BTN_PINKIE: c_int = 0x125;
pub const BTN_BASE: c_int = 0x126;
pub const BTN_BASE2: c_int = 0x127;
pub const BTN_BASE3: c_int = 0x128;
pub const BTN_BASE4: c_int = 0x129;
pub const BTN_BASE5: c_int = 0x12a;
pub const BTN_BASE6: c_int = 0x12b;
pub const BTN_DEAD: c_int = 0x12f;
pub const BTN_GAMEPAD: c_int = 0x130;
pub const BTN_SOUTH: c_int = 0x130;
pub const BTN_A: c_int = BTN_SOUTH;
pub const BTN_EAST: c_int = 0x131;
pub const BTN_B: c_int = BTN_EAST;
pub const BTN_C: c_int = 0x132;
pub const BTN_NORTH: c_int = 0x133;
pub const BTN_X: c_int = BTN_NORTH;
pub const BTN_WEST: c_int = 0x134;
pub const BTN_Y: c_int = BTN_WEST;
pub const BTN_Z: c_int = 0x135;
pub const BTN_TL: c_int = 0x136;
pub const BTN_TR: c_int = 0x137;
pub const BTN_TL2: c_int = 0x138;
pub const BTN_TR2: c_int = 0x139;
pub const BTN_SELECT: c_int = 0x13a;
pub const BTN_START: c_int = 0x13b;
pub const BTN_MODE: c_int = 0x13c;
pub const BTN_THUMBL: c_int = 0x13d;
pub const BTN_THUMBR: c_int = 0x13e;
pub const BTN_DIGI: c_int = 0x140;
pub const BTN_TOOL_PEN: c_int = 0x140;
pub const BTN_TOOL_RUBBER: c_int = 0x141;
pub const BTN_TOOL_BRUSH: c_int = 0x142;
pub const BTN_TOOL_PENCIL: c_int = 0x143;
pub const BTN_TOOL_AIRBRUSH: c_int = 0x144;
pub const BTN_TOOL_FINGER: c_int = 0x145;
pub const BTN_TOOL_MOUSE: c_int = 0x146;
pub const BTN_TOOL_LENS: c_int = 0x147;
pub const BTN_TOOL_QUINTTAP: c_int = 0x148; /* Five fingers on trackpad */
pub const BTN_TOUCH: c_int = 0x14a;
pub const BTN_STYLUS: c_int = 0x14b;
pub const BTN_STYLUS2: c_int = 0x14c;
pub const BTN_TOOL_DOUBLETAP: c_int = 0x14d;
pub const BTN_TOOL_TRIPLETAP: c_int = 0x14e;
pub const BTN_TOOL_QUADTAP: c_int = 0x14f; /* Four fingers on trackpad */
pub const BTN_WHEEL: c_int = 0x150;
pub const BTN_GEAR_DOWN: c_int = 0x150;
pub const BTN_GEAR_UP: c_int = 0x151;
pub const KEY_OK: c_int = 0x160;
pub const KEY_SELECT: c_int = 0x161;
pub const KEY_GOTO: c_int = 0x162;
pub const KEY_CLEAR: c_int = 0x163;
pub const KEY_POWER2: c_int = 0x164;
pub const KEY_OPTION: c_int = 0x165;
pub const KEY_INFO: c_int = 0x166; /* AL OEM Features/Tips/Tutorial */
pub const KEY_TIME: c_int = 0x167;
pub const KEY_VENDOR: c_int = 0x168;
pub const KEY_ARCHIVE: c_int = 0x169;
pub const KEY_PROGRAM: c_int = 0x16a; /* Media Select Program Guide */
pub const KEY_CHANNEL: c_int = 0x16b;
pub const KEY_FAVORITES: c_int = 0x16c;
pub const KEY_EPG: c_int = 0x16d;
pub const KEY_PVR: c_int = 0x16e; /* Media Select Home */
pub const KEY_MHP: c_int = 0x16f;
pub const KEY_LANGUAGE: c_int = 0x170;
pub const KEY_TITLE: c_int = 0x171;
pub const KEY_SUBTITLE: c_int = 0x172;
pub const KEY_ANGLE: c_int = 0x173;
pub const KEY_ZOOM: c_int = 0x174;
pub const KEY_MODE: c_int = 0x175;
pub const KEY_KEYBOARD: c_int = 0x176;
pub const KEY_SCREEN: c_int = 0x177;
pub const KEY_PC: c_int = 0x178; /* Media Select Computer */
pub const KEY_TV: c_int = 0x179; /* Media Select TV */
pub const KEY_TV2: c_int = 0x17a; /* Media Select Cable */
pub const KEY_VCR: c_int = 0x17b; /* Media Select VCR */
pub const KEY_VCR2: c_int = 0x17c; /* VCR Plus */
pub const KEY_SAT: c_int = 0x17d; /* Media Select Satellite */
pub const KEY_SAT2: c_int = 0x17e;
pub const KEY_CD: c_int = 0x17f; /* Media Select CD */
pub const KEY_TAPE: c_int = 0x180; /* Media Select Tape */
pub const KEY_RADIO: c_int = 0x181;
pub const KEY_TUNER: c_int = 0x182; /* Media Select Tuner */
pub const KEY_PLAYER: c_int = 0x183;
pub const KEY_TEXT: c_int = 0x184;
pub const KEY_DVD: c_int = 0x185; /* Media Select DVD */
pub const KEY_AUX: c_int = 0x186;
pub const KEY_MP3: c_int = 0x187;
pub const KEY_AUDIO: c_int = 0x188; /* AL Audio Browser */
pub const KEY_VIDEO: c_int = 0x189; /* AL Movie Browser */
pub const KEY_DIRECTORY: c_int = 0x18a;
pub const KEY_LIST: c_int = 0x18b;
pub const KEY_MEMO: c_int = 0x18c; /* Media Select Messages */
pub const KEY_CALENDAR: c_int = 0x18d;
pub const KEY_RED: c_int = 0x18e;
pub const KEY_GREEN: c_int = 0x18f;
pub const KEY_YELLOW: c_int = 0x190;
pub const KEY_BLUE: c_int = 0x191;
pub const KEY_CHANNELUP: c_int = 0x192; /* Channel Increment */
pub const KEY_CHANNELDOWN: c_int = 0x193; /* Channel Decrement */
pub const KEY_FIRST: c_int = 0x194;
pub const KEY_LAST: c_int = 0x195; /* Recall Last */
pub const KEY_AB: c_int = 0x196;
pub const KEY_NEXT: c_int = 0x197;
pub const KEY_RESTART: c_int = 0x198;
pub const KEY_SLOW: c_int = 0x199;
pub const KEY_SHUFFLE: c_int = 0x19a;
pub const KEY_BREAK: c_int = 0x19b;
pub const KEY_PREVIOUS: c_int = 0x19c;
pub const KEY_DIGITS: c_int = 0x19d;
pub const KEY_TEEN: c_int = 0x19e;
pub const KEY_TWEN: c_int = 0x19f;
pub const KEY_VIDEOPHONE: c_int = 0x1a0; /* Media Select Video Phone */
pub const KEY_GAMES: c_int = 0x1a1; /* Media Select Games */
pub const KEY_ZOOMIN: c_int = 0x1a2; /* AC Zoom In */
pub const KEY_ZOOMOUT: c_int = 0x1a3; /* AC Zoom Out */
pub const KEY_ZOOMRESET: c_int = 0x1a4; /* AC Zoom */
pub const KEY_WORDPROCESSOR: c_int = 0x1a5; /* AL Word Processor */
pub const KEY_EDITOR: c_int = 0x1a6; /* AL Text Editor */
pub const KEY_SPREADSHEET: c_int = 0x1a7; /* AL Spreadsheet */
pub const KEY_GRAPHICSEDITOR: c_int = 0x1a8; /* AL Graphics Editor */
pub const KEY_PRESENTATION: c_int = 0x1a9; /* AL Presentation App */
pub const KEY_DATABASE: c_int = 0x1aa; /* AL Database App */
pub const KEY_NEWS: c_int = 0x1ab; /* AL Newsreader */
pub const KEY_VOICEMAIL: c_int = 0x1ac; /* AL Voicemail */
pub const KEY_ADDRESSBOOK: c_int = 0x1ad; /* AL Contacts/Address Book */
pub const KEY_MESSENGER: c_int = 0x1ae; /* AL Instant Messaging */
pub const KEY_DISPLAYTOGGLE: c_int = 0x1af; /* Turn display : c_int = LCD on and off */
pub const KEY_BRIGHTNESS_TOGGLE: c_int = KEY_DISPLAYTOGGLE;
pub const KEY_SPELLCHECK: c_int = 0x1b0; /* AL Spell Check */
pub const KEY_LOGOFF: c_int = 0x1b1; /* AL Logoff */
pub const KEY_DOLLAR: c_int = 0x1b2;
pub const KEY_EURO: c_int = 0x1b3;
pub const KEY_FRAMEBACK: c_int = 0x1b4; /* Consumer - transport controls */
pub const KEY_FRAMEFORWARD: c_int = 0x1b5;
pub const KEY_CONTEXT_MENU: c_int = 0x1b6; /* GenDesc - system context menu */
pub const KEY_MEDIA_REPEAT: c_int = 0x1b7; /* Consumer - transport control */
pub const KEY_10CHANNELSUP: c_int = 0x1b8; /* 10 channels up : c_int = 10+ */
pub const KEY_10CHANNELSDOWN: c_int = 0x1b9; /* 10 channels down : c_int = 10- */
pub const KEY_IMAGES: c_int = 0x1ba; /* AL Image Browser */
pub const KEY_DEL_EOL: c_int = 0x1c0;
pub const KEY_DEL_EOS: c_int = 0x1c1;
pub const KEY_INS_LINE: c_int = 0x1c2;
pub const KEY_DEL_LINE: c_int = 0x1c3;
pub const KEY_FN: c_int = 0x1d0;
pub const KEY_FN_ESC: c_int = 0x1d1;
pub const KEY_FN_F1: c_int = 0x1d2;
pub const KEY_FN_F2: c_int = 0x1d3;
pub const KEY_FN_F3: c_int = 0x1d4;
pub const KEY_FN_F4: c_int = 0x1d5;
pub const KEY_FN_F5: c_int = 0x1d6;
pub const KEY_FN_F6: c_int = 0x1d7;
pub const KEY_FN_F7: c_int = 0x1d8;
pub const KEY_FN_F8: c_int = 0x1d9;
pub const KEY_FN_F9: c_int = 0x1da;
pub const KEY_FN_F10: c_int = 0x1db;
pub const KEY_FN_F11: c_int = 0x1dc;
pub const KEY_FN_F12: c_int = 0x1dd;
pub const KEY_FN_1: c_int = 0x1de;
pub const KEY_FN_2: c_int = 0x1df;
pub const KEY_FN_D: c_int = 0x1e0;
pub const KEY_FN_E: c_int = 0x1e1;
pub const KEY_FN_F: c_int = 0x1e2;
pub const KEY_FN_S: c_int = 0x1e3;
pub const KEY_FN_B: c_int = 0x1e4;
pub const KEY_BRL_DOT1: c_int = 0x1f1;
pub const KEY_BRL_DOT2: c_int = 0x1f2;
pub const KEY_BRL_DOT3: c_int = 0x1f3;
pub const KEY_BRL_DOT4: c_int = 0x1f4;
pub const KEY_BRL_DOT5: c_int = 0x1f5;
pub const KEY_BRL_DOT6: c_int = 0x1f6;
pub const KEY_BRL_DOT7: c_int = 0x1f7;
pub const KEY_BRL_DOT8: c_int = 0x1f8;
pub const KEY_BRL_DOT9: c_int = 0x1f9;
pub const KEY_BRL_DOT10: c_int = 0x1fa;
pub const KEY_NUMERIC_0: c_int = 0x200; /* used by phones, remote controls, */
pub const KEY_NUMERIC_1: c_int = 0x201; /* and other keypads */
pub const KEY_NUMERIC_2: c_int = 0x202;
pub const KEY_NUMERIC_3: c_int = 0x203;
pub const KEY_NUMERIC_4: c_int = 0x204;
pub const KEY_NUMERIC_5: c_int = 0x205;
pub const KEY_NUMERIC_6: c_int = 0x206;
pub const KEY_NUMERIC_7: c_int = 0x207;
pub const KEY_NUMERIC_8: c_int = 0x208;
pub const KEY_NUMERIC_9: c_int = 0x209;
pub const KEY_NUMERIC_STAR: c_int = 0x20a;
pub const KEY_NUMERIC_POUND: c_int = 0x20b;
pub const KEY_NUMERIC_A: c_int = 0x20c; /* Phone key A - HUT Telephony 0xb9 */
pub const KEY_NUMERIC_B: c_int = 0x20d;
pub const KEY_NUMERIC_C: c_int = 0x20e;
pub const KEY_NUMERIC_D: c_int = 0x20f;
pub const KEY_CAMERA_FOCUS: c_int = 0x210;
pub const KEY_WPS_BUTTON: c_int = 0x211; /* WiFi Protected Setup key */
pub const KEY_TOUCHPAD_TOGGLE: c_int = 0x212; /* Request switch touchpad on or off */
pub const KEY_TOUCHPAD_ON: c_int = 0x213;
pub const KEY_TOUCHPAD_OFF: c_int = 0x214;
pub const KEY_CAMERA_ZOOMIN: c_int = 0x215;
pub const KEY_CAMERA_ZOOMOUT: c_int = 0x216;
pub const KEY_CAMERA_UP: c_int = 0x217;
pub const KEY_CAMERA_DOWN: c_int = 0x218;
pub const KEY_CAMERA_LEFT: c_int = 0x219;
pub const KEY_CAMERA_RIGHT: c_int = 0x21a;
pub const KEY_ATTENDANT_ON: c_int = 0x21b;
pub const KEY_ATTENDANT_OFF: c_int = 0x21c;
pub const KEY_ATTENDANT_TOGGLE: c_int = 0x21d; /* Attendant call on or off */
pub const KEY_LIGHTS_TOGGLE: c_int = 0x21e; /* Reading light on or off */
pub const BTN_DPAD_UP: c_int = 0x220;
pub const BTN_DPAD_DOWN: c_int = 0x221;
pub const BTN_DPAD_LEFT: c_int = 0x222;
pub const BTN_DPAD_RIGHT: c_int = 0x223;
pub const KEY_ALS_TOGGLE: c_int = 0x230; /* Ambient light sensor */
pub const KEY_BUTTONCONFIG: c_int = 0x240; /* AL Button Configuration */
pub const KEY_TASKMANAGER: c_int = 0x241; /* AL Task/Project Manager */
pub const KEY_JOURNAL: c_int = 0x242; /* AL Log/Journal/Timecard */
pub const KEY_CONTROLPANEL: c_int = 0x243; /* AL Control Panel */
pub const KEY_APPSELECT: c_int = 0x244; /* AL Select Task/Application */
pub const KEY_SCREENSAVER: c_int = 0x245; /* AL Screen Saver */
pub const KEY_VOICECOMMAND: c_int = 0x246; /* Listening Voice Command */
pub const KEY_BRIGHTNESS_MIN: c_int = 0x250; /* Set Brightness to Minimum */
pub const KEY_BRIGHTNESS_MAX: c_int = 0x251; /* Set Brightness to Maximum */
pub const KEY_KBDINPUTASSIST_PREV: c_int = 0x260;
pub const KEY_KBDINPUTASSIST_NEXT: c_int = 0x261;
pub const KEY_KBDINPUTASSIST_PREVGROUP: c_int = 0x262;
pub const KEY_KBDINPUTASSIST_NEXTGROUP: c_int = 0x263;
pub const KEY_KBDINPUTASSIST_ACCEPT: c_int = 0x264;
pub const KEY_KBDINPUTASSIST_CANCEL: c_int = 0x265;
pub const BTN_TRIGGER_HAPPY: c_int = 0x2c0;
pub const BTN_TRIGGER_HAPPY1: c_int = 0x2c0;
pub const BTN_TRIGGER_HAPPY2: c_int = 0x2c1;
pub const BTN_TRIGGER_HAPPY3: c_int = 0x2c2;
pub const BTN_TRIGGER_HAPPY4: c_int = 0x2c3;
pub const BTN_TRIGGER_HAPPY5: c_int = 0x2c4;
pub const BTN_TRIGGER_HAPPY6: c_int = 0x2c5;
pub const BTN_TRIGGER_HAPPY7: c_int = 0x2c6;
pub const BTN_TRIGGER_HAPPY8: c_int = 0x2c7;
pub const BTN_TRIGGER_HAPPY9: c_int = 0x2c8;
pub const BTN_TRIGGER_HAPPY10: c_int = 0x2c9;
pub const BTN_TRIGGER_HAPPY11: c_int = 0x2ca;
pub const BTN_TRIGGER_HAPPY12: c_int = 0x2cb;
pub const BTN_TRIGGER_HAPPY13: c_int = 0x2cc;
pub const BTN_TRIGGER_HAPPY14: c_int = 0x2cd;
pub const BTN_TRIGGER_HAPPY15: c_int = 0x2ce;
pub const BTN_TRIGGER_HAPPY16: c_int = 0x2cf;
pub const BTN_TRIGGER_HAPPY17: c_int = 0x2d0;
pub const BTN_TRIGGER_HAPPY18: c_int = 0x2d1;
pub const BTN_TRIGGER_HAPPY19: c_int = 0x2d2;
pub const BTN_TRIGGER_HAPPY20: c_int = 0x2d3;
pub const BTN_TRIGGER_HAPPY21: c_int = 0x2d4;
pub const BTN_TRIGGER_HAPPY22: c_int = 0x2d5;
pub const BTN_TRIGGER_HAPPY23: c_int = 0x2d6;
pub const BTN_TRIGGER_HAPPY24: c_int = 0x2d7;
pub const BTN_TRIGGER_HAPPY25: c_int = 0x2d8;
pub const BTN_TRIGGER_HAPPY26: c_int = 0x2d9;
pub const BTN_TRIGGER_HAPPY27: c_int = 0x2da;
pub const BTN_TRIGGER_HAPPY28: c_int = 0x2db;
pub const BTN_TRIGGER_HAPPY29: c_int = 0x2dc;
pub const BTN_TRIGGER_HAPPY30: c_int = 0x2dd;
pub const BTN_TRIGGER_HAPPY31: c_int = 0x2de;
pub const BTN_TRIGGER_HAPPY32: c_int = 0x2df;
pub const BTN_TRIGGER_HAPPY33: c_int = 0x2e0;
pub const BTN_TRIGGER_HAPPY34: c_int = 0x2e1;
pub const BTN_TRIGGER_HAPPY35: c_int = 0x2e2;
pub const BTN_TRIGGER_HAPPY36: c_int = 0x2e3;
pub const BTN_TRIGGER_HAPPY37: c_int = 0x2e4;
pub const BTN_TRIGGER_HAPPY38: c_int = 0x2e5;
pub const BTN_TRIGGER_HAPPY39: c_int = 0x2e6;
pub const BTN_TRIGGER_HAPPY40: c_int = 0x2e7;
/* We avoid low common keys in module aliases so they don't get huge. */
pub const KEY_MIN_INTERESTING: c_int = KEY_MUTE;
pub const KEY_MAX: c_int = 0x2ff;
pub const KEY_CNT: c_int = KEY_MAX + 1;
/*
* Relative axes
*/
pub const REL_X: c_int = 0x00;
pub const REL_Y: c_int = 0x01;
pub const REL_Z: c_int = 0x02;
pub const REL_RX: c_int = 0x03;
pub const REL_RY: c_int = 0x04;
pub const REL_RZ: c_int = 0x05;
pub const REL_HWHEEL: c_int = 0x06;
pub const REL_DIAL: c_int = 0x07;
pub const REL_WHEEL: c_int = 0x08;
pub const REL_MISC: c_int = 0x09;
pub const REL_MAX: c_int = 0x0f;
pub const REL_CNT: c_int = REL_MAX + 1;
/*
* Absolute axes
*/
pub const ABS_X: c_int = 0x00;
pub const ABS_Y: c_int = 0x01;
pub const ABS_Z: c_int = 0x02;
pub const ABS_RX: c_int = 0x03;
pub const ABS_RY: c_int = 0x04;
pub const ABS_RZ: c_int = 0x05;
pub const ABS_THROTTLE: c_int = 0x06;
pub const ABS_RUDDER: c_int = 0x07;
pub const ABS_WHEEL: c_int = 0x08;
pub const ABS_GAS: c_int = 0x09;
pub const ABS_BRAKE: c_int = 0x0a;
pub const ABS_HAT0X: c_int = 0x10;
pub const ABS_HAT0Y: c_int = 0x11;
pub const ABS_HAT1X: c_int = 0x12;
pub const ABS_HAT1Y: c_int = 0x13;
pub const ABS_HAT2X: c_int = 0x14;
pub const ABS_HAT2Y: c_int = 0x15;
pub const ABS_HAT3X: c_int = 0x16;
pub const ABS_HAT3Y: c_int = 0x17;
pub const ABS_PRESSURE: c_int = 0x18;
pub const ABS_DISTANCE: c_int = 0x19;
pub const ABS_TILT_X: c_int = 0x1a;
pub const ABS_TILT_Y: c_int = 0x1b;
pub const ABS_TOOL_WIDTH: c_int = 0x1c;
pub const ABS_VOLUME: c_int = 0x20;
pub const ABS_MISC: c_int = 0x28;
pub const ABS_MT_SLOT: c_int = 0x2f; /* MT slot being modified */
pub const ABS_MT_TOUCH_MAJOR: c_int = 0x30; /* Major axis of touching ellipse */
pub const ABS_MT_TOUCH_MINOR: c_int = 0x31; /* Minor axis : c_int = omit if circular */
pub const ABS_MT_WIDTH_MAJOR: c_int = 0x32; /* Major axis of approaching ellipse */
pub const ABS_MT_WIDTH_MINOR: c_int = 0x33; /* Minor axis : c_int = omit if circular */
pub const ABS_MT_ORIENTATION: c_int = 0x34; /* Ellipse orientation */
pub const ABS_MT_POSITION_X: c_int = 0x35; /* Center X touch position */
pub const ABS_MT_POSITION_Y: c_int = 0x36; /* Center Y touch position */
pub const ABS_MT_TOOL_TYPE: c_int = 0x37; /* Type of touching device */
pub const ABS_MT_BLOB_ID: c_int = 0x38; /* Group a set of packets as a blob */
pub const ABS_MT_TRACKING_ID: c_int = 0x39; /* Unique ID of initiated contact */
pub const ABS_MT_PRESSURE: c_int = 0x3a; /* Pressure on contact area */
pub const ABS_MT_DISTANCE: c_int = 0x3b; /* Contact hover distance */
pub const ABS_MT_TOOL_X: c_int = 0x3c; /* Center X tool position */
pub const ABS_MT_TOOL_Y: c_int = 0x3d; /* Center Y tool position */
pub const ABS_MAX: c_int = 0x3f;
pub const ABS_CNT: c_int = ABS_MAX + 1;
/*
* Switch events
*/
pub const SW_LID: c_int = 0x00; /* set = lid shut */
pub const SW_TABLET_MODE: c_int = 0x01; /* set = tablet mode */
pub const SW_HEADPHONE_INSERT: c_int = 0x02; /* set = inserted */
pub const SW_RFKILL_ALL: c_int = 0x03; /* rfkill master switch, type "any" set = radio enabled */
pub const SW_RADIO: c_int = SW_RFKILL_ALL; /* deprecated */
pub const SW_MICROPHONE_INSERT: c_int = 0x04; /* set = inserted */
pub const SW_DOCK: c_int = 0x05; /* set = plugged into dock */
pub const SW_LINEOUT_INSERT: c_int = 0x06; /* set = inserted */
pub const SW_JACK_PHYSICAL_INSERT: c_int = 0x07; /* set = mechanical switch set */
pub const SW_VIDEOOUT_INSERT: c_int = 0x08; /* set = inserted */
pub const SW_CAMERA_LENS_COVER: c_int = 0x09; /* set = lens covered */
pub const SW_KEYPAD_SLIDE: c_int = 0x0a; /* set = keypad slide out */
pub const SW_FRONT_PROXIMITY: c_int = 0x0b; /* set = front proximity sensor active */
pub const SW_ROTATE_LOCK: c_int = 0x0c; /* set = rotate locked/disabled */
pub const SW_LINEIN_INSERT: c_int = 0x0d; /* set = inserted */
pub const SW_MUTE_DEVICE: c_int = 0x0e; /* set = device disabled */
pub const SW_MAX: c_int = 0x0f;
pub const SW_CNT: c_int = SW_MAX + 1;
/*
* Misc events
*/
pub const MSC_SERIAL: c_int = 0x00;
pub const MSC_PULSELED: c_int = 0x01;
pub const MSC_GESTURE: c_int = 0x02;
pub const MSC_RAW: c_int = 0x03;
pub const MSC_SCAN: c_int = 0x04;
pub const MSC_TIMESTAMP: c_int = 0x05;
pub const MSC_MAX: c_int = 0x07;
pub const MSC_CNT: c_int = MSC_MAX + 1;
/*
* LEDs
*/
pub const LED_NUML: c_int = 0x00;
pub const LED_CAPSL: c_int = 0x01;
pub const LED_SCROLLL: c_int = 0x02;
pub const LED_COMPOSE: c_int = 0x03;
pub const LED_KANA: c_int = 0x04;
pub const LED_SLEEP: c_int = 0x05;
pub const LED_SUSPEND: c_int = 0x06;
pub const LED_MUTE: c_int = 0x07;
pub const LED_MISC: c_int = 0x08;
pub const LED_MAIL: c_int = 0x09;
pub const LED_CHARGING: c_int = 0x0a;
pub const LED_MAX: c_int = 0x0f;
pub const LED_CNT: c_int = LED_MAX + 1;
/*
* Autorepeat values
*/
pub const REP_DELAY: c_int = 0x00;
pub const REP_PERIOD: c_int = 0x01;
pub const REP_MAX: c_int = 0x01;
pub const REP_CNT: c_int = REP_MAX + 1;
/*
* Sounds
*/
pub const SND_CLICK: c_int = 0x00;
pub const SND_BELL: c_int = 0x01;
pub const SND_TONE: c_int = 0x02;
pub const SND_MAX: c_int = 0x07;
pub const SND_CNT: c_int = SND_MAX + 1;

View File

@ -1,8 +1,11 @@
use std::{mem, ptr, slice};
use libc::{timeval, gettimeofday, input_event, c_int};
use nix::{unistd, errno::Errno};
use uinput_sys::*;
use crate::{Result as Res};
use nix::{unistd, ioctl_none};
use crate::Result;
use crate::linux::device::codes::*;
ioctl_none!(ui_dev_destroy, b'U', 2);
/// The virtual device.
pub struct Device {
@ -18,7 +21,7 @@ impl Device {
}
#[doc(hidden)]
pub fn write(&self, kind: c_int, code: c_int, value: c_int) -> Res<()> {
pub fn write(&self, kind: c_int, code: c_int, value: c_int) -> Result<()> {
let mut event = input_event {
time: timeval { tv_sec: 0, tv_usec: 0 },
type_: kind as u16,
@ -30,7 +33,7 @@ impl Device {
}
#[doc(hidden)]
pub fn write_event(&self, event: &mut input_event) -> Res<()> {
pub fn write_event(&self, event: &mut input_event) -> Result<()> {
unsafe {
gettimeofday(&mut event.time, ptr::null_mut());
@ -44,35 +47,33 @@ impl Device {
}
/// Synchronize the device.
pub fn synchronize(&self) -> Res<()> {
pub fn synchronize(&self) -> Result<()> {
self.write(EV_SYN, SYN_REPORT, 0)
}
/// Send an event.
pub fn send(&self, kind: c_int, code: c_int, value: i32) -> Res<()> {
pub fn send(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
self.write(kind, code, value)
}
/// Send a press event.
pub fn press(&self, kind: c_int, code: c_int) -> Res<()> {
pub fn press(&self, kind: c_int, code: c_int) -> Result<()> {
self.write(kind, code, 1)
}
/// Send a release event.
pub fn release(&self, kind: c_int, code: c_int) -> Res<()> {
pub fn release(&self, kind: c_int, code: c_int) -> Result<()> {
self.write(kind, code, 0)
}
/// Send a press and release event.
pub fn click(&self, kind: c_int, code: c_int) -> Res<()> {
pub fn click(&self, kind: c_int, code: c_int) -> Result<()> {
self.press(kind, code)?;
self.release(kind, code)?;
Ok(())
self.release(kind, code)
}
/// Send a relative or absolute positioning event.
pub fn position(&self, kind: c_int, code: c_int, value: i32) -> Res<()> {
pub fn position(&self, kind: c_int, code: c_int, value: i32) -> Result<()> {
self.write(kind, code, value)
}
}
@ -80,7 +81,8 @@ impl Device {
impl Drop for Device {
fn drop(&mut self) {
unsafe {
Errno::result(ui_dev_destroy(self.fd)).unwrap();
// ignore error here so as to not panic in a drop
ui_dev_destroy(self.fd).ok();
}
}
}

View File

@ -3,54 +3,148 @@ use std::fs::File;
use std::io::Read;
use std::os::unix::io::AsRawFd;
use libc::{input_event, c_int};
use nix::ioctl_write_ptr;
use nix::{ioctl_write_ptr, ioctl_read_buf};
#[cfg(feature = "epoll_inotify")]
use std::os::unix::prelude::RawFd;
use crate::{Error,Result};
use crate::linux::{EV_KEY, KEY_MAX, NAME, KEY_W, KEY_A, KEY_S, KEY_D, BTN_LEFT};
ioctl_write_ptr!(eviocgrab, b'E', 0x90, c_int);
ioctl_read_buf!(eviocgname, b'E', 0x06, u8);
ioctl_read_buf!(eviocgbit, b'E', 0x20, u8);
ioctl_read_buf!(eviocgbit_ev_key, b'E', 0x20 + EV_KEY, u8);
// TODO: use size_of_input_event instead of hard-coding 24.
const SIZE_OF_INPUT_EVENT: usize = 24;//mem::size_of::<input_event>();
const SIZE_OF_INPUT_EVENT: usize = mem::size_of::<input_event>();
pub struct InputDevice {
device_file: File,
buf: [u8; SIZE_OF_INPUT_EVENT],
grabbed: bool,
#[cfg(feature = "epoll_inotify")]
epoll_fd: Option<RawFd>,
}
impl InputDevice {
pub fn open(device_file: &str) -> Result<Self> {
let device_file = File::open(device_file)?;
pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
Ok(InputDevice {
device_file: device_file,
buf: [0u8; SIZE_OF_INPUT_EVENT],
device_file: File::open(path)?,
grabbed: false,
#[cfg(feature = "epoll_inotify")]
epoll_fd: None,
})
}
pub fn new_input_event_buf() -> [u8; SIZE_OF_INPUT_EVENT] {
[0u8; SIZE_OF_INPUT_EVENT]
}
pub fn read_event(&mut self) -> Result<input_event> {
let num_bytes = self.device_file.read(&mut self.buf)?;
pub fn read_event(&mut self, buf: &mut [u8; SIZE_OF_INPUT_EVENT]) -> Result<input_event> {
let num_bytes = self.device_file.read(buf)?;
if num_bytes != SIZE_OF_INPUT_EVENT {
return Err(Error::ShortRead);
}
let event: input_event = unsafe { mem::transmute(self.buf) };
let event: input_event = unsafe { mem::transmute(*buf) };
Ok(event)
}
pub fn grab(&mut self) -> Result<()> {
pub fn valid_keyboard_device(self) -> Result<Self> {
use std::os::unix::fs::FileTypeExt;
// must be a character device
if !self.device_file.metadata()?.file_type().is_char_device() {
return Err(Error::NotAKeyboard);
}
let raw_fd = self.device_file.as_raw_fd();
// does it support EV_KEY
let mut evbit = [0u8; 8];
unsafe {
eviocgbit(raw_fd, &mut evbit)?;
};
let evbit = u64::from_ne_bytes(evbit);
if (evbit & (1 << EV_KEY)) == 0 {
return Err(Error::NotAKeyboard);
}
// does it support all keys WASD and *not* LEFT mouse button ? (yes this is fairly random but probably good enough, could make configuration probably)
let mut key_bits = [0u8; (KEY_MAX as usize / 8) + 1];
unsafe {
eviocgbit_ev_key(raw_fd, &mut key_bits)?;
};
let key_unsupported = |key : c_int| (key_bits[key as usize / 8] & (1 << (key % 8))) == 0;
if key_unsupported(KEY_W) || key_unsupported(KEY_A) || key_unsupported(KEY_S) || key_unsupported(KEY_D) || !key_unsupported(BTN_LEFT) {
return Err(Error::NotAKeyboard);
}
// is it another running copy of rusty-keys ?
let mut name = [0u8; NAME.len()];
unsafe {
eviocgname(raw_fd, &mut name)?
};
// exclude anything starting with "Yubico" also
if NAME.as_bytes() == &name || "Yubico".as_bytes() == &name[0..6] {
return Err(Error::NotAKeyboard);
}
return Ok(self);
}
pub fn grab(mut self) -> Result<Self> {
unsafe {
eviocgrab(self.device_file.as_raw_fd(), 1 as *const c_int)?;
}
Ok(())
self.grabbed = true;
Ok(self)
}
pub fn release(&mut self) -> Result<()> {
unsafe {
eviocgrab(self.device_file.as_raw_fd(), 0 as *const c_int)?;
if self.grabbed {
unsafe {
eviocgrab(self.device_file.as_raw_fd(), 0 as *const c_int)?;
}
self.grabbed = false;
}
Ok(())
}
#[cfg(feature = "epoll_inotify")]
pub fn epoll_add(mut self, epoll_fd: RawFd, data: u64) -> Result<Self> {
use nix::fcntl::{OFlag, fcntl, FcntlArg};
if None != self.epoll_fd {
return Err(Error::EpollAlreadyAdded);
}
let raw_fd = self.device_file.as_raw_fd();
let flags = unsafe {
// https://github.com/nix-rust/nix/issues/1102
OFlag::from_bits_unchecked(fcntl(raw_fd, FcntlArg::F_GETFL)?)
};
fcntl(raw_fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK))?;
let epoll_event = epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, data);
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_ADD, raw_fd, epoll_event)?;
self.epoll_fd = Some(epoll_fd);
Ok(self)
}
#[cfg(feature = "epoll_inotify")]
pub fn epoll_del(&mut self) -> Result<&mut Self> {
if let Some(epoll_fd) = self.epoll_fd {
// set this to None first, if we end up returning an Err early, we can't do anything else anyway...
self.epoll_fd = None;
let empty_event = epoll::Event::new(epoll::Events::empty(), 0);
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_DEL, self.device_file.as_raw_fd(), empty_event)?;
}
Ok(self)
}
}
impl Drop for InputDevice {
fn drop(&mut self) {
self.release().ok(); // ignore any errors here, what could we do anyhow?
// ignore any errors here, what could we do anyhow?
self.release().ok();
#[cfg(feature = "epoll_inotify")]
self.epoll_del().ok();
}
}

View File

@ -1,6 +1,9 @@
mod builder;
pub use self::builder::Builder;
pub mod codes;
pub use codes::*;
mod device;
pub use self::device::Device;

View File

@ -1,26 +1,18 @@
use crate::*;
use std::path::Path;
use crate::linux::device::codes::*;
pub mod device;
pub use device::{Device,InputDevice};
pub use device::{Device,InputDevice, Builder};
/// Open the default uinput device.
pub fn default() -> Result<device::Builder> {
device::Builder::default()
}
/// Open the specified uinput device.
pub fn open<P: AsRef<Path>>(path: P) -> Result<device::Builder> {
device::Builder::open(path)
}
use uinput_sys::*;
use libc::input_event;
use std::process::exit;
use std::{env, thread};
use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::env;
use std::collections::HashMap;
#[cfg(feature = "epoll_inotify")]
const INPUT_FOLDER: &str = "/dev/input/";
// 1 is down, 0 is up
const DOWN: i32 = 1;
@ -28,13 +20,6 @@ const UP: i32 = 0;
use getopts::Options;
use inotify::{
EventMask,
Inotify,
WatchMask,
};
use std::collections::HashMap;
const EV_KEY_U16: u16 = EV_KEY as u16;
type LinuxKeyMaps = KeyMaps<Device, u16, input_event>;
@ -98,8 +83,6 @@ impl Keyboard<u16, input_event> for Device {
}
}
#[derive(Debug)]
struct Config {
device_files: Vec<String>,
@ -119,88 +102,133 @@ pub fn main_res() -> Result<()> {
let key_map = key_map();
//println!("key_map: {:?}", key_map);
let device = open("/dev/uinput")
.or_else(|_| open("/dev/input/uinput"))
.or_else(|_| default())?
.name("rusty-keys")?
let device = Builder::open("/dev/uinput")
.or_else(|_| Builder::open("/dev/input/uinput"))
.or_else(|_| Builder::default())?
.name(NAME)?
.event(key_map.values())?
.create()?;
#[cfg(not(feature = "toml_serde"))]
let mut key_map = LinuxKeyMaps::new(&key_map, KeymapConfig::default());
#[cfg(feature = "toml_serde")]
let mut key_map = LinuxKeyMaps::from_cfg(&key_map, &config.config_file);
//println!("keymaps: {:?}", keymaps);
let mut input_event_buf = InputDevice::new_input_event_buf();
if config.device_files.len() == 1 {
// shortcut, don't bother with threads
let mut input_device = InputDevice::open(&config.device_files[0])?;
input_device.grab()?;
// shortcut, don't bother with epoll
let mut input_device = InputDevice::open(&config.device_files[0])?.grab()?;
loop {
let event = input_device.read_event()?;
let event = input_device.read_event(&mut input_event_buf)?;
send_event(&mut key_map, event, &device)?
}
} else {
// start up some intra thread communication
let (tx, rx) = mpsc::channel();
#[cfg(not(feature = "epoll_inotify"))]
panic!("without epoll_inotify feature, only exactly 1 device is supported");
if config.device_files.len() > 0 {
// we only want to operate on device files sent in then quit
for device_file in config.device_files.iter() {
let device_file = device_file.clone();
let tx = tx.clone();
thread::spawn(move || {
let ret = spawn_map_thread(tx, &device_file);
if let Err(e) = ret {
println!("mapping for {} ended due to error: {}", device_file, e);
}
});
}
} else {
let tx = tx.clone();
thread::spawn(move || {
// we want to wait forever starting new threads for any new keyboard devices
let mut inotify = Inotify::init().expect("Failed to initialize inotify");
#[cfg(feature = "epoll_inotify")]
{
use inotify::{Inotify, WatchMask};
inotify.add_watch("/dev/input/", WatchMask::CREATE).expect("Failed to add inotify watch");
let epoll_fd = epoll::create(true)?;
const INOTIFY_DATA: u64 = u64::max_value();
let device_files = get_keyboard_device_filenames();
println!("Detected devices: {:?}", device_files);
for device_file in device_files.iter() {
inotify_spawn_thread(&tx, device_file);
let (device_files, mut inotify) = if config.device_files.len() > 0 {
// we operate on exactly the devices sent in and never watch for new devices
(config.device_files.iter().map(|device_file| InputDevice::open(&device_file).expect("device_file does not exist!")).collect(), None)
} else {
use std::os::unix::io::AsRawFd;
// we want to wait forever starting new threads for any new keyboard devices
// there is a slight race condition here, if a keyboard is plugged in between the time we
// enumerate the devices and set up the inotify watch, we'll miss it, doing it the other way
// can bring duplicates though, todo: think about this...
let device_files = get_keyboard_devices();
let mut inotify = Inotify::init()?;
inotify.add_watch(INPUT_FOLDER, WatchMask::CREATE)?;
let epoll_event = epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, INOTIFY_DATA);
epoll::ctl(epoll_fd, epoll::ControlOptions::EPOLL_CTL_ADD, inotify.as_raw_fd(), epoll_event)?;
(device_files, Some(inotify))
};
let mut input_devices = Vec::with_capacity(device_files.len());
for (idx, device_file) in device_files.into_iter().enumerate() {
input_devices.push(Some(device_file.grab()?.epoll_add(epoll_fd, idx as u64)?));
}
let mut buffer = [0u8; 4096];
loop {
let events = inotify.read_events_blocking(&mut buffer);
let mut epoll_buf = [epoll::Event::new(epoll::Events::empty(), 0); 4];
let mut inotify_buf = [0u8; 256];
if let Ok(events) = events {
for event in events {
if !event.mask.contains(EventMask::ISDIR) {
if let Some(device_file) = event.name.and_then(|name|name.to_str()) {
// check if this is an eligible keyboard device
let device_files = get_keyboard_device_filenames();
if !device_files.contains(&device_file.to_string()) {
continue;
loop {
let num_events = epoll::wait(epoll_fd, -1, &mut epoll_buf)?;
for event in &epoll_buf[0..num_events] {
let idx = event.data as usize;
if let Some(Some(input_device)) = &mut input_devices.get_mut(idx) {
loop {
match input_device.read_event(&mut input_event_buf) {
Ok(event) => {
//println!("input event: {:?}", event);
send_event(&mut key_map, event, &device)?
}
Err(err) => {
if let Error::Io(ref err) = err {
if err.kind() == std::io::ErrorKind::WouldBlock {
// go back to epoll event loop
break;
}
}
// otherwise it's some other error, don't read anything from this again
println!("input err: {:?}", err);
// remove it from input_devices and drop it
let _ = std::mem::replace(&mut input_devices[idx], None);
if inotify.is_none() {
// if we aren't watching with inotify, and the last device is removed (Vec only has None's in it), exit the program
if input_devices.iter().all(|id| id.is_none()) {
println!("last device went away, exiting...");
return Ok(());
}
}
break;
}
}
}
} else if event.data == INOTIFY_DATA {
if let Some(inotify) = &mut inotify {
for event in inotify.read_events(&mut inotify_buf)? {
if let Some(device_file) = event.name.and_then(|name| name.to_str()) {
// check if this is an eligible keyboard device
let mut path = std::path::PathBuf::new();
path.push(INPUT_FOLDER);
path.push(device_file);
if let Ok(input_device) = InputDevice::open(path).and_then(|id| id.valid_keyboard_device()) {
println!("starting mapping for new keyboard: {}", device_file);
let idx = input_devices.iter().position(|id| id.is_none()).unwrap_or(input_devices.len());
let input_device = input_device.grab()?.epoll_add(epoll_fd, idx as u64)?;
if idx == input_devices.len() {
input_devices.push(Some(input_device));
} else {
// simply replacing None here
let _ = std::mem::replace(&mut input_devices[idx], Some(input_device));
}
}
}
println!("starting mapping thread for: {}", device_file);
inotify_spawn_thread(&tx, device_file.clone());
}
}
}
}
}
});
}
drop(tx); // drop our last one, so when the threads finish, everything stops
// process all events
for event in rx {
send_event(&mut key_map, event, &device)?
}
}
}
Ok(())
}
fn send_event(key_map: &mut LinuxKeyMaps, mut event: input_event, device: &Device) -> Result<()> {
if event.type_ == EV_KEY_U16 {
// println!("type: {} code: {:?} value: {:?}", event.type_, event.code(), event.value());
key_map.send_event(&mut event, &device)?
} else {
device.write_event(&mut event)?
@ -208,28 +236,6 @@ fn send_event(key_map: &mut LinuxKeyMaps, mut event: input_event, device: &Devic
Ok(())
}
fn inotify_spawn_thread(tx: &Sender<input_event>, device_file: &str) {
let mut filename = "/dev/input/".to_string();
filename.push_str(&device_file);
let tx = tx.clone();
thread::spawn(move || {
let ret = spawn_map_thread(tx, &filename);
if let Err(e) = ret {
println!("mapping for {} ended due to error: {}", filename, e);
}
});
}
fn spawn_map_thread(tx: Sender<input_event>, device_file: &str) -> Result<()> {
let mut input_device = InputDevice::open(device_file)?;
input_device.grab()?;
loop {
let event = input_device.read_event()?;
tx.send(event)?
}
}
fn parse_args() -> Config {
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} [options] [device_files...]", program);
@ -255,7 +261,7 @@ fn parse_args() -> Config {
}
if matches.opt_present("v") {
println!("rusty-keys {}", VERSION);
println!("{} {}", NAME, VERSION);
exit(0);
}
@ -264,43 +270,25 @@ fn parse_args() -> Config {
Config::new(matches.free, config_file)
}
// Detects and returns the name of the keyboard device file. This function uses
// the fact that all device information is shown in /proc/bus/input/devices and
// the keyboard device file should always have an EV of 120013
// grep -E 'Handlers|EV' /proc/bus/input/devices | grep -B1 120013 | grep -Eo event[0-9]+
fn get_keyboard_device_filenames() -> Vec<String> {
use std::io::BufReader;
use std::io::prelude::*;
use std::fs::File;
let f = File::open("/proc/bus/input/devices");
if f.is_err() {
return Vec::new();
}
let f = BufReader::new(f.unwrap());
let mut filename = None;
let mut filenames = Vec::new();
for line in f.lines() {
if let Ok(line) = line {
if line.starts_with("H: Handlers=") {
if let Some(event_index) = line.find("event") {
let last_index = line[event_index..line.len()-1].find(" ").and_then(|i| Some(i + event_index)).unwrap_or(line.len() - 1);
filename = Some(line[event_index..last_index].to_owned());
}
} else if line.starts_with("B: EV=") && line.contains("120013") {
if let Some(ref filename) = filename {
filenames.push(filename.clone());
#[cfg(feature = "epoll_inotify")]
fn get_keyboard_devices() -> Vec<InputDevice> {
let mut res = Vec::new();
if let Ok(entries) = std::fs::read_dir(INPUT_FOLDER) {
for entry in entries {
if let Ok(entry) = entry {
if let Ok(input_device) = InputDevice::open(entry.path()).and_then(|id|id.valid_keyboard_device()) {
res.push(input_device);
}
}
}
}
filenames
res
}
pub fn key_map() -> HashMap<&'static str, u16> {
[
// generated like:
// grep -o 'KEY_[^ :;]*' ~/.cargo/registry/src/github.com-1ecc6299db9ec823/uinput-sys-0.1.3/src/events.rs | sed 's/^KEY_//' | awk '{print "(\""$1"\", KEY_"$1"),"}'
// grep -o 'KEY_[^ :;]*' ~/.cargo/registry/src/github.com-1ecc6299db9ec823/uinput-sys-0.1.3/src/codes | sed 's/^KEY_//' | awk '{print "(\""$1"\", KEY_"$1"),"}'
("RESERVED", KEY_RESERVED),
("ESC", KEY_ESC),
("1", KEY_1),
@ -605,5 +593,7 @@ pub fn key_map() -> HashMap<&'static str, u16> {
("P0", KEY_KP0),
("PDOT", KEY_KPDOT),
("PENT", KEY_KPENTER),
("TOUCHPAD_TOGGLE", KEY_TOUCHPAD_TOGGLE),
].iter().cloned().map(|(m, v)| (m, v as u16)).collect()
}
}

View File

@ -84,7 +84,7 @@ pub const KEY_KPPLUS: CGKeyCode = 0x0045;
pub const KEY_KP1: CGKeyCode = 0x0053;
pub const KEY_KP2: CGKeyCode = 0x0054;
pub const KEY_KP3: CGKeyCode = 0x0055;
pub const KEY_KP0: CGKeyCode = 0x0052;
pub const KEY_KP0: CGKeyCode = 0x0052; // https://code-with-me.jetbrains.com/UCsz0dzSd1QAbmOi8g0V3w#p=IC&fp=6298EDAF97FA62E9897E2556D1A6631FB66974568C7252E696472EE85078E8A0
pub const KEY_KPDOT: CGKeyCode = 0x0041;
// pub const KEY_ZENKAKUHANKAKU: CGKeyCode = NOT_FOUND;
pub const KEY_102ND: CGKeyCode = 0x000A;
@ -96,7 +96,7 @@ pub const KEY_F12: CGKeyCode = 0x006F;
// pub const KEY_HENKAN: CGKeyCode = NOT_FOUND;
// pub const KEY_KATAKANAHIRAGANA: CGKeyCode = NOT_FOUND;
// pub const KEY_MUHENKAN: CGKeyCode = NOT_FOUND;
// pub const KEY_KPJPCOMMA: CGKeyCode = NOT_FOUND;
// pub const KEY_KPJPCOMMA: CGKeyCode = NOT_FOUND; // https://code-with-me.jetbrains.com/Mf59EFUeJZQ2mpGCCCjNWw#p=IC&fp=6298EDAF97FA62E9897E2556D1A6631FB66974568C7252E696472EE85078E8A0
pub const KEY_KPENTER: CGKeyCode = 0x004C;
pub const KEY_RIGHTCTRL: CGKeyCode = 0x003E;
pub const KEY_KPSLASH: CGKeyCode = 0x004B;
@ -120,15 +120,15 @@ pub const KEY_DELETE: CGKeyCode = 0x0075;
// pub const KEY_POWER: CGKeyCode = NOT_FOUND;
pub const KEY_KPEQUAL: CGKeyCode = 0x0069;
// pub const KEY_KPPLUSMINUS: CGKeyCode = NOT_FOUND;
// pub const KEY_PAUSE: CGKeyCode = NOT_FOUND;
pub const KEY_PAUSE: CGKeyCode = KEY_LINEFEED;
pub const KEY_SCALE: CGKeyCode = 0x0047;
pub const KEY_KPCOMMA: CGKeyCode = 0x0036;
// pub const KEY_HANGEUL: CGKeyCode = NOT_FOUND;
// pub const KEY_HANGUEL: CGKeyCode = NOT_FOUND;
// pub const KEY_HANGEUL: CGKeyCode = NOT_FOUND;
// pub const KEY_HANJA: CGKeyCode = NOT_FOUND;
pub const KEY_YEN: CGKeyCode = 0x0037;
// pub const KEY_LEFTMETA: CGKeyCode = NOT_FOUND;
//pub const KEY_YEN: CGKeyCode = NOT_FOUND;
pub const KEY_LEFTMETA: CGKeyCode = 0x0037;
pub const KEY_RIGHTMETA: CGKeyCode = 0x0036;
pub const KEY_COMPOSE: CGKeyCode = 0x006E;
// pub const KEY_STOP: CGKeyCode = NOT_FOUND;
@ -516,7 +516,7 @@ pub fn key_map() -> HashMap<&'static str, CGKeyCode> {
// below manual shortcuts
("PSCR", KEY_SYSRQ),
("SLCK", KEY_SCROLLLOCK),
//("BRK", KEY_PAUSE),
("BRK", KEY_PAUSE),
("GRV", KEY_GRAVE),
("0", KEY_10), // dumb or named wrong?
("MINS", KEY_MINUS),
@ -540,7 +540,7 @@ pub fn key_map() -> HashMap<&'static str, CGKeyCode> {
("RCTL", KEY_RIGHTCTRL),
("LALT", KEY_LEFTALT),
("RALT", KEY_RIGHTALT),
//("LGUI", KEY_LEFTMETA),
("LGUI", KEY_LEFTMETA),
("RGUI", KEY_RIGHTMETA),
("INS", KEY_INSERT),
("PGUP", KEY_PAGEUP),

View File

@ -9,126 +9,114 @@ use std::process::exit;
use getopts::Options;
use std::fs::File;
use std::io::Write;
pub mod codes;
use codes::*;
use lazy_static::lazy_static;
use std::sync::Mutex;
use core_graphics::event::CGKeyCode;
use core_graphics::event::*;
use core_graphics::event_source::*;
use core_foundation_sys::*;
use core_foundation_sys::base::*;
use core_foundation_sys::runloop::*;
use core_graphics::event::{CGEventTapLocation, CGEventType};
type MacOSKeyMaps = KeyMaps<CGEventSource, CGKeyCode, CGEvent, Option<CGEvent>>;
type CallbackPointer = (MacOSKeyMaps, CGEventSource);
/*
extern {
/// Return the type identifier for the opaque type `CGEventRef'.
//fn CGEventGetTypeID() -> CFTypeID;
pub fn CFRunLoopRun();
}
*/
// possible types for event_source
Private = -1,
CombinedSessionState = 0,
HIDSystemState = 1,
type MacOSKeyMaps = KeyMaps<Device, CGKeyCode, InputEvent, Option<CGEventRef>>;
// possible types for tapLocation
HID,
Session,
AnnotatedSession,
*/
// this is used for identifying the fake keypresses we insert, so we don't process them in an infinite loop
//const FAKE_EXTRA_INFO: ULONG_PTR = 332;
// macOS seems to require this, or it ignores shift, WHY?
const delay: std::time::Duration = std::time::Duration::from_millis(20);
const tapLocation: CGEventTapLocation = CGEventTapLocation::Session;
// this is only used if tapLocation is HID, to prevent us from mapping our own key inputs
const uniqueHIDUserData: i64 = 45;
//const BLOCK_KEY: *const CGEventRef = std::ptr::null();
//const BLOCK_KEY: *mut CGEventRef = std::ptr::null_mut();
pub struct InputEvent {
event_type: CGEventType,
event: CGEventRef,
}
impl KeyEvent<CGKeyCode> for InputEvent {
impl KeyEvent<CGKeyCode> for CGEvent {
fn code(&self) -> CGKeyCode {
//1
//self.event.to_owned().get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE) as CGKeyCode
unsafe { CGEventGetIntegerValueField(self.event, kCGKeyboardEventKeycode) }
self.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE) as CGKeyCode
}
/*
fn set_code(&self, code: CGKeyCode) {
//1
//self.event.to_owned().get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE) as CGKeyCode
unsafe { CGEventSetIntegerValueField(self.event, kCGKeyboardEventKeycode) }
}
*/
fn value(&self) -> KeyState {
match self.event_type {
kCGEventFlagsChanged => KeyState::DOWN,
kCGEventKeyDown => KeyState::DOWN,
kCGEventKeyUp => KeyState::UP,
kCGEventTapDisabledByTimeout => {
let event_type = self.get_type();
match event_type {
CGEventType::FlagsChanged => {
let flags = self.get_flags().bits(); // todo: fix cast?
let mask = match self.code() {
KEY_LEFTCTRL => NX_DEVICELCTLKEYMASK,
KEY_RIGHTCTRL => NX_DEVICERCTLKEYMASK,
KEY_LEFTSHIFT => NX_DEVICELSHIFTKEYMASK,
KEY_RIGHTSHIFT => NX_DEVICERSHIFTKEYMASK,
KEY_LEFTMETA => NX_DEVICELCMDKEYMASK,
KEY_RIGHTMETA => NX_DEVICERCMDKEYMASK,
KEY_LEFTALT => NX_DEVICELALTKEYMASK,
KEY_RIGHTALT => NX_DEVICERALTKEYMASK,
KEY_CAPSLOCK => NX_DEVICECAPSLOCKMASK,
_ => panic!("unhandled key: {}", self.code()),
};
if (flags & mask) != 0 { KeyState::DOWN } else { KeyState::UP }
},
CGEventType::KeyDown => KeyState::DOWN,
CGEventType::KeyUp => KeyState::UP,
CGEventType::TapDisabledByTimeout => {
println!("Quartz event tap disabled because of timeout; attempting to reregister.");
todo!("implement register listener");
//register_listener(channel);
KeyState::OTHER
//KeyState::OTHER
},
_ => {
println!("Received unknown EventType: {}", self.event_type);
println!("Received unknown EventType: {:?}", event_type);
KeyState::OTHER
},
}
}
}
pub enum DeviceRet {
EVENT(CGEventRef),
NULL,
}
pub struct Device;
impl Keyboard<CGKeyCode, InputEvent, Option<CGEventRef>> for Device {
fn send(&self, event: &mut InputEvent) -> Result<Option<CGEventRef>> {
println!("send orig: {}", event.code());
Ok(Some(event.event))
}
fn send_mod_code(&self, code: CGKeyCode, event: &mut InputEvent) -> Result<Option<CGEventRef>> {
// event.value should only ever be UP/DOWN when this method is called
println!("send_mod_code orig: {} code: {}", event.code(), code);
//event.event.set_integer_value_field();
//unsafe { CGEventSetIntegerValueField(event.event, kCGKeyboardEventKeycode, code as i64) };
impl Keyboard<CGKeyCode, CGEvent, Option<CGEvent>> for CGEventSource {
fn send(&self, event: &mut CGEvent) -> Result<Option<CGEvent>> {
//println!("send orig: {}", event.code());
//Ok(Some(event.event))
//Ok(None)
self.send_mod_code_value(event.code(), event.value() == KeyState::UP, event)
}
fn send_mod_code(&self, code: CGKeyCode, event: &mut CGEvent) -> Result<Option<CGEvent>> {
// event.value should only ever be UP/DOWN when this method is called
//println!("send_mod_code orig: {} code: {}", event.code(), code);
//unsafe { CGEventSetIntegerValueField(event.event, kCGKeyboardEventKeycode, code as i64) };
//Ok(Some(event.event))
self.send_mod_code_value(code, event.value() == KeyState::UP, event)
}
fn send_mod_code_value(&self, code: CGKeyCode, up_not_down: bool, event: &mut InputEvent) -> Result<Option<CGEventRef>> {
println!("send_mod_code_value orig: {} code: {}, up_not_down: {}", event.code(), code, up_not_down);
// https://github.com/enigo-rs/enigo/blob/master/src/macos/macos_impl.rs
/*
let event_source = CGEventSource::new(CGEventSourceStateID::CombinedSessionState)
.expect("Failed creating event source");
fn send_mod_code_value(&self, code: CGKeyCode, up_not_down: bool, _event: &mut CGEvent) -> Result<Option<CGEvent>> {
//println!("send_mod_code_value orig: {} code: {}, up_not_down: {}", event.code(), code, up_not_down);
//return Ok(None);
let event =
CGEvent::new_keyboard_event(event_source.clone(), code, !up_not_down)
CGEvent::new_keyboard_event(self.clone(), code, !up_not_down)
.expect("Failed creating event");
event.post(CGEventTapLocation::HID);
*/
match tapLocation {
CGEventTapLocation::HID => event.set_integer_value_field(EventField::EVENT_SOURCE_USER_DATA, uniqueHIDUserData),
_ => {}
};
event.post(tapLocation);
unsafe { CGEventSetIntegerValueField(event.event, kCGKeyboardEventKeycode, code as i64) };
let flags = unsafe { CGEventGetFlags(event.event) };
print_flags(flags);
let flags = flags >> NX_DEVICERSHIFTKEYMASK;
print_flags(flags);
//CGEventSetFlags(event, flags);
Ok(Some(event.event))
//Ok(None)
Ok(None)
}
fn synchronize(&self) -> Result<Option<CGEventRef>> {
// no-op here
fn synchronize(&self) -> Result<Option<CGEvent>> {
std::thread::sleep(delay);
Ok(None)
}
@ -144,55 +132,25 @@ impl Keyboard<CGKeyCode, InputEvent, Option<CGEventRef>> for Device {
KEY_CAPSLOCK
}
fn block_key(&self) -> Result<Option<CGEventRef>> {
fn block_key(&self) -> Result<Option<CGEvent>> {
Ok(None)
}
}
unsafe impl Send for MacOSKeyMaps {
// windows promises us keybd_proc will only be called by a single thread at a time
// but rust makes us wrap in mutex anyway, so we are extra safe...
}
const DEVICE: Device = Device;
/*
lazy_static! {
static ref KEY_MAPPER: Mutex<MacOSKeyMaps> = {
pub fn main_res() -> Result<()> {
let config = parse_args();
//println!("Config: {:?}", config);
let key_map = key_map();
//println!("key_map: {:?}", key_map);
println!("chosen config file: {}", config.config_file);
Mutex::new(MacOSKeyMaps::from_cfg(&key_map, &config.config_file))
};
}
*/
pub fn main_res() -> Result<()> {
// this is just to cause the lazy_static init to run first, so if -h or -v is wanted, we do that
// and exit immediately... todo: how to avoid mutex/lazy_static entirely???
//let _ = KEY_MAPPER.lock().unwrap();
let config = parse_args();
println!("Config: {:?}", config);
let key_map = key_map();
println!("key_map: {:?}", key_map);
println!("chosen config file: {}", config.config_file);
let key_maps = MacOSKeyMaps::from_cfg(&key_map, &config.config_file);
//println!("key_maps: {}", key_maps);
let callback_pointer: CallbackPointer = (key_maps, CGEventSource::new(CGEventSourceStateID::Private).expect("Failed creating event source"));
let mask = CGEventMaskBit(kCGEventKeyDown)
| CGEventMaskBit(kCGEventKeyUp)
| CGEventMaskBit(kCGEventFlagsChanged)
let mask = CGEventMaskBit(CGEventType::KeyDown)
| CGEventMaskBit(CGEventType::KeyUp)
| CGEventMaskBit(CGEventType::FlagsChanged)
;
unsafe {
@ -205,10 +163,11 @@ pub fn main_res() -> Result<()> {
options,
mask,
callback,
&key_maps,
&callback_pointer,
);
assert!(!event_tap.is_null(),
"Unable to create event tap. Please make sure you have the correct permissions");
if event_tap.is_null() {
panic!("Unable to create event tap. Please make sure you have the correct permissions");
}
println!("Created event tap...");
let allocator = kCFAllocatorDefault;
@ -308,44 +267,22 @@ fn parse_args() -> Config {
}
use libc;
use core_graphics::event::CGEventType::Null;
// Opaque Pointer Types
pub type Pointer = *mut libc::c_void;
pub type CGEventRef = Pointer;
pub type CFMachPortRef = Pointer;
type Pointer = *mut libc::c_void;
type CFMachPortRef = Pointer;
// Integer Types
pub type CGEventField = u32;
pub type CGEventMask = u64;
pub type CGEventTapLocation = u32;
pub type CGEventTapOptions = u32;
pub type CGEventTapPlacement = u32;
pub type CGEventType = u32;
pub type CGEventFlags = u64;
//pub type CGKeyCode = u16;
type CGEventMask = u64;
type CGEventTapOptions = u32;
type CGEventTapPlacement = u32;
// Callback Type
pub type CGEventTapCallBack = extern "C"
fn(Pointer, CGEventType, CGEventRef, &mut MacOSKeyMaps) -> CGEventRef;
type CGEventTapCallBack = extern "C" fn(Pointer, CGEventType, CGEvent, &mut CallbackPointer) -> CGEvent;
// Constants
/*
pub const kCGEventKeyDown: CGEventType = CGEventType::KeyDown;
pub const kCGEventKeyUp: CGEventType = CGEventType::KeyUp;
pub const kCGEventFlagsChanged: CGEventType = CGEventType::FlagsChanged;
pub const kCGSessionEventTap: CGEventTapLocation = 1;
pub const kCGHeadInsertEventTap: CGEventTapPlacement = 0;
pub const kCGKeyboardEventKeycode: CGEventField = 9;
pub const kCGEventTapDisabledByTimeout: CGEventType = CGEventType::TapDisabledByTimeout;
*/
pub const kCGEventKeyDown: CGEventType = 10;
pub const kCGEventKeyUp: CGEventType = 11;
pub const kCGEventFlagsChanged: CGEventType = 12;
pub const kCGSessionEventTap: CGEventTapLocation = 1;
pub const kCGHeadInsertEventTap: CGEventTapPlacement = 0;
pub const kCGKeyboardEventKeycode: CGEventField = 9;
pub const kCGEventTapDisabledByTimeout: CGEventType = 0xFFFFFFFE;
const kCGSessionEventTap: CGEventTapLocation = CGEventTapLocation::HID;
const kCGHeadInsertEventTap: CGEventTapPlacement = 0;
// Link to ApplicationServices/ApplicationServices.h and Carbon/Carbon.h
#[link(name = "ApplicationServices", kind = "framework")]
@ -364,14 +301,6 @@ pub const kCGEventTapDisabledByTimeout: CGEventType = 0xFFFFFFFE;
/// Obtain the current threads loop
pub fn CFRunLoopGetCurrent() -> Pointer;
/// Get the code of the event back, e.g. the key code
pub fn CGEventGetIntegerValueField(
event: CGEventRef,
field: CGEventField,
) -> CGKeyCode;
fn CGEventSetIntegerValueField(event: CGEventRef, field: CGEventField, value: i64);
/// Create an event tap
///
/// # Arguments
@ -419,7 +348,7 @@ pub const kCGEventTapDisabledByTimeout: CGEventType = 0xFFFFFFFE;
options: CGEventTapOptions,
eventsOfInterest: CGEventMask,
callback: CGEventTapCallBack,
channel: &MacOSKeyMaps,
channel: &CallbackPointer,
) -> CFMachPortRef;
/// Creates a CFRunLoopSource object for a CFMachPort
@ -442,150 +371,44 @@ pub const kCGEventTapDisabledByTimeout: CGEventType = 0xFFFFFFFE;
);
pub fn CGEventTapEnable(port: CFMachPortRef, enable: bool);
pub fn CGEventGetType(event: CGEventRef) -> CGEventType;
pub fn CGEventGetFlags(event: CGEventRef) -> CGEventFlags;
pub fn CGEventSetFlags(event: CGEventRef, flags: CGEventFlags);
}
const CGEventFlagNull: u64 = 0;
// Device-independent modifier key bits.
const CGEventFlagAlphaShift: u64 = 0x00010000;
const CGEventFlagShift: u64 = 0x00020000;
const CGEventFlagControl: u64 = 0x00040000;
const CGEventFlagAlternate: u64 = 0x00080000;
const CGEventFlagCommand: u64 = 0x00100000;
// Special key identifiers.
const CGEventFlagHelp: u64 = 0x00400000;
const CGEventFlagSecondaryFn: u64 = 0x00800000;
// Identifies key events from numeric keypad area on extended keyboards.
const CGEventFlagNumericPad: u64 = 0x00200000;
// Indicates if mouse/pen movement events are not being coalesced
const CGEventFlagNonCoalesced: u64 = 0x00000100;
const NX_DEVICELCTLKEYMASK: u64 = 0x00000001;
const NX_DEVICERCTLKEYMASK: u64 = 0x00002000;
const NX_DEVICELSHIFTKEYMASK: u64 = 0x00000002;
const NX_DEVICERSHIFTKEYMASK: u64 = 0x00000004;
const NX_DEVICELCMDKEYMASK: u64 = 0x00000008;
const NX_DEVICERCMDKEYMASK: u64 = 0x00000010;
const NX_DEVICELALTKEYMASK: u64 = 0x00000020;
const NX_DEVICERALTKEYMASK: u64 = 0x00000040;
const NX_DEVICERCTLKEYMASK: u64 = 0x00002000;
fn print_flags(flags: CGEventFlags) {
println!("flags: {}", flags);
println!("flags: {:#064b}", flags);
println!("EventFlags: {:x} ({} {} {} {} {} {} {} {})\n",
flags,
if (flags & NX_DEVICELCTLKEYMASK) != 0 { "lcontrol" } else { "" },
if (flags & NX_DEVICERCTLKEYMASK) != 0 { "rcontrol" } else { "" },
if (flags & NX_DEVICELSHIFTKEYMASK) != 0 { "lshift" } else { "" },
if (flags & NX_DEVICERSHIFTKEYMASK) != 0 { "rshift" } else { "" },
if (flags & NX_DEVICELCMDKEYMASK) != 0 { "lcommand" } else { "" },
if (flags & NX_DEVICERCMDKEYMASK) != 0 { "rcommand" } else { "" },
if (flags & NX_DEVICELALTKEYMASK) != 0 { "lalt" } else { "" },
if (flags & NX_DEVICERALTKEYMASK) != 0 { "ralt" } else { "" },
);
}
const NX_DEVICECAPSLOCKMASK: u64 = 1 << 16;
/// This callback will be registered to be invoked from the run loop
/// to which the event tap is added as a source.
#[no_mangle]
#[allow(unused_variables)]
pub extern fn callback(proxy: Pointer, event_type: CGEventType, event: CGEventRef, key_maps: &mut MacOSKeyMaps)
-> CGEventRef {
//print_flags(event);
/*
println!("+++++++++++++++++++++++++++++++++++++++");
let event_type2 = unsafe { CGEventGetType(event) };
println!("event_type2: {}", event_type2);
match event_type {
kCGEventKeyDown => println!("key down"),
kCGEventKeyUp => println!("key up"),
kCGEventFlagsChanged => println!("flags changed"),
kCGEventTapDisabledByTimeout => {
println!("Quartz event tap disabled because of timeout; attempting to reregister.");
//register_listener(channel);
//return event;
},
_ => {
println!("Received unknown EventType: {}", event_type as u32);
//return event;
},
};
*/
unsafe {
let mut input_event = InputEvent {
event_type,
event,
};
println!("got keyCode: {}", input_event.code());
/*
println!("---------------------------------------");
if input_event.value() == KeyState::DOWN {
let code = input_event.code();
println!("KEY 0x{:04X}", code);
write_key_file(code).expect("error writing key file");
#[allow(unused_variables, improper_ctypes_definitions)]
pub extern fn callback(proxy: Pointer, event_type: CGEventType, mut event: CGEvent, callback_pointer: &mut CallbackPointer) -> CGEvent {
let (key_maps, event_source) = callback_pointer;
match tapLocation {
CGEventTapLocation::HID => {
let user_data = event.get_integer_value_field(EventField::EVENT_SOURCE_USER_DATA);
if user_data == uniqueHIDUserData {
return event;
}
}
std::ptr::null_mut()
*/
_ => {}
};
//input_event.event.set
//input_event.event
//Null.
//Some(input_event.event)
key_maps.send_event(&mut input_event, &DEVICE).expect("macos shouldn't error...")
.unwrap_or_else(|| {
println!("returning NULL from hook");
std::ptr::null_mut()
}) // None means return NULL
//let keyCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
//println!("got keyCode: {}", keyCode);
/*
let event = KeyEvent {
etype: match etype as u32 {
kCGEventKeyDown => EventType::KeyDown,
kCGEventKeyUp => EventType::KeyUp,
kCGEventFlagsChanged => EventType::FlagsChanged,
kCGEventTapDisabledByTimeout => {
warn!("Quartz event tap disabled because of timeout; attempting to reregister.");
register_listener(channel);
return event;
},
_ => {
error!("Received unknown EventType: {:}", etype);
return event;
},
},
code: keyCode,
};
println!("Received event: {:?}", event);
let _ = channel.send(event);
*/
key_maps.send_event(&mut event, &event_source).expect("macos shouldn't error...")
.unwrap_or_else(|| {
event.set_type(CGEventType::Null);
event
}) // None means return NULL
}
//event
}
fn write_key_file(code: CGKeyCode) -> std::io::Result<()> {
let mut buffer = File::create("/Users/mopar/key.txt")?;
write!(buffer, "0x{:04X}", code)?;
Ok(())
}
/// Redefine macro for bitshifting from header as function here
pub fn CGEventMaskBit(eventType: u32) -> CGEventMask {
1 << (eventType)
}
/// Redefine macro for bitshifting from header as function here
pub fn CGEventMaskBit(eventType: CGEventType) -> CGEventMask {
1 << (eventType as u32)
}

View File

@ -4,6 +4,8 @@ After=systemd-udevd.service
[Service]
ExecStart=/usr/bin/rusty-keys
Restart=always
RestartSec=1s
[Install]
WantedBy=default.target