Disabling Command-Tab on Mac OS X

NOTE: This experiment only lasted a couple weeks before I re-enabled cmd-tab. Also, Karabiner does not work with macOS 10.12 Sierra so you won’t be able to implement this hack if that’s your OS.

I’m trying an experiment. I’ve disabled ⌘-Tab on my computer. I wanted to try using LaunchBar’s app switcher in place of it, but there’s no way that I can override nearly twenty-five years worth of muscle memory1 without a little brute force. Karabiner to the rescue. Here is my entry in custom.xml to make it happen:

<item>
  <name>Disable Command-Tab</name>
  <identifier>private.disable_command_tab</identifier>
  <autogen>
    --KeyToKey--
    KeyCode::TAB, VK_COMMAND | ModifierFlag::NONE,
    KeyCode::VK_NONE
  </autogen>
  <autogen>
    --KeyToKey--
    KeyCode::TAB, VK_COMMAND | VK_SHIFT | ModifierFlag::NONE,
    KeyCode::VK_NONE
  </autogen>
</item>

If you wanted to remap ⌘-Tab to actually do something, such as Escape, this would do the job:

<item>
  <name>Remap Command-Tab to Escape</name>
  <identifier>private.command_tab_to_escape</identifier>
  <autogen>
    --KeyToKey--
    KeyCode::TAB, VK_COMMAND | ModifierFlag::NONE,
    KeyCode::ESCAPE
  </autogen>
</item>

I’m not sure if this will stick. Giving up ⌘-Tab in favor of the LaunchBar way, I mean. ⌘-Tab and ⌘-Space are probably the two key-combos I hit more than any on my computer. Day in and day out I’m living in LaunchBar and switching between apps. I figure if I can just use ⌘-Space for both things, it will eventually be a net win. Also, in the few minutes I’ve had this set up, I can already feel things happening to my brain. ⌘-Tab is something I trigger without thinking. And I truly mean that it can be mindless in the worst way. Sometimes it makes me feel like a rat in a cage, hitting the lever to get a drug hit.2 The fact that my old ⌘-Tab habit no longer has any effect is making me act in a more mindful manner. Before I leave the current app to move to a new app, I have to think for a split second about where I want to go and what I want to do. It’s a subtle change that makes me feel more focused. The downside is that occasionally it adds friction that wasn’t there before.


  1. I started using Alt-Tab way back with Windows 3.1 in the early/mid 1990’s! 😱 
  2. But I don’t blame the poor rats for getting addicted to drugs while they were forced to live alone in miserable conditions. 

Open Tweet in TweetBot 1.0.1

I updated my Open Tweet in Tweetbot action for LaunchBar. You can download it from GitHub.

The previous version didn’t work properly if you triggered it and TweetBot for Mac wasn’t already running. Now that I’m using Marco Arment’s Quitter and TweetBot is being killed all the time, I was running into this bug a lot. The new update to the action fixes it.

Nerdy Details

Making this fix required doing a check to see if TweetBot was already running and, if not, to launch the app. I wrote the original script in JavaScript. As far as I can tell, there isn’t a way to use JavaScript to see if an app is running or not. But you can do that with AppleScript. And you can call out to an AppleScript from JavaScript. Here is the AppleScript that I’m using:

if application "Tweetbot" is not running then
    tell application "Tweetbot" to launch
    return false
else
    return true
end if

And here’s a line in the action’s main script that calls out to it:

var tweetbotIsOpen = LaunchBar.executeAppleScriptFile("open-tweetbot.scpt")

So the JavaScript calls out to the AppleScript which will launch TweetBot if it’s not already running. That AppleScript will also tell the caller if TweetBot was already running or not. In this case, I store the result of that call in the tweetIsOpen var. If you look at the full code, you’ll see that I’m not actually doing anything with the tweetIsOpen var. The reason for this is that I thought I might have to wait a second after opening TweetBot before sending it a URL to open. Turns out that isn’t necessary. 👍

Making Animated GIFs of Code

This is my process for creating animated GIFs of coding examples, like the one below. It’s changed over time and is my assimilation of posts from InVision and Wes Bos on the subject. You should read those. Wes made a nice video where he walks through his process. Know up front that I’m focusing on quality first, minimizing file size second, and workflow speed last. I’m also use ScreenFlow and the Gifify NPM module. Gifify might take a little time to get up and running, but the list of requirements is clear.1

operator-mono-powerline

Capture

I capture and edit in ScreenFlow. The editing is important. This is where you can remove typos and “dead air,” speed things up or slow things down, and generally get your clip polished to your taste. Previously I did this in Photoshop’s animation palette, which, in hindsight, was just plain insanity. Learn from my mistakes and use ScreenFlow’s editing tools.

Export

