Support multiple keyboards in remap-keys module

This commit is contained in:
T. R. Bernstein
2024-06-26 18:45:59 +02:00
committed by T. R. Bernstein
parent 97bb7bd9c5
commit 23016a639e

View File

@@ -7,31 +7,37 @@ function ensureRightAccess() {
chmod ugo=rx ${filesystemItem} chmod ugo=rx ${filesystemItem}
} }
function createRemapKeysBinary() { function getDataForMicrosoftKeyboard() {
cat > ${remapKeysPath} <<- BINARY local name="$1"
#!/bin/zsh [ "$name" == "ProductID" ] && echo '0x7a5'
PRODUCT_MATCHER='{"ProductID":0x7a5,"VendorID":0x45e}' [ "$name" == "VendorID" ] && echo '0x45e'
[ "$name" == "LaunchdServiceName"] && echo 'de.astzweig.macos.launchdaemons.microsoft-keymapper'
hasMappingBeenAlreadyActivated() { [ "$name" == "BinaryName" ] && echo 'remap-keys-microsoft'
local currentModifierKeyMappings="\`hidutil property --get UserKeyMapping -m '{"ProductID":0x7a5,"VendorID":0x45e}' | grep HIDKeyboardModifierMappingDst | wc -l\`" [ "$name" == "KeyMappings" ] && cat <<- KEYMAPPINGS
test "\${currentModifierKeyMappings}" -gt 1 {"HIDKeyboardModifierMappingSrc": 0x700000065, "HIDKeyboardModifierMappingDst": 0x7000000e7},
} {"HIDKeyboardModifierMappingSrc": 0x7000000e3, "HIDKeyboardModifierMappingDst": 0x7000000e2},
{"HIDKeyboardModifierMappingSrc": 0x7000000e2, "HIDKeyboardModifierMappingDst": 0x7000000e3}
hasMappingBeenAlreadyActivated && exit 0 KEYMAPPINGS
hidutil property --matching "\${PRODUCT_MATCHER}" --set '{"UserKeyMapping": [ }
{"HIDKeyboardModifierMappingSrc": 0x700000065, "HIDKeyboardModifierMappingDst": 0x7000000e7},
{"HIDKeyboardModifierMappingSrc": 0x7000000e3, "HIDKeyboardModifierMappingDst": 0x7000000e2}, function getDataForLogitechKeyboard() {
{"HIDKeyboardModifierMappingSrc": 0x7000000e2, "HIDKeyboardModifierMappingDst": 0x7000000e3} local name="$1"
]}' > /dev/null 2>&1 [ "$name" == "ProductID" ] && echo '0xc52b'
BINARY [ "$name" == "VendorID" ] && echo '0x46d'
ensureRightAccess ${remapKeysPath} [ "$name" == "LaunchdServiceName"] && echo 'de.astzweig.macos.launchdaemons.logitech-keymapper'
[ "$name" == "BinaryName" ] && echo 'remap-keys-logitech'
[ "$name" == "KeyMappings" ] && cat <<- KEYMAPPINGS
{"HIDKeyboardModifierMappingSrc": 0x7000000e6, "HIDKeyboardModifierMappingDst": 0x7000000e7},
{"HIDKeyboardModifierMappingSrc": 0x7000000e7, "HIDKeyboardModifierMappingDst": 0x7000000e6}
KEYMAPPINGS
} }
function createXPCConsumer() { function createXPCConsumer() {
[[ -x ${xpcConsumerPath} ]] && return 10
clang -framework Foundation -x objective-c -o ${xpcConsumerPath} - <<- BINARY clang -framework Foundation -x objective-c -o ${xpcConsumerPath} - <<- BINARY
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <xpc/xpc.h> #include <xpc/xpc.h>
int main(int argc, const char * argv[]) { int main(int argc, const char * argv[]) {
@autoreleasepool { @autoreleasepool {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
@@ -50,7 +56,42 @@ function createXPCConsumer() {
ensureRightAccess ${xpcConsumerPath} ensureRightAccess ${xpcConsumerPath}
} }
function getProductPlistDict() {
local dataProvider="$1"
cat <<- PLISTDICT
<dict>
<key>idProduct</key>
<integer>$(($($dataProvider ProductID)))</integer>
<key>idVendor</key>
<integer>$(($($dataProvider VendorID)))</integer>
<key>IOProviderClass</key>
<string>IOUSBDevice</string>
<key>IOMatchLaunchStream</key>
<true/>
</dict>
PLISTDICT
}
function createRemapKeysBinary() {
cat > ${binaryPath} <<- BINARY
#!/bin/zsh
PRODUCT_MATCHER='{"ProductID":$($dataProvider ProductID),"VendorID":$($dataProvider VendorID)}'
hasMappingBeenAlreadyActivated() {
local currentModifierKeyMappings="\`hidutil property --get UserKeyMapping -m "\${PRODUCT_MATCHER}" | grep HIDKeyboardModifierMappingDst | wc -l\`"
test "\${currentModifierKeyMappings}" -gt 1
}
hasMappingBeenAlreadyActivated || \
hidutil property --matching "\${PRODUCT_MATCHER}" --set '{"UserKeyMapping": [
$($dataProvider KeyMappings)
]}' > /dev/null 2>&1
BINARY
ensureRightAccess ${binaryPath}
}
function createLaunchDaemon() { function createLaunchDaemon() {
local dataProvider="$1"
cat > ${launchDaemonPath} <<- LDAEMON cat > ${launchDaemonPath} <<- LDAEMON
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -69,14 +110,7 @@ function createLaunchDaemon() {
<dict> <dict>
<key>com.apple.device-attach</key> <key>com.apple.device-attach</key>
<dict> <dict>
<key>idProduct</key> $(getProductPlistDict $dataProvider)
<integer>1957</integer>
<key>idVendor</key>
<integer>1118</integer>
<key>IOProviderClass</key>
<string>IOUSBDevice</string>
<key>IOMatchLaunchStream</key>
<true/>
</dict> </dict>
</dict> </dict>
</dict> </dict>
@@ -90,18 +124,33 @@ function enableLaunchDaemon() {
launchctl bootstrap system ${launchDaemonPath} launchctl bootstrap system ${launchDaemonPath}
} }
function createLaunchdService() {
local launchDaemonPath="/Library/LaunchDaemons/$($dataProvider LaunchdServiceName).plist"
[[ -f ${launchDaemonPath} ]] || indicateActivity -- 'Create Launch Daemon' createLaunchDaemon
indicateActivity -- 'Enable Launch Daemon' enableLaunchDaemon
}
function configureKeymappers() {
local mapper= dataProvider= binaryPath=
for mapper dataProvider in $(mappers); do
lop -y h1 -- -i "Configure ${mapper} Keymapper"
binaryPath="${dstDir}/$($dataProvider BinaryName)"
createRemapKeysBinary
createLaunchdService
done
}
function configure_system() { function configure_system() {
lop -y h1 -- -i 'Configure Microsoft Keyremapper' typeset -A mappers=(
local serviceName='de.astzweig.macos.launchdaemons.keymapper' [Microsoft]=getDataForMicrosoftKeyboard
[Logitech]=getDataForLogitechKeyboard
)
local dstDir='/usr/local/bin' local dstDir='/usr/local/bin'
local xpcConsumerPath="${dstDir}/astzweig-xpc-consumer" local xpcConsumerPath="${dstDir}/astzweig-xpc-consumer"
local remapKeysPath="${dstDir}/remap-keys"
local launchDaemonPath="/Library/LaunchDaemons/${serviceName}.plist" ensurePathOrLogError ${dstDir} 'Could not create destination dir for remap-keys binary.' || return 10
ensurePathOrLogError ${dstDir} 'Could not install remap-keys.' || return 10 indicateActivity -- 'Create XPC event consumer' createXPCConsumer
[[ -x ${remapKeysPath} ]] || indicateActivity -- 'Create remap-keys executable' createRemapKeysBinary configureKeymappers
[[ -x ${xpcConsumerPath} ]] || createXPCConsumer 'Create XPC event consuer'
[[ -f ${launchDaemonPath} ]] || createLaunchDaemon 'Create Launch Daemon'
indicateActivity -- 'Enable Launch Daemon' enableLaunchDaemon
} }
function getExecPrerequisites() { function getExecPrerequisites() {
@@ -119,10 +168,10 @@ function getUsage() {
Usage: Usage:
$cmdName show-questions [<modkey> <modans>]... $cmdName show-questions [<modkey> <modans>]...
$cmdName [-v] [-d FILE] $cmdName [-v] [-d FILE]
Install a system wide key remapper for the Microsoft Sculpt Keyboard using Install a system wide key remapper for the Microsoft Sculpt Keyboard using
macOS nativ hidutil, in order to swap command and option key. macOS nativ hidutil, in order to swap command and option key.
Options: Options:
-d FILE, --logfile FILE Print log message to logfile instead of stdout. -d FILE, --logfile FILE Print log message to logfile instead of stdout.
-v, --verbose Be more verbose. -v, --verbose Be more verbose.