Welcome to the lab.

Giveaway: The Keyboard Maestro Field Guide

[Tweet : nvALT]

I saw a great response to my post about MacSparky’s Keyboard Maestro Field Guide, and David was kind enough to provide some promo codes for a giveaway. If you haven’t checked it out, it contains everything you need to know to get started and dive deep with the Mac automation utility Keyboard Maestro.

I recently switched my hosting for this site, and as a result I had to rewrite the Killotron Giveaway Robot. I can’t easily run CouchDB on Dreamhost, so the whole thing is now backed by Firebase (no, I don’t want to work with mySQL, actually). So this is the first public run of the new setup, and if there are complications I’ll be immediately pulling this post and trying again after some fixes. But I think it’s working.

I have 5 copies of the Keyboard Maestro Field Guide to give away. Add your name and email below to enter the drawing. Winners will be randomly selected on July 15 at noon CST.

Sorry, this giveaway has ended.

Scripting Mac display brightness

[Tweet : nvALT]

After talking about it with the panel on a recent Mac Show appearance (pretty sure this part of the conversation happened during technical difficulties), I pulled out my Griffin PowerMate. The older USB one. While I did upgrade to the Bluetooth version, I still like the USB one better1. For various reasons, I’d replaced it with my Shuttle Xpress on my desk, but I found space to comfortably use both and set about re-configuring the actions on it.

Meanwhile, I keep waking up too early and being unable to fall back asleep2. Which means I slog to my computer in the dark, and coming out of a pitch black room means adjusting my monitor brightness more than “automatically adjust brightness” will accommodate. With BetterTouchTool and my Ultimate Hacking Keyboard I have Fn-M and Fn-N assigned to simultaneously increase and decrease the brightness on both of my MacBook Pro display and my external Thunderbolt Display, which is generally satisfactory. But with the PowerMate on my desktop, I developed a curiosity. You can see where this is going.

The thing is, unlike system volume, there’s no System Events API for display brightness. To script it, you have to open System Preferences and use accessibility scripting to actually move the slider, which I refuse to do on principle. It took a while to find a CLI called brightness by Nicholas Riley, but it’s a perfect fix. It can query all displays for current brightness levels (and other info) and modify the brightness on any or all displays from the command line.

brightness can be installed with Homebrew: brew install brightness will do the trick. Once installed, you can use brightness -l to query all displays for basic info:

$ brightness -l
display 0: main, active, awake, online, external, ID 0x4248798
display 0: brightness 1.000000
display 1: active, awake, online, built-in, ID 0x4280886
display 1: brightness 0.937500

Add -v for verbose information:

$ brightness -lv
display 0: main, active, awake, online, external, ID 0x4248798
	resolution 2560 x 1440 pt (2560 x 1440 px) @ 0.0 Hz, origin (0, 0)
	physical size 597 x 336 mm
	IOKit flags 0x2000007; IOKit display mode ID 0x80003000
	usable for desktop GUI, uses OpenGL acceleration
display 0: brightness 1.000000
display 1: active, awake, online, built-in, ID 0x4280886
	resolution 1440 x 900 pt (2880 x 1800 px) @ 0.0 Hz, origin (2560, 586)
	physical size 331 x 207 mm
	IOKit flags 0x2000007; IOKit display mode ID 0x80003000
	usable for desktop GUI, uses OpenGL acceleration
display 1: brightness 0.937500

The current display brightness is returned as a float (decimal) between 0 and 1, so 0.5 is half brightness, and 1 is full. To set a new brightness, just call brightness with a float between 0 and 1 as an argument, e.g. brightness 0.8. You can specify a display with -m for the “main” display or -d and an integer to target a specific display by number (as returned in the -l listing).

In order to put brightness control onto the spinning knob of my PowerMate, I needed to be able to increment and decrement instead of setting the brightness directly. And that’s the only thing that brightness is missing. I started hacking the source to handle this, but because the project is regularly maintained as the SDK changes, I thought twice about messing up its ability to be updated. So a simple script wrapper handles it.

The script below changes the argument from a decimal float to a straight percentage representation (integer between 0 and 100) and allows incrementing and decrementing by percentage.

Using brightness.rb 10 (or +10) will increase the brightness of all attached displays by 10%. Make it negative to decrease, e.g. brightness.rb -10. You can also use = to set a specific percentage, e.g. brightness.rb =75.