screenflow-export-losslessUsing ScreenFlow, I export as Lossless. Yes, lossless. This is key as it gives you the highest quality video to convert to an animated GIF. Exporting to some kind of compressed video format will introduce artifacts that can not only make your final GIF look worse, they could make the final file size larger. Going lossless also gives you a huge file: 158MB for 19 seconds of video! Final note: I export the recording of my Retina screen at 1× rather than scaling it down to 0.5× so that I end up with the nicest looking GIF possible. Converting beautiful, high-res text to nasty, low-res text makes me sad.

Conversion

Finally, use gifify to convert the MOV to a GIF. These are the settings I used:

$ gifify --colors 255 --compress 0 --fps 30 -o operator-mono-powerline.gif operator-mono-powerline.mov

Max colors. No compression. High frame rate.

Are those settings a little aggressive? Nope. The final product is a whopping 70KB. Surely I could squash that down some more, but this resulted in a final product that’s big and beautiful and certainly lightweight enough, IMHO2.


  1. I’m assuming you’re comfortable with the command line since you’re reading about how to make an animated GIF of code. If you don’t know what Homebrew or NPM are, this might not be the workflow for you. 
  2. The conversion did take a while on a 2013 quad-core MacBook. Maybe a minute. Long enough that I was concerned that something was wrong. It just took some horsepower to squash 158MB of video down to a 70KB GIF and, frankly, Gifify doesn’t do a good job of using all available CPU cores. 

Quick Tip: Operator Mono and Powerline

Love Operator Mono for coding but also love having a Powerline font for your terminal work? Did you know that you can have both? At least you can with iTerm. Here are the settings I use to do just that:

iterm2-font-settings

The trick is enabling the Use a different font for non-ASCII text option and then choosing a Powerline-compatible font. You’ll also have to strike a balance between the font sizes for Operator Mono and your Powerline font to make everything look nice. Getting the Powerline arrow characters to vertically align properly is the key issue here. The result of the settings I’m using can be seen below.

operator-mono-powerline-solarized-dark-eph

LaunchBar Action Development Tip

folder-in-actions-folderAfter writing my first custom LaunchBar action the other day, I’ve been pondering the best way to work on LaunchBar actions in the future. The biggest problem was that if you simply have your .lbaction sitting in the ~/Library/Application Support/LaunchBar/Actions/ folder, you can’t keep that action in a GitHub-friendly repo. Turns out that the solution to that problem is dead simple.

You can put folders inside of the LaunchBar/Actions/ folder and LaunchBar will find the .lbactions in those folders, too.

Problem solved! Never mind that I didn’t discover this until after I wrote a Node.js script that keeps two (or more) folders on your computer in sync in real-time. Sigh. It’s a long story.

Mac OS X Dock Not Working

What follows is my real-time trouble-shooting of a Mac OS X problem I had two mornings ago. I was unable to find a solution online, but I did manage to get things back to normal. I’m posting this so that it might help someone else with a similar problem.

The Symptoms

My OS X Dock isn’t there. It just vanished. Also:

  • Command-tab doesn’t work
  • My desktop is just black
  • Files and folder appear on the desktop, but there’s no wallpaper
  • Right-clicking on the desktop doesn’t do anything
  • Mission Control/Exposé doesn’t work either

Trying to kill/restart the Dock process from the terminal doesn’t work:

$ killall Dock
No matching processes belonging to you were found

Activity Monitor shows the ReportCrash process running and using ~10-11% CPU. It respawns after I kill it.

Reboot doesn’t help. Everything is fine if I log in as another user.

System seems fine otherwise. If it wasn’t for LaunchBar, I wouldn’t be able to do much of anything on this MacBook.1

The Origin

Seems that this issue started when I added a new folder of images (from Solid Color Backgrounds2) to the Desktop & Screen Saver preference pane. The folder was full of 1000+ tiny 1×1px PNGs. Or maybe it was the folder of 1000+ 640×480px JPEGs. The folder was added to the preference pane just fine, but trying to use one of those 1000+ images as the desktop wallpaper didn’t work. That seems to be what killed the Dock and made the desktop non-functional.

The Fix?

I deleted the folder of images I had added to the preference pane. I removed both the reference to the folder in the Desktop & Screen Saver preference pane and I deleted the folder itself from Finder. Shortly after that, the desktop appeared and the Dock came back.


  1. I forgot to check if Spotlight worked or not. 
  2. But I don’t want to blame that site for this problem. I likely made some changes to the images after I downloaded them. And they worked fine a year or two ago on this same computer. 

Open Tweet Links in Tweetbot with LaunchBar

I really went off the rails with this one.

The morning started with experimenting in Keynote to see if it had the tools I needed to make some animations for a video project I’m putting together. Before too long I discovered a bug with the Magic Move feature when applied to two text slides. Looking for a solution led me to this old tweet from Jake Wharton. The tweet didn’t offer a solution, but it was nice to see that he ran into the exact same problem I had. After I came up with a hacky fix, I wanted to ask Jake if he ever found a good solution.

Finally, the meat of this post!

