Karabiner

User avatar
Muirium
µ

01 Jan 2022, 13:08

Oh yeah, tweaked the AppleScripts for toggling Auto Brightness:

Code: Select all

--Check if System Preferences already open?
--Don't want to quit it on exit if it's already running
if application "System Preferences" is running then
	set appRunning to true
else
	set appRunning to false
	display notification "Automatic Brightness: Running…" with title "Automatic Display Brightness"
	tell application "System Preferences"
		activate
		set current pane to pane id "com.apple.preference.displays"
		delay 2
	end tell
end if

--Toggle Automatic Display Brightness
tell application "System Preferences"
	set current pane to pane id "com.apple.preference.displays"
	tell application "System Events"
		tell process "System Preferences"
			tell checkbox "Automatically adjust brightness" of group of window 1
				click
				--Display a matching notification
				if value = {0} then
					display notification "Automatic Brightness Disabled: Manual Override" with title "Manual Display Brightness"
				end if
				if value = {1} then
					display notification "Automatic Brightness Enabled: Sensor Engaged" with title "Automatic Display Brightness"
				end if
			end tell
		end tell
	end tell
end tell

--Quit System Preferences if this script opened it up
if appRunning = false then
	delay 1
	tell application "System Preferences" to quit
end if
And True Tone:

Code: Select all

--Check if System Preferences already open?
--Don't want to quit it on exit if it's already running
if application "System Preferences" is running then
	set appRunning to true
else
	set appRunning to false
	display notification "True Tone: Running…" with title "True Tone"
	tell application "System Preferences"
		activate
		set current pane to pane id "com.apple.preference.displays"
		delay 2
	end tell
end if

--Toggle Automatic Display Brightness
tell application "System Preferences"
	set current pane to pane id "com.apple.preference.displays"
	tell application "System Events"
		tell process "System Preferences"
			tell checkbox "True Tone, Automatically adapt display to make colours appear consistent in different ambient lighting conditions." of group of window 1
				click
				--Display a matching notification
				if value = {0} then
					display notification "True Tone Disabled: Manual Override" with title "True Tone"
				end if
				if value = {1} then
					display notification "True Tone Enabled: Sensor Engaged" with title "True Tone"
				end if
			end tell
		end tell
	end tell
end tell

--Quit System Preferences if this script opened it up
if appRunning = false then
	delay 1
	tell application "System Preferences" to quit
end if
They provide immediate feedback even when System Preferences isn't already open now. I don't like laggy UIs!

User avatar
Muirium
µ

05 Feb 2022, 10:38

You show your love by filing bugs. :roll: :D

When:
Single open ‘ quote
Single close ’ quote
Double open “ quote
Double close ” quote
Single dumb ' doubledumbumb " quote's
em—dash en–dash hy-phen e…lipsis
和一些中文文本
और कुछ हिंदी पाठ
🍆🤷 “Who, me?” F‘rlz?
Becomes:
single open ‘ quote
single close ’ quote
double open “ quote
double close ” quote
single dumb ' doubledumbumb " quote's
em—dash en–dash hy-phen e…lipsis
???????
?? ??? ????? ???
???? “who, me?” f‘rlz?
Oy oy oy…

xxhellfirexx

05 Feb 2022, 21:32

Muirium wrote:
05 Feb 2022, 10:38
You show your love by filing bugs. :roll: :D
What happens when you escape the characters?

https://dencode.com/en/string/unicode-escape

User avatar
Muirium
µ

06 Feb 2022, 12:15