To install, just save the script in your path (and optionally make it executable if you’re going to use it from the command line). See below for implementation in other apps.

You can obviously call the script directly where appropriate. The most universal way to incorporate it into most Mac automation utilities is with AppleScript and do shell script:

-- Brightness Up.scpt
do shell script "/usr/bin/env ruby /Users/ttscoff/scripts/brightness.rb 10"

-- Brightness Down.scpt
do shell script "/usr/bin/env ruby /Users/ttscoff/scripts/brightness.rb -10"

(If you’re wondering, always using /usr/bin/env is a future-proofing strategy, given /usr/bin/ruby etc. will be disappearing.)

These AppleScripts can be attached to the PowerMate gestures in the PowerMate app, or used in tools like BetterTouchTool3 to attach the functions to any other hardware, including trackpad gestures, MIDI signals, or your Siri remote. You could incorporate the scripts into a Bunch, too, if you had some reason to do that. I also use them with my Indigo setup so that if I turn on my office light switch during my “night time” hours, my office lights only brighten to 30% and my screens get set to 50%. To that end, my PowerMate now also controls my office lights, because why not?

I blog this partly because I just like to look back years later and see what shenanigans I got up to in the past4. But I have to assume that the lack of automation options for display brightness has been a frustration for others, too, so hopefully this finds some Mac users who will find it helpful.

  1. Aside, why did Griffin cripple the PowerMate app? No more light states or modifier key conditionals, and the AppleScript library cut out all the cool controls…

  2. I usually get up at 5 but I keep waking up at 3:30am. It’s not new, but for over a year I’ve had much better sleep patterns than I used to and have grown accustomed to 8-hour rest periods. It’s problematic.

  3. Have you seen BetterTouchTool lately? Hard to believe it continues to get better and better. I really need to write a whole article just about that…

  4. Plus there’s that thing where I search DDG for an answer to a problem and find out I wrote a solution years ago and then forgot about, which happens to me about once a week.

BrettTerpstra.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means to earn fees when linking to Amazon.com and affiliated sites.

Emoji input on macOS

[Tweet : nvALT]

Happy Independence Day to my US readers. I’m not doing any parades, nor running any special discounts on my apps. Just a silly post.

Since this blog has always been 86% me documenting things I figured out so I can find them later, I’m going to go ahead and write about something I’m pretty sure everybody else already knew.

I’ll start with a drawn-out backstory.

I held out on the whole emoji thing for a long time. I figured there had to be a reason that Apple, Google, Microsoft, and others were putting so much effort into adding them to messaging, but it didn’t make sense in my own habits. I’m a person who even in a 140-character message would prefer to use multiple messages to allow complete words and sentences with correct punctuation than lower myself to the level of “idk prly dum.”

But I started to see the intrigue of creating a new language, one based on hieroglyphs that held different meanings in different contexts and combinations, and even changing definitions between tribes. They could be used to punctuate regular text, or to add humor through ambiguity, or to provide a more precise representation of intent and emotion than text alone could, and with more depth than emoticons could. So maybe two years ago I really started using them.

On my iPhone, emoji input is really easy. Even with Apple’s default keyboard — but more so with Gboard or some of the emoji-centric 3rd-party keyboards — they were always at hand and almost as accessible as regular alphanumeric characters. But what about on my Mac? Now that I’m using them frequently, it was annoying to deal with the impediments there.

So, first step, the character palette. By default the keyboard shortcut is ⌃⌘␣ (Control-Command-Space). I hit it while typing in Messages and it gave me a popup with available emoji. I could search by name or just use the arrow keys to navigate the list as a grid. Ok. Then I enter one and it disappears. I have to open it again, navigate again, and then it disappears again.

You can also open the traditional character palette input method using the icon in the upper right of the popup panel. In this mode it stays open and doesn’t take keyboard focus, so you can click multiple emoji and keep typing. But because it doesn’t take keyboard focus, it also means you have a float-over window that requires mouse interaction every time, and each character requires a double-click. Tradeoff.

