Open dPowNextdoor opened 3 years ago
+1
+2
+3
+4
+5
+6
+7
+8
it will be a helpful feature
Vote for 10086
I'd like to offer some perspective to those who come to this software in hopes of rather complex behavior at the push of a button, as I did.
I am using both Windows and Mac (the latter being the new addition) and my setup is such that I have created a custom keyboard layout that I now use on both systems for all the simple stuff. For more complex stuff, I need additional software, especially in order to have more or less the same hotkeys on both systems.
I've spent a few days trying to get even a single function to work with Karabiner that would take minutes with AutoHotKey. Obviously, being new to Karabiner, I cannot expect the same speed yet. But it just doesn't work and will likely never work, because, and that is the main point: according to what I have seen in my trial, Karabiner is not an automation tool, it is really focussed on remapping your keyboard. I think it's already doing too much in that regard, which enables this kind of confusion, at least that's part of what happened to me.
Therefore, for anybody who is dissattisfied with the feature scope here, accept the reality that your use-case differs from the app's target and look for an automation tool that allows you to capture and send keyboard events and do whatever you want based on that. Hammerspoon seems to be such a tool, for example.
To the authors of Karabiner: This is not intended to talk badly about your work or the app itself. I think it is a very nice tool for what it is supposed to do, and I was especially happy with the event viewer, which is definitely better than that of AHK.
+9
I've got the following custom script:
{
"description": "hjkl for Guitar Pro",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h"
},
"to": [
{
"key_code": "left_arrow"
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j"
},
"to": [
{
"key_code": "down_arrow"
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k"
},
"to": [
{
"key_code": "up_arrow"
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l"
},
"to": [
{
"key_code": "right_arrow"
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"command"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"command"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"command"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"command"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"shift"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"shift"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"shift"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"shift"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"shift"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"shift"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"shift"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"shift"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"shift",
"command"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"shift",
"command"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"shift",
"command"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"shift",
"command"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"shift",
"control"
]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"shift",
"control"
]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": [
"shift",
"control"
]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": [
"^com\\.arobas-music\\.guitarpro7"
],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"shift",
"control"
]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": [
"shift",
"command"
]
}
],
"type": "basic"
}
]
}
Which could be reduced to something like:
{
"description": "hjkl for Guitar Pro",
"manipulators": [
{
"conditions": [
{
"bundle_identifiers": ["^com\\.arobas-music\\.guitarpro7"],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "h",
"modifiers": {
"optional": ["command, control, shift"]
}
},
"to": [
{
"key_code": "left_arrow",
"modifiers": ["pass_through"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": ["^com\\.arobas-music\\.guitarpro7"],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "j",
"modifiers": {
"mandatory": ["command, control, shift"]
}
},
"to": [
{
"key_code": "down_arrow",
"modifiers": ["pass_through"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": ["^com\\.arobas-music\\.guitarpro7"],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "k",
"modifiers": {
"mandatory": ["command, control, shift"]
}
},
"to": [
{
"key_code": "up_arrow",
"modifiers": ["pass_through"]
}
],
"type": "basic"
},
{
"conditions": [
{
"bundle_identifiers": ["^com\\.arobas-music\\.guitarpro7"],
"type": "frontmost_application_if"
}
],
"from": {
"key_code": "l",
"modifiers": {
"mandatory": ["command, control, shift"]
}
},
"to": [
{
"key_code": "right_arrow",
"modifiers": ["pass_through"]
}
],
"type": "basic"
}
]
}
The second one would really be great to have.
My two cents after finding this thread:
I'm a software developer who wanted to remap some things when using WhatsApp Desktop:
Cmd+Return
Return
This was as simple as using ChatGPT:
Create a complex rule for Karabiner Elements on macOS that changes the Return key for the WhatsApp desktop app to be "Shift+Return" and make "Cmd + Return" be the "Return" key
After a couple more messages, 2 working rules were created (attached). return_to_shift-return.json cmd-return_to_return.json
Maybe this helps someone!
Instead of a rules engine, it would be nice if I could write Lua, or really, any embedded language.
Expressing complex conditionals in a configuration file is always going to be painful to some degree.
Thanks for the detailed input! A good way to steer development towards this would be to send in a pull request with an attempt at implementing this so there is something to start from.
Issue
Writing complex modification rules for Karabiner is an all but manual process. There are external GUIs out there that format the JSON for you, but they don't have autocomplete, nor do they work for specific, environment-specific conditions, variables, etc. As such, they offer no benefit other than formatting JSON.
Furthermore, as stated here and reiterated here, Karabiner is currently very limited in that it ignores rules that are defined after other rules even if they technically have different conditions.
These issues include, but are not limited to:
Less specific rules overriding more specific rules
I can't write the below config and have both rules activated because the first overrides the second. This doesn't appear terrible at first until you have many rules, either within one file or in separate files, and they end up not working as expected because an earlier rule conflicts with a later rule.
Then you're forced to rewrite all previous rules to include
condition_unless
or to dissect how all imported rules work to find the issue all BY HAND.Example: Fails without `frontmost_application_unless` in first rule
```json { "title": "Ctrl --> Command except in IDE, but I don't work!", "rules": [ { "description": "Ctrl --> Command", "manipulators": [ { "type": "basic", "from": { "key_code": "left_control", "modifiers": { "optional": [ "any" ] } }, "to": [ { "key_code": "left_command" } ] }, { "type": "basic", "from": { "key_code": "left_control", "modifiers": { "optional": [ "any" ] } }, "to": [ { "key_code": "left_control" } ], "conditions": [ { "type": "frontmost_application_if", "bundle_identifiers": [ "com.jetbrains.*" ] } ] } ] } ] } ```Related rules/manipulators all require possibly infinite amounts of duplicated code
If there exists a rule with many related manipulators, I have to duplicate the conditions for that rule in every single entry, resulting in a config that is both difficult to read and less configurable. Then, If I decide I want to add a new application in
frontmost_application_if
, I have to do it multiple times even though it's all for the same rule.Example: Fails without `device_if` in every rule/manipulator
```json { "title": "Make Mac keys work like PC (Linux/Windows) on external keyboard", "rules": [ { "description": "Ctrl/Command to behave like PC (PC: Ctrl=Ctrl, Super=Command, Alt=Option)", "manipulators": [ { "type": "basic", "from": { "key_code": "left_control", "modifiers": { "optional": [ "any" ] } }, "to": [ { "key_code": "left_command" } ], "conditions": [ "Oh no, I forgot to add device_if here :'c ", "Ugh, after hours of debugging, finally tracked down that bug.", "[some time later]", "Wait, now I want to add a new external keyboard!", "Looks like I have to edit every single rule I have D:< " ] }, { "type": "basic", "from": { "key_code": "left_command", "modifiers": { "optional": [ "any" ] } }, "to": [ { "key_code": "left_option" } ], "conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 1234 } ] } ] }, { "type": "basic", "from": { "key_code": "left_option", "modifiers": { "optional": [ "any" ] } }, "to": [ { "key_code": "left_control" } ], "conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 1234 } ] } ] } ] } ] } ```TL;DR
The current rule format has many issues and needs revisiting. Changing them would solve some of the most common issues users experience.
Yes, some of the examples (especially the
jetbrains
one) above could be solved by just reordering them, but that was just a minimally-reproducible example. In a real life scenario that's not always possible depending on what rules a user imported or certain rule dependencies (or at least not reasonable, even if possible, because you'd have to e.g. dissect rules downloaded from the internet).Priority: HIGH
It seems that most reported issues are related to this.
Proposal
Make Karabiner complex modifications extendable. Allow:
rules
.manipulators
.type
.type
.frontmost_application_unless
, etc. rules since the rules that apply only to those applications are overridden only in that application's rule/manipulators.condition.id
andcondition.overrides[ids]
fields so users can specify which conditions they want to override manually.This would be an incredibly better way to write rules/conditions, especially since the entries' contents have to be written manually. It also means that similar manipulators can be grouped into one rule instead of spreading their logic across multiple rules (e.g.
frontmost_application_unless
) and/or breaking because the user accidentally imported them in the wrong order (e.g.frontmost_application_if
not working due to a previous/global rule using the same key combo).Also, this idea already has support from other users, so it's clearly a highly desired feature.
This would result in solving a majority of the issues users post and probably attract new users!
Examples
Simple
Better application-only rules
All levels of conditions