Well, using that tool you linked:
\u0053\u0069\u006e\u0067\u006c\u0065\u0020\u006f\u0070\u0065\u006e\u0020\u2018\u0020\u0071\u0075\u006f\u0074\u0065\u000d\u000a\u0053\u0069\u006e\u0067\u006c\u0065\u0020\u0063\u006c\u006f\u0073\u0065\u0020\u2019\u0020\u0071\u0075\u006f\u0074\u0065\u000d\u000a\u0044\u006f\u0075\u0062\u006c\u0065\u0020\u006f\u0070\u0065\u006e\u0020\u201c\u0020\u0071\u0075\u006f\u0074\u0065\u000d\u000a\u0044\u006f\u0075\u0062\u006c\u0065\u0020\u0063\u006c\u006f\u0073\u0065\u0020\u201d\u0020\u0071\u0075\u006f\u0074\u0065\u000d\u000a\u0053\u0069\u006e\u0067\u006c\u0065\u0020\u0064\u0075\u006d\u0062\u0020\u0027\u0020\u0064\u006f\u0075\u0062\u006c\u0065\u0064\u0075\u006d\u0062\u0075\u006d\u0062\u0020\u0022\u0020\u0071\u0075\u006f\u0074\u0065\u0027\u0073\u000d\u000a\u0065\u006d\u2014\u0064\u0061\u0073\u0068\u0020\u0065\u006e\u2013\u0064\u0061\u0073\u0068\u0020\u0068\u0079\u002d\u0070\u0068\u0065\u006e\u0020\u0065\u2026\u006c\u0069\u0070\u0073\u0069\u0073\u000d\u000a\u548c\u4e00\u4e9b\u4e2d\u6587\u6587\u672c\u000d\u000a\u0914\u0930\u0020\u0915\u0941\u091b\u0020\u0939\u093f\u0902\u0926\u0940\u0020\u092a\u093e\u0920\u000d\u000a\ud83c\udf46\ud83e\udd37\u0020\u201c\u0057\u0068\u006f\u002c\u0020\u006d\u0065\u003f\u201d\u0020\u0046\u2018\u0072\u006c\u007a\u003f
Which then successfully remains that same sequence of harmless ASCII characters all the way through my debug text file chain. But unfortunately also remains jibberish at the end! Pasting it back into the converter returns my original Unicode sample text, without any transformation. (Same is true for my capitalisation etc. scripts, which just consider the text as literal ASCII, not encoded Unicode.)

To paraphrase Bart Simpson: I'm aware of escaped characters. (Not the same thing as knowing how to use them.) :lol:

User avatar
Muirium
µ

07 Feb 2022, 18:24

Here's a little escaping in action. No success, however. Karabiner's quite the fortress! :roll:

I guess what you mean is I could find and replace all my non-ASCII characters in the output of my scripts, and escape them, relying on Karabiner to decode this on the way out. That seems to be happening with the smart quotes which perplexed me so in my example. They seem to come back from out of nowhere. Something is doing that. The same must be true on the way in to my scripts. Maybe I could hack something up to exploit this?

Yeah, maybe. I'd rather they fixed it, but. The sed and tr stuff I do in my scripts is more my level of programming than opening up the whole project and finding the bit where it needs bumped up to UTF-8. I'm sure I'd wreck the whole thing, no matter how lightly I touched. :lol:

User avatar
stratokaster

07 Feb 2022, 22:24

Muirium wrote:
23 Mar 2021, 12:52
As far as laptops go, the Air's keyboard is obviously much better than those from the horrific "Butterfly" era.
I tried them at our local Apple dealership and did not like them at all. I prefer the crisp "snap" of the butterfly keyboard, but yeah, the butterfly's reliability was a bit hit-and-miss :? They are also much worse than some ThinkPads I have tried. In fact, I have a very beaten up ThinkPad X230 in my possession -- more as a historical artifact than a useful device (it's probably the last completely modular ultraportable laptop) -- and it has an excellent keyboard, far better than any Apple laptop I have ever used or tried.

Also I noticed that every single new Apple laptop on display already had very shiny keys, it seems Apple used especially cheap and nasty coating this time around.

User avatar
Muirium
µ

08 Feb 2022, 01:17

As I said in the opening post, I'm talking strictly about super thin laptop keyboards. I have no plans to replace my 3276 here with a millimetre thin chiclet keyboard, no matter how reliable or snappy. Honestly, the front door this thing has for holding its instruction manual is thicker than the MacBook Air's whole keyboard. :lol:

Seeing as we're /offtopicthority here, I'll crow about how much I prefer my svelte little M1 Air over its more beastly M1 Max brothers which came out in the meantime. They're impressive machines and I'm glad they exist but they're not for me, and I'm cool with that. The CPU in this little guy is still running circles around everything I ever do with it, and I routinely carry this Mac around town on my back, so every gram counts along with those saved millimetres. The fact I can use it docked so neatly, without any performance compromises I've encountered, is something I'm well chuffed about. No sync issues, all state is preserved when switching between my laptop and desktop, and the slick 'lil bugger still has no fan to even think about annoying me the way computers have ever since the blessed silent era before hard drives! Still very much in love with this Mac of mine. 😄

When we've some bloody light again, I'll shoot some pics of its very well used keyboard, and my 2003 PowerBook's. That one—very same Apple UK layout—I wore all the way through on the A key, as I remember. I like that keyboard for its sculpted caps and fair decent (laptop) feel. Still prefer it to my Air's, as I recall, though it's been a while. They weren't any better made back then, just significantly thicker so with more leeway for the design. I shine PBT, I'm that prolific, so the shine on these ABS laptops is just a mark of their battles, like those scuffs all over everything in Star Wars. They’ve been through a lot.

User avatar
Muirium
µ

08 Feb 2022, 11:41

Karabiner's lead dev got back to me. Apparently I just need to prefix export LC_ALL=en_GB.UTF-8; to my command-line scripts. Dirty but it works.

User avatar
stratokaster

08 Feb 2022, 12:29

Muirium wrote:
08 Feb 2022, 11:41
Karabiner's lead dev got back to me. Apparently I just need to prefix export LC_ALL=en_GB.UTF-8; to my command-line scripts. Dirty but it works.
Instead of editing all of your scripts, you could try adding this line to your ~/.bash_profile or whatever its replacement is in recent versions of macOS, ~/.zprofile? But it's not guaranteed to work since in macOS, unlike other POSIX-compliant operating systems, GUI processes don't inherit environment variables set in the user's profile.
Last edited by stratokaster on 08 Feb 2022, 13:07, edited 1 time in total.

User avatar
Muirium
µ

08 Feb 2022, 12:42

Well, I already bunged that into all of them—single find and replace job—and everything works now. But I get what you mean. zsh is the Mac's default shell (always used to be bash but changed some years back). I opened ~/.zprofile which does indeed exist (modified date January 2021) but is in fact empty! Huh.

Maybe if I defined it in there… I'm guessing just LC_ALL=en_GB.UTF-8 should do the trick? All too literally guessing! :lol:

Terminal, meanwhile, uses en_GB.UTF-8 and so ran my scripts perfectly from the start. Settings heaped upon settings!

User avatar
stratokaster

08 Feb 2022, 13:07

Muirium wrote:
08 Feb 2022, 12:42
Maybe if I defined it in there… I'm guessing just LC_ALL=en_GB.UTF-8 should do the trick? All too literally guessing! :lol:
No, it should be:

Code: Select all

export LC_ALL=en_GB.UTF-8
Your .zprofile is still a regular shell script, but it's supposed to be executed automatically when you log into the system.
Muirium wrote:
08 Feb 2022, 12:42
Terminal, meanwhile, uses en_GB.UTF-8 and so ran my scripts perfectly from the start. Settings heaped upon settings!
Yes, I've been tripped up by this bullshit countless times over the years. As I said, GUI processes in macOS don't inherit your environment variables. This means that if you run your script in the Terminal, it runs fine. But if you use some kind of GUI application to trigger it — like Spark or FastScripts — you'd get all kinds of weird behaviour.
Last edited by stratokaster on 08 Feb 2022, 13:53, edited 1 time in total.

User avatar
Muirium
µ

08 Feb 2022, 13:28

Threw that in there. Reverted the scripts. They're back to their old broken behaviour. Restarted the Mac. No dice, still the old way. Blast! :P

User avatar
stratokaster

08 Feb 2022, 13:54

Oh well, at least we've tried :lol:

User avatar
Muirium
µ

08 Feb 2022, 14:03

Indeed! Thanks for trying. These ????Äî� scripts of mine have been a special kind of fun.

Image