There’s no perfect combination here, but there is a third option that I like slightly better: when it’s in the popup mode (which you can get back to from the character palette by clicking the icon in the upper right and then closing the panel), you can click below the search field and drag it to untether it from the input field. Weirdly, the search field has to have focus for this to work, so if it doesn’t drag, click in the search field first. It now becomes a floating palette that allows you to click multiple emoji and quickly insert a combination. They only require a single-click, and it doesn’t take keyboard focus so you can be typing, click one or more emoji, and then just continue typing without needing to click back to what you’re writing.

You can always set up TextExpander snippets or Keyboard Maestro macros, too, and that’s great for frequently used emoji or combinations. It’ll never be as easy as it is on my phone; I can’t just change my actual keyboard the way I can with a tap on iOS. Though it seems like something I’d eventually try to do if I had a keyboard with programmable OLED keycaps. I mean, obviously.

Anyway, no groundbreaking discoveries, but if you’re like me and happen to be relatively new at giving any firetrucks about emoji, maybe these tips help in some small way…

Web Excursions for July 03, 2019

[Tweet : nvALT]

Web Excursions header, Brett holding map

Web excursions brought to you in partnership with Codecademy, the easiest way to learn to code.

Eva Design System: Deep learning color generator
I think the most common reason I break out color wheels is to find the right success/info/warning/error colors for a web interface. This tool lets you specify a primary color and generates your green, blue, yellow, and red hues to match it.
Xprim
A free tool which enables presenters to conduct live polls during a talk. Put up a QR code to link everyone to the polls and Q&A forms, then get feedback as you go. Cool idea. For a better overview, be sure to check the docs.
swiftwebui/SwiftWebUI
A demo implementation of SwiftUI for the Web. It’s a fun toy to start playing. Requires macOS Catalina and Xcode 11, so if you weren’t already sure it was for devs…
soheilpro/catj
A CLI that displays JSON files in a flat format, quickly turning JSON data into valid JavaScript field references. It will make more sense when you check out the repo.
History Will Not Be Kind to Jony Ive
A scathing but undisputable take from Jason Koebler at Motherboard. “Ive, Apple’s Chief Design Officer, is leaving the company. He leaves a legacy that made its products hard to repair and impossible to upgrade.”

Codecademy Pro

Bunch and Timing.app

[Tweet : nvALT]

I started this post a while ago, before I realized that Timing would be sponsoring the blog later this month. So full disclosure, Timing is sponsoring the blog later this month. This is a handy trick either way, so I’ll go ahead and post it as… value added?

Intro recap: Bunch is my little utility for batch launching apps and switching “contexts” as you work on your Mac. Timing is an excellent time tracking app for Mac that automatically keeps track of what you’re working on, helping you compile accurate reports of your time.

Aside from just launching apps, Bunch has features for running scripts and Automator Workflows. And Timing has an AppleScript dictionary that makes it easy to change the current “task” (a classification you can add to a time block). Thus, in a Bunch that launches a specific project context, you can use AppleScript to switch Timing over at the same time.

There are a few ways to do it, but the simplest is with raw AppleScript. At the top of the Bunch I use to switch to working on nvUltra, I have this:

* tell application "TimingHelper" to stop current task
* tell application "TimingHelper" to start task with title "nvUltra" project (project named "Development")

# When quitting the Bunch, stop current task
!* tell application "TimingHelper" to stop current task

The first line stops whatever task is currently being tracked. The second line sets the task to “nvUltra” and the project to “Development” (so as not to confuse it with the “Writing” nvUltra task).

The last line (!*) is only run when the Bunch is being closed. It will return Timing to general tracking without an assigned task.

If you want to get a little more reusable with this, you can create a shell script or Automator workflow and either pass arguments to it, or have logic that uses the $BUNCH environment variable to determine the task automatically. ($BUNCH is populated with the name of the Bunch in any script environments, and it shows up as a variable named “Bunch” for Automator workflows). I’m including a Workflow below that accepts a “task” and “project” variable when called from the Bunch, like this:

& workflows/Timing
- task = Bunch
- project = Development
!& workflows/Timing

Note that I have my Workflows stored in a subfolder (workflows) and that the .workflow extension is assumed by Bunch, so that’s not needed in the line that calls it.

It will automatically stop any running task before starting the one you pass. When it’s run without any arguments, as shown in the last line, it quits the current task and exits. Here’s what it looks like. If you’re interested in the actual AppleScript, just download below and open it in Automator.