No way I was going to use the Twitter website to post my reply to Jake’s tweet. I’ll do it in Tweetbot for Mac, thank you very much. But how to open this specific tweet ID in Tweetbot? There doesn’t seem to be a way to punch a Tweet ID into Tweetbot. But there is a Tweetbot URL scheme that will accomplish the goal. All I had to do was replace the https://twitter.com/ portion of the tweet’s URL with tweetbot:// and that tweet would open up in Tweetbot. Brilliant!

Enter LaunchBar

Rather than get back to what I was supposed to be doing this morning, I figured there had to be a way to use LaunchBar to make this task easier. In other words, how could I have LaunchBar do the following:

  1. Take in a URL for a specific tweet
  2. Confirm that it is a valid tweet URL
  3. Transform the URL to Tweetbot’s format
  4. Open the transformed URL in the default browser (which in turn would open the tweet in Tweetbot)

Turns out, once you dig into the LaunchBar Action docs a bit, it is pretty simple. So let’s walk through it.

Making a simple LaunchBar Action

  1. Open the LaunchBar Action Editor (Hint: use LaunchBar to open the Action Editor)
  2. Give it a name such as Open Tweet URL in Tweetbot (Bonus: set the Action Icon to com.tapbots.TweetbotMac)
  3. Create a new Action (the + button in the bottom left of the window)
  4. Set JavaScript as the language for the Default Script.
  5. Check the boxes for Requires argument and Accepts string argument
  6. Edit the default.js file (the Edit button in the upper right of the window)
  7. Replace the template code that LaunchBar gives you with the following:
function run(argument) {
  var regex = /^https?:\/\/(www.)?twitter.com\//
  // make sure that we passed in something, ANYTHING, to the action
  if (argument == undefined) {
    LaunchBar.alert('No argument was passed to the action');
  }
  // make sure we passed in a valid Twitter URL
  if (argument.match(regex) != null && argument.match(regex).index === 0) {
    // replace the `https://www.twitter.com/` with `tweetbot://`
    argument = argument.replace(regex, "tweetbot://")
    // now just tell LaunchBar to open the tweetbot URL
    LaunchBar.openURL(argument);
  } else {
    LaunchBar.alert('It appears that\n`' + argument + '`\nis not a valid Twitter URL')
  }
}

That’s all there is to it. A little regular expression magic and knowing how to tell LaunchBar to show alerts and open URLs is all this takes. This is far from a robust script. If you pass it a valid URL to a specific tweet in Twitter, such as https://twitter.com/eirkeirkeirk/status/725185945465556992, it’ll work. But it’ll choke and silently fail with a lot of other types of twitter.com URLs.

It’s on GitHub

So you can grab the .lbaction package from there instead of building it yourself.

A new discovery

lb-action-editor

If you have this Action installed, you can just send a tweet URL directly to Tweetbot itself and it will open. The magic is in the Runtime Behavior > Associated Application field. Because it’s set to com.tapbots.TweetbotMac, LaunchBar will pass the tweet URL on to this Action if you send the URL directly to Tweetbot. 🔥🔥🔥

Solarized Light EPH

markdown

I made a tweaked version of the Solarized Light .tmTheme and posted it to GitHub. You can think of it as Solarized Light, with a tasteful sprinkling of italics and a few enhancements when editing Markdown.

I always come back to using Solarized Light in my editor. When I use a darker theme, it’s usually Cobalt2 by Wes Bos. I really like how Wes uses italics in his theme and I wanted the same kind of thing in Solarized Light. This is my attempt at it. It’s working for me. Perhaps you’ll like it, too. Give it a shot.

Mykytok

It's almost like they dropped the same photo of Mike Mykytok into two different scenes.
It’s almost like they dropped the same photo of Mike Mykytok into two different scenes.

I went down the Google rabbit hole and ended up looking at the list of past U.S. 10,000m champions. The name Mike Mykytok jumped out at me. It’s a name I hadn’t heard or seen since 1997 yet it was instantly familiar. I’m not sure why. My best guess is that I was paying very close attention to the U.S. 10,000m scene in 1997. That’s the year I ran the race at the Junior National meet. Or maybe I saw him run a good 10K at Stanford around that time. Or because he was a former Junior National champ at 10,000m and for nearly two years of high school and college I was focused on doing the same thing.

Who knows. Point is, running forms are like finger prints, aren’t they?

Bad UX: T-Mobile Online Payment

The Problem

The NEXT button is in the wrong place. By being on the far left of the screen, it implies BACK while its label reads NEXT. Cognitive dissonance makes me sad.

The NEXT button is in the wrong place
The NEXT button is in the wrong place

The Fix

Move the NEXT button to the far right, and make the button a little bit bigger while we’re at it.

Buttons that move you forward in a process should be on the right, at least when dealing with languages that read left to right.
Buttons that move you forward within a process should be on the right, at least when dealing with languages that read left to right. Buttons that cancel the process or move you backwards should be on the left.