Anywho, that repetitive boilerplate prefix aside, they're working great!

User avatar
Muirium
µ

09 Feb 2022, 09:55

Anyone fancy joining in my request for Karabiner to default to Unicode?
Note that by default the Terminal application uses the UTF 8 encoding and automatically sets the appropriate locale environment variable.
Shouldn't Karabiner do the same? I can't think of any reason not to use UTF-8. It prevents corruption bugs like the ones afflicting my code, which were extra confusing as Terminal always got them right.
Its lead dev says he’ll consider it, with enough requests.

User avatar
Muirium
µ

10 Feb 2022, 11:56

Updated OP with some fresh pics. Here's another: my Macintosh brothers in arms. They've been through a lot!

The Shining.jpg
The Shining.jpg (351.97 KiB) Viewed 23194 times

Who needs Intels?

The PowerBook's keyboard is still nicer to type on. I especially like its sculpted caps—free from the bland constraints of chiclet flatland—and its extra travel is quite nice as well. But they aye shine up, too. Just take a look!

Aaaaa!.jpg
Aaaaa!.jpg (897.13 KiB) Viewed 23194 times

Amusingly, the legend's still intact. But the fake silver shine? Hoo doozy! Its tiny little trackpad is also well shined up. So much so, it's actually kinda nice to scoot around on. You know, that half second or so until you hit those aluminium edges!

User avatar
wobbled

11 Feb 2022, 17:26

That powerbook looks in great shape except for the keyboard Mu, do you think you'd ever sell it on?

User avatar
Muirium
µ

12 Feb 2022, 10:19

Thanks for the kind observation! I've always been a bit OCD (or "fastidious" as we used to say)—never even ate at my computers as a kid—so yeah my hardware's generally quite sparkly, besides those hard worn keys!

Now, you asked a question of two parts…
  • Did you see my other picture, in the OP? The aluminium shell is buckled a bit at the back right corner. That PowerBook had years of travelling with me and took a handful of drops. That's the evidence of the main one. It's not bad on the outside of the computer, no big crater dent, but you can see that corner bulge out from under the keyboard just like in the picture when you're using it. Also the LCD is a bit smeary right up at the top right corner, where the Spotlight icon lives in Tiger, an ancient cleaning attempt gone wrong. Thoroughly usable but no 10/10!
  • As for my willingness to sell, it'd be a really hard one. That 12 inch G4 is my first Mac. Bought new in 2003, I was still using it exclusively, day-in-day-out in 2009! (And part time till 2013.) Epic personal history. It's got the most sentimental value of any of my computers.

User avatar
Muirium
µ

10 Apr 2022, 12:08

Karabiner isn't the complete story for my typing automation, I will admit…
µAutocorrect Text Replacement in System Preferences.png
µAutocorrect Text Replacement in System Preferences.png (263.08 KiB) Viewed 22042 times
I made a habit of adding corrections when I notice myself making the same mistakes. I've automated this process a bit with Karabiner: to get to the Keyboard preference pane now I just hit Option F2. (I've added various pref panes to the usual ones along the function keys.) But if anyone knows how to automate switching to this tab and hitting the + button, I'm all ears! My lousy AppleScript-fu falls short.

User avatar
Muirium
µ

16 Aug 2022, 18:16

I implemented mouse control on numpads via Karabiner now—which works much better than doing it in QMK etc. on the boards themselves. I'll write it up when I'm happy with it, as I've made things complex with two separate versions: one for fullsize, and one for toggling the arrow key layer to mouse control on HHKBs and other compacts. Can't ever keep things simple, can I?

Anyway, you can tell what I've been up to from my feature requests. Yes: Karabiner must have control of all three lock lights! I just can't stop myself from trusting those lying things. :roll:

User avatar
Muirium
µ

18 Aug 2022, 00:50

So, I'd like to toggle the Num Lock light when entering numeric layers on my keyboards. Trouble is: the Mac has no such thing as Num Lock or Scroll Lock. (Not since the integrated numpad on the PowerBook at least.) Sounds like a job for Karabiner!