You’ll see the variables named “task,” “project,” and “Bunch” present in the variables section of the Workflow. These must exist for Bunch to call it with the above parameters. (They also have to be empty for the “stop timing if there are no variables” thing to work.)

Timing.app Workflow for Bunch v1.0.0

An Automator Workflow for integrating Timing.app with your Bunches

Published 07/02/19.

Updated 07/02/19. Changelog

DonateMore info…

Don’t forget that Bunch also has its own (admittedly limited) AppleScript dictionary, so if you’re already scripting Timing from somewhere else, you can also launch a Bunch at the same time with a line like tell app "Bunch" to open "nvUltra" (to open the Bunch named “nvUltra”).

This is just one example of how Bunch can tie into other tools. For instance, you could use AppleScript to focus a specific project or tag in OmniFocus when switching to a relevant project with Bunch, or even read your todo items out loud while it launches the other tasks…

Have fun, and of course, check out Timing and see the Bunch project page for the latest documentation!

On scripting runtimes and macOS

[Tweet : nvALT]

As noted by Michael Tsai, in the Xcode 11 beta release notes, Apple notified us that scripting runtimes will be removed from “future versions” of macOS. I previously linked Dr. Drang’s thoughts on this as well:

Scripting language runtimes such as Python, Ruby, and Perl are included in macOS for compatibility with legacy software. In future versions of macOS, scripting language runtimes won’t be available by default, and may require you to install an additional package. If your software depends on scripting languages, it’s recommended that you bundle the runtime within the app.

Considering how integral these runtimes are to my own daily use of my Mac, this is a real annoyance. I’m fully capable of installing them myself, but I still find the decision baffling.

Consider the things I share right here on my blog. It’s an extensive list, and 90% of these projects rely on Ruby, Python, or Perl to function. Even the ones that don’t require you to go anywhere near the command line use scripting languages in the background to do what they do. So while this might not be a huge blow for me, it’s an impediment to anyone who uses my projects that isn’t a Terminal nerd.

The Markdown Service Tools are one of my most consistently popular projects. Every one of those Services relies on a scripting language, all via Automator. So if the runtimes aren’t available by default, does that mean that Automator won’t have a Run Shell Script action anymore? Or, very likely, that Automator will be no more, replaced by Shortcuts and entirely lacking scripting runtimes?

The announcements also include a switch from Bash to Zsh as the default shell. I’m unclear as to whether bash will be removed from the default install entirely, but doing so would also require many of my projects to be re-tooled for zsh so as not to require every user to install bash just to run a simple shell script. Feasible, but unlikely that I’d ever get around to updating everything that uses bash scripting at its core. Don’t forget, even Homebrew requires Ruby to install itself, so that’s a speed bump to easily installing command line tools.

Marked makes use of the system Ruby runtime when it compiles Scrivener documents for preview, and many of my customers use Custom Processors that rely on scripting runtimes, even if they have limited experience in the shell. Some apps rely so heavily on system runtimes that they’d be crippled without embedding their own runtime. Dropzone, for example, uses Ruby as the base for all of its Destinations, and embedding Ruby in a way that makes it useful to the general population is not a simple task. I’m sure we’ll all figure it out, but I’m also convinced that it’s an unnecessary burden on developers.

So the question is why? I can’t wrap my head around any real benefit to Apple’s line of reasoning on this. They’ve not been great about keeping the runtimes up to date, but that’s actually been a boon, requiring less effort to keep scripts working with every OS release. These runtimes were even touted as a selling point in the past, and Microsoft is just now starting to add tools like this to the default Windows install. And they’re including a sexy Terminal. So why is Apple moving in the opposite direction?

My only guess is that it’s directly related to the iOS-ification of macOS. iOS is based on Unix, just like macOS, but scripting runtimes have never been included (nor are they installable without bundling). So, security? A higher wall on the garden, one more easily controlled? It can’t be about file size, nor complexity for the everyday user. It doesn’t affect either in any measurable way. I don’t have an answer to this question yet, and I don’t know that we’ll ever really get one.

It’s a long list of pitfalls and downsides with no easily grokked upside to the decision. My best hope is that Apple provides the runtimes in a package like the Command Line Tools available through the developer site. Maybe it will be as easy as clicking a PKG file and running the install. But I still can’t figure out why this is a necessary change.