Only, it doesn't work. There is hope, though. A helpful commenter at GitHub pointed me to previous work on this: setledmac, which builds and runs and works quite nicely… albeit without Karabiner running. They don't play nice together.

But, seeing as I can play with my Num Lock LEDs now, I tried an experiment. How is Num Lock implemented in keyboards anyway?
Hooking up several keyboards, like a crazy person, I can report how this almost works. The lock light behaviour is a little different on different keyboards. Nothing I couldn't resolve with my own device_if complex rules in Karabiner, however. If only I could access them with it running…

Filco Majestouch 2 Tenkeyless: This USB native, non-programmable keyboard has Caps Lock and Scroll Lock lights, but no Num Lock. setledmac will manipulate "all 3", reporting no error when accessing the Num Lock which is not there. The keyboard behaves normally besides its lights. Entering Caps Lock does not GO ALL CAPS.

Topre Realforce 87u: This USB native, non-programmable tenkeyless keyboard has Caps Lock and Num Lock LEDs, integrated into their respective keys. setledmac will toggle the Caps Lock light with no effect on typing. But toggling the Num Lock light d6es 5n fact engage the 5ntegrated n40pad 06de! Turn the Num Lock light back off and the alpha keys are restored, so this keyboard does in fact internally produce numeric mode. EventViewer shows the keys as keypad_1 etc., matching all the front legends. Including even the comma key which becomes 00 by pressing 0 twice.

NMB RT8255C+: This fullsize vintage PC/AT keyboard has an internal TMK AT to USB programmable converter, and all 3 lock lights in hardware, above the numpad. setledmac freely manipulates all of them, and the keyboard simply sends the same keystrokes no matter their state. I believe this is how it's meant to be for all keyboards, without size-reducing sneaky tricks like Topre's above!
So, not all Num Locks are equal! Specifically, if a compact keyboard has an integrated numpad layer, one way of implementing it is to tie it to the state of Num Lock. That's not quite playing by the rules, but it works… on PC. My challenge is to make it so on the Mac. ;)

I've two different uses for Num Lock in mind, depending on whether a given keyboard fullsize vs. compact layout. On fullsize boards, I'd like to use the numpad as a mouse pointer control by default, hitting the Num Lock key to toggle into a numeric layer which returns the numpad to its numeric glory. Something quite like Num Lock as originally implemented on the PC, then, only to move the mouse around instead of the arrow keys which live just beside it.

On compacts, like my Realforce and Filco, I'd like to do the old numpad layer trick on the keys IBM, Apple and Topre all agreed should be used for the purpose: numpad 5 on I and so forth, aligning with the number row for 7 8 and 9. Num Lock would then light up when in this mode—again Num Lock indicates numbers—while no Num Lock light means back to normal business, alphabetic in this case.

Scroll Lock can wait for future expansion. :P

User avatar
Muirium
µ

04 Sep 2022, 21:06

As promised, my latest update: 🖱 Numpad Mouse Keys

This mode is entered by pressing Fn + M (mouse) on my HHKB. (Behind the scenes, I remapped Fn + M to F16 for this purpose.) You exit the mode by pressing Fn + N (navigation) right beside it. (Mapped to F18 internally, for Karabiner to catch it.) I didn't use a toggle this time because leaving the HHKB in Mouse mode is too disruptive. I want to be able to jam it directly in and out this mode without needing to think about it. So dedicated Mouse and Navigation Fn keys it is.

This file contains two different mousing rules, which are individually selectable in Karabiner’s complex modifications tab. One is for my beloved sixty percent boards, bringing them “HHKB-style” mouse keys on the familiar cursor keys. The other is for full-size keyboards, whose numpads are crying out for a good use. :D

Code: Select all

{
  "title": "🖱 Mouse Key Modes",
  "rules": [
    {
      "description": "🖱 Numpad Mouse Keys",
      "manipulators": [
        {
          "from": {
            "key_code": "keypad_num_lock",
            "modifiers": {
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "numpad_mode",
                "value": 1
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "from": {
            "key_code": "keypad_num_lock",
            "modifiers": {
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "numpad_mode",
                "value": 0
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 1
            }
          ]
        },
        {
          "from": {
            "key_code": "n",
            "modifiers": {
              "mandatory": [
                "fn"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "numpad_mode",
                "value": 1
              }
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_1",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x": -1500,
                "y":  1500
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_2",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "y": 2121
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_3",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x": 1500,
                "y": 1500
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_4",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x": -2121
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_5",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "y": 1000
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_6",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x": 2121
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_7",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x": -1500,
                "y": -1500
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_8",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "y": -2121
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_9",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "x":  1500,
                "y": -1500
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_hyphen",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "vertical_wheel": -48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_plus",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "vertical_wheel": 48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_0",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "pointing_button": "button1"
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_period",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "pointing_button": "button2"
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_slash",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "horizontal_wheel": 48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_asterisk",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "horizontal_wheel": -48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "numpad_mode",
              "value": 0
            }
          ]
        }
      ]
    },
    {
      "description": "🖱 HHKB Style Mouse Keys",
      "manipulators": [
        {
          "from": {
            "key_code": "f16",
            "modifiers": {
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "mouse_keys_mode",
                "value": 1
              }
            }
          ]
        },
        {
          "from": {
            "key_code": "f18",
            "modifiers": {
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "mouse_keys_mode",
                "value": 0
              }
            }
          ]
        },
        {
          "from": {
            "key_code": "n",
            "modifiers": {
              "mandatory": [
                "fn"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "type": "basic",
          "to": [
            {
              "set_variable": {
                "name": "mouse_keys_mode",
                "value": 0
              }
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "left_arrow"
          },
          "to": [
            {
              "mouse_key": {
                "x": -3000
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "right_arrow"
          },
          "to": [
            {
              "mouse_key": {
                "x": 3000
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "up_arrow"
          },
          "to": [
            {
              "mouse_key": {
                "y": -3000
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "down_arrow"
          },
          "to": [
            {
              "mouse_key": {
                "y": 3000
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "page_up"
          },
          "to": [
            {
              "mouse_key": {
                "vertical_wheel": -48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "page_down"
          },
          "to": [
            {
              "mouse_key": {
                "vertical_wheel": 48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "pause"
          },
          "to": [
            {
              "pointing_button": "button1"
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "delete_forward"
          },
          "to": [
            {
              "pointing_button": "button1"
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "f17"
          },
          "to": [
            {
              "pointing_button": "button2"
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "keypad_slash",
            "modifiers": {"optional": ["any"]}
          },
          "to": [
            {
              "mouse_key": {
                "horizontal_wheel": 48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        },
        {
          "type": "basic",
          "from": {
            "key_code": "home"
          },
          "to": [
            {
              "mouse_key": {
                "horizontal_wheel": -48
              }
            }
          ],
          "conditions": [
            {
              "type": "variable_if",
              "name": "mouse_keys_mode",
              "value": 1
            }
          ]
        }
      ]
    }
  ]
}
Points if you can figure out why some numpad keys move the mouse pointer 1500 × 1500 units while others move it 2121. Hint: love having true diagonals. Especially chording them with cardinal arrows to get the full complement of 16 directions like NNE and WSW. Feels immediately obvious when you have that “joystick” right there.

User avatar
Muirium
µ

17 Nov 2022, 18:08

Here's a good quickie:

Code: Select all

      {
         "description": "⎀Insert ⇨ 🌐Fn",
         "manipulators": [
            {
               "type": "basic",
               "from": {
                  "key_code": "insert",
                  "modifiers": {
                     "optional": [
                        "any"
                     ]
                  }
               },
               "to": {
                  "apple_vendor_top_case_key_code": "keyboard_fn"
               }
            }
         ]
      }
Turns the useless Insert key on any connected keyboard to the Apple special Fn key on your Mac. Tap it once for the character palette—which I use when naming these rules, of course—or hold as an extra modifier. Been using it since I found out about the apple_vendor_top_case_key_code group of keycodes. Sneaky Apple keeps them for itself, but even sneakier Karabiner lets us in.

User avatar
Muirium
µ

24 Nov 2022, 16:06

A more complex one. This rule strips [1] out [2] those [3][4] irritating [citation needed] square bracketed reference markers so common on Wikipedia. When I found myself Command + Fing for ] to go nix them by hand, I realised I know how to use sed for this:

Code: Select all

    {
      "description": "Dereference: ⌃ Control ] ⇨ Strip [references]",
      "manipulators": [
        {
          "from": {
            "key_code": "close_bracket",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "key_code": "c",
              "modifiers": [
                "left_command"
              ],
              "hold_down_milliseconds": 200
            },
            {
              "shell_command": "export LC_ALL=en_GB.UTF-8; pbpaste | sed 's/\\[[a-z ]*[0-9]*\\]//g' | pbcopy"
            },
            {
              "key_code": "left_command",
              "hold_down_milliseconds": 200
            },
            {
              "key_code": "v",
              "modifiers": [
                "left_command"
              ]
            }
          ],
          "type": "basic"
        }
      ]
    }
So now it's a keystroke: Control ] on any text selection, and those references are purged. :nerd:

The real work is in that shell_command, simply using sed with a [seeking] regex. Note the ungainly need to escape backslashes twice! The delays are there just to ensure that it all runs, as Karabiner can run ahead of MacOS (regardless of hardware) as I discovered earlier on this thread.

User avatar
Muirium
µ

22 Aug 2023, 12:50

Here's today's creation: a keyboard expression calculator. Hit Control = and it takes the current text selection, evaluates it, and prints = then the result. (Throw Shift into the mix and it outright replaces the selection.)

Code: Select all

    {
      "description": "∑ Calc: ⌃ Control = Equals ⇨ Calculate Expression and Paste",
      "manipulators": [
        {
          "from": {
            "key_code": "equal_sign",
            "modifiers": {
              "mandatory": [
                "control",
                "shift"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "key_code": "c",
              "modifiers": [
                "left_command"
              ],
              "hold_down_milliseconds": 200
            },
            {
              "shell_command": "export LC_ALL=en_GB.UTF-8; pbpaste | bc -l | sed '/\\./ s/\\.\\{0,1\\}0\\{1,\\}$//' | pbcopy"
            },
            {
              "key_code": "left_command",
              "hold_down_milliseconds": 200
            },
            {
              "key_code": "v",
              "modifiers": [
                "left_command"
              ]
            }
          ],
          "type": "basic"
        },
        {
          "from": {
            "key_code": "equal_sign",
            "modifiers": {
              "mandatory": [
                "control"
              ],
              "optional": [
                "caps_lock"
              ]
            }
          },
          "to": [
            {
              "key_code": "c",
              "modifiers": [
                "left_command"
              ],
              "hold_down_milliseconds": 200
            },
            {
              "shell_command": "export LC_ALL=en_GB.UTF-8; pbpaste | bc -l | sed '/\\./ s/\\.\\{0,1\\}0\\{1,\\}$//' | pbcopy"
            },
            {
            	"key_code": "right_arrow"
            },
            {
            	"key_code": "equal_sign"
            },
            {
              "key_code": "left_command",
              "hold_down_milliseconds": 200
            },
            {
              "key_code": "v",
              "modifiers": [
                "left_command"
              ]
            }
          ],
          "type": "basic"
        }
      ]
    }
I’m using bc to do the math, and a little sed to clean up the result to my taste. (Yes, those \ characters in the sed string are doubled because JSON…) The core of the thing is really like this: inevitably from Stack Overflow!

Code: Select all

bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'
I've almost got it where I want it. Examples:

Code: Select all

66+69=135 ← good
1/-0.33=-3.03030303030303030303 ← a bit too long
8/9=.88888888888888888888 ← I'd like it to start with a 0.
One other niggle: undesired newline characters, pushing my cursor one line down instead of staying flush with the result. Any suggestions? Something I'd really like is to concatenate repeating decimals like .888888 and 3.0303030 with a … after their first occurrence. 0.8… and 3.03… in their case. I know 3.03… is ambiguous—could be 3.03030303 or 3.033333333—but I’m interested to see how I can hack it.

There's a world of fiddly preferences when it comes to simple floating numbers. Who knew!? :D

I'll come back to it when I've next the itch.

User avatar
Muirium
µ

22 Aug 2023, 13:47

So I still had the itch. Hasn't done me much good, though. No idea why, as this works quite well for the missing initial 0. issue, when run in the terminal:

Code: Select all

printf %.4f $(pbpaste | bc -l <<< $0) | sed '/\./ s/\.\{0,1\}0\{1,\}$//' | pbcopy
printf takes bc's excessively long decimals, trims them down to 4 and inserts the initial 0 if needed. sed then does its thing on trailing 0s in the decimals.

Select and copy a string like -1e19/3e3 and you'll get -3333333333333333.5 without trailing zeroes. Run it on 1/9 and you'll get 0.1111 so not too bad. The trouble is all when I put it into Karabiner in the form of JSON:

Code: Select all

"shell_command": "export LC_ALL=en_GB.UTF-8; printf %.4f $(pbpaste | bc -l <<< $0) | sed '/\\./ s/\\.\\{0,1\\}0\\{1,\\}$//' | pbcopy"
The export LC_ALL guff is explained elsewhere in this thread. All I did to my command was escape the backslashes. It runs. But guess what? The answer is always '0'! On any expression. Whisky Tango Foxtrot?

From my experimenting so far: that printf seems to be the issue. Any time I take it out, things work, but without the formatting I want. Put it in, and it's fine in Terminal but spits out zero in Karabiner.

fanf

22 Aug 2023, 14:16

Dunno why it isn’t working, but you can probably bypass the problem using `bc -S 4` to set its scale to 4 instead of passing through printf

User avatar
Muirium
µ

22 Aug 2023, 14:39

Yeah, I tried changing scale on bc first. Trying again now, it's refusing everything I throw at it in the Terminal. Your command specifically:

Fatal error: bad command-line option: "S"

My Terminal is a comedy sketch right now of every permutation of S, Scale, space = () etc. that I can think of. The manpage is no help on this. I wound up settling on -l earlier as it returns a non-laughable answer for divisions like 1/3 != 0 bc! :P

User avatar
Muirium
µ

22 Aug 2023, 18:36

All right, I got it now. :nerd:

Code: Select all

"shell_command": "zsh -c 'printf \"%g\" $((1.0*$(pbpaste))) | pbcopy'"
%g is what I need. The bugger was trying to get simple printf to play ball in Karabiner. Once again its nasty old shell is the culprit—please update it, FFS!—and reverting to zsh meant I could calculate there and ditch (the truly aptly named) bc, if I could only work out how to get any of this to print. Finally did, first with double escaped $s and all the rest of it, then refactored down to this. What a messy path to get here!

Oh, the mandatory ×1.0 is simply to force floating point arithmetic on integers, as even zsh was dumb enough to tell me 10/3 == 3.0000 :roll:

Hmm… 2^2 isn't working right, where I obviously want 2 to the power of 2, not shifting. And bc could do sqrt() as well. I would still like to be able to evaluate expressions like (3^2)/(2^2)/(sqrt(16)/sqrt(9))

That nerdiness can wait for another cursed day!

Ah, bugger it, I’m still itchy. :ugeek:

Code: Select all

printf %g $(pbpaste | bc -l <<< $0)
Getting this *in there* is the hard part.

Code: Select all

"shell_command": "zsh -c 'printf %g $(pbpaste | bc -l <<< $0) | pbcopy'"
Try as I might, this don't work. 2^2=0 now so it does?

fanf

22 Aug 2023, 21:38

Ohhh I think it’s the <<< which is supported by your interactive shell (usually zsh on macOS) but not by /bin/sh (a POSIX sh derived from FreeBSD’s Almquist shell). I guess you can just delete the <<<$0 bit because bc will read your calculation from stdin by default.

I guess the 0 comes from bc reporting file <<< not found and printing nothing to stdout, and nothing evaluates to 0. And the $0 will expand to something like /bin/sh, not anything related to your expression.

Post Reply

Return to “Workshop”