Block > MacBook Pro: Touchbar

 10 min (2080 Wörter, 14989 Zeichen)

Inhaltsverzeichnis

Nach langer Nutzung eines Desktop-Rechners auf Arbeit, habe ich gegen Ende 2018 puenktlich zur “Interbustour” ein MacBook Pro (13-inch, 2017) bekommen. Das Geraet hatte schon eine Touchbar, allerdings auch nur eine virtuelle Esc-Taste, was mich schon von Anfang an sehr genervt hat (neovim ftw!).

2 Jahre spaeter habe ich ein neueres Modell bekommen (16-inch, 2019), diesmal mit “echter” Esc-Taste 🎉

Und dann dachte ich mir auch eines Tages mal:

Hey, ich koennte ja mal gucken, was ich so alles konfigurieren kann in der Touchbar.

Und wurde ziemlich enttaeuscht, die Einstellungsmoeglichkeiten unter macOS sind sehr bescheiden fuer so ein cooles Stueck Hardware. Die Einstellungen verstecken sich unter macOS 13.x in den Systemeinstellungen, indem nach “touchbar” gesucht wird. Dort gibt es unter “Keyboard” den Punkt “Customise Touch Bar or Control Strip” sowie unter “Extensions” den Punkt “Touch Bar”. Sehr intuitiv /s .

Da frage ich mich, ob das Ding ueberhaupt genutzt werden soll?

Gefunden habe ich dann ein paar Apps, aber wie das so ist im Apple-Land, die meisten sind nur Freeware oder aehnliches, wo mich nur BetterTouchTool ein bisschen ueberzeugen konnte. Nach 45 Tagen war damit aber auch Schluss.

Monate spaeter bin ich dann ueber die Website Awesome Open Source gestolpert, die sehr viele Projekte auflistet. Dort habe ich einfach mal nach “Touchbar” gesucht und 30 Projekte gefunden. Angeguckt hab ich mir Pock und MTMR .

Aber auch nur kurz, denn die Wahl fiel allein schon wegen der viel leichteren Installation mit Hilfe von Homebrew und auch wegen des Names bzw. des Akronyms auf MTMR (My Touchbar. My Rules.) 🎉

Installation #

Wie gesagt, sehr einfach, wenn brew installiert ist:

brew install mtmr

Konfiguration #

Die Standardmoeglichkeiten gefallen mir schonmal, konfigurieren laesst sich die Touchbar aber natuerlich auch, naemlich durch die JSON-Datei ~/Library/Application\ Support/MTMR/items.json. Das haben auch schon viele andere getan, wie im MTMR-presets -Repo zu sehen ist.

Diese items.json kopiere ich mir in ein Git repository (und linke sie anschliessend wieder zurueck), damit ich alles ganz gemaess nach Infrastructure as Code versionieren und ueberall deployen kann.

Hinweis

Sollte sich nach der Verlinkung und Aenderung im Code nichts mehr an der Touchbar aendern, hilft ein Restart von MTMR.

Im Prinzip ist die Touchbar wie meine Statusleiste bei dwm , kann nur ein bisschen mehr, da ich sie ja auch antippen kann und dann Aktionen ausgefuehrt werden 🎉

Meine Touchbar sieht im Moment wie folgt aus (Screenshot via ⌘⇧6 (Command, Shift und 6):

Meine Touchbar Ende April 2021
Meine Touchbar Ende April 2021

Mit laufendem MTMR funktionieren uebrigens noch die Funktionstasten (fn) und die Standardkonfiguration, wenn der Bildschirm gesperrt ist.

Funktionstasten, wenn 'fn' gedrueckt wird
Funktionstasten, wenn 'fn' gedrueckt wird
Touchbar, wenn der Bildschirm gesperrt ist
Touchbar, wenn der Bildschirm gesperrt ist

Ein Killerfeature von MTMR ist erstmal gar nicht sichtbar in der Bar und versteckt sich stattdessen in den Einstellungen, naemlich “Volume/Brightness gestures”.

'Volume/Brightness gestures' in den Einstellungen
'Volume/Brightness gestures' in den Einstellungen

Denn damit kann ich, wie in der README beschrieben ist, mit 2 Fingern irgendwo wischen und damit die Lautstaerke steuern sowie mit 3 Fingern die Bildschirmhelligkeit.
Mega, denn dadurch sind schonmal mindestens 2 Buttons komplett unnoetig, die ich daher auch alle weggelassen habe.
Minimalismus 🎉

Ansonsten hat meine Touchbar 6 “Elemente”, die ich im Folgenden aufliste und beschreibe.

Dabei ist die Bar bei mir in 2 Teile aufgeteilt: links + rechts (wobei links der Standard ist, daher gibt es auch im Code nur "align": "right").

Spotify #

In der Standardkonfiguration wird der aktuell gespielte Titel angezeigt, wenn Spotify laeuft und ein Lied gerade abgespielt wird. Ein Touch auf die Sektion springt zum naechsten Lied in der Playlist.

Touchbar mit langem Spotify Titel
Touchbar mit langem Spotify Titel

Das war mir ein bisschen zu wenig, denn ich will damit auch pausieren (Toggle heisst das Zauberwort) und auch mal zum letzten Lied zurueckspringen koennen. Zudem soll auch der aktuelle Track angezeigt werden, wenn Spotify gerade pausiert ist. Daher ist auch eine Statusanzeige (playing/paused) ganz nuetzlich.

Und damit habe ich mich auch zum ersten Mal mit AppleScript auseinandergesetzt und auch gesehen, dass einige Programme - wie z.B. Spotify - eine Datei mitbringen, mit der sie automatisiert werden koennen. Naemlich eine Datei mit der Endung .sdef , im Falle von Spotify befindet sich diese unter /Applications/Spotify.app/Contents/Resources/Spotify.sdef (Quelle ). Ausprobieren bzw. Debuggen laesst sich AppleScript mit AppleScript Editor oder Xcode.

Jedenfalls habe ich alles gewuenschte eingebaut:

Die Konfiguration fuer Spotify sieht so aus:

  {
    "type": "appleScriptTitledButton",
    "source": {
      "inline": "if application \"Spotify\" is running then\rtell application \"Spotify\"\rreturn (get artist of current track) & \" – \" & (get name of current track) & \" (\" & (get player state) & \")\"\rend tell\rend if\rreturn \"\"\r"
    },
    "actions": [
      {
        "trigger": "singleTap",
        "action": "appleScript",
        "actionAppleScript": {
          "inline": "if application \"Spotify\" is running then\rtell application \"Spotify\"\rplaypause\rend tell\rend if\r"
        },
      },
      {
        "trigger": "longTap",
        "action": "appleScript",
        "actionAppleScript": {
          "inline": "if application \"Spotify\" is running then\rtell application \"Spotify\"\rnext track\rend tell\rend if\r"
        }
      },
      {
        "trigger": "doubleTap",
        "action": "appleScript",
        "actionAppleScript": {
          "inline": "if application \"Spotify\" is running then\rtell application \"Spotify\"\rprevious track\rend tell\rend if\r"
        }
      }
    ],
    "refreshInterval": 1,
    "image": {
      "base64": "iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAYUExURUdwTB3WXx3UXh3VXx7XYBkXFRpVLRyURmIaeAQAAAAEdFJOUwDDO3fSqUUkAAABbklEQVRIx61VbW6DMAztoAeYNA7ApB6gkzhAWS24wIAL0HABaK6/pHFNEhy8TXu/kPzkPD/8cTj8K7KPAqB+K5NhQPCUrABCXe7HOUYYZxgVRLiG8RfY4DUgFFtC7cffAfZTFBwBdhWEKfgEq4ocEjgj4ZQifO6/QG9kkETp1dDeVWfRKx3XYSW0LoqY5kCElXDrQkyeCCuh6WL0M4nIWQIyzqixdfKU1koFDKvyCA8NJMzU4xiD+b4kfHRpsIyKc6hBwjVptFHVY51EMAINNDFGJITKDNQcdpX74Hz0CQ3rY5qwMp4EIxrlafzrsYZ2Veb0DkRgfNCUok4Y1fqEijfyi2b8RE9beWqa48Y/uvCNMcH9btfUi+/CGLR1vhL6Zz9N/vBlaCU+7lwY/cmJ67Ryen/2tj23PLqJBodZH8vgj544vOL4pxfI5acrSFxi8hrkU9TSKr78ZpnL50A8KPJJEo+afBblwyqf5j/iGys5j6ScrST2AAAAAElFTkSuQmCC"
    },
    "disableMarquee": false
  },

Alternative zu Spotify: mpd/mpc #

Statt mit einer externen Musikquelle wollte ich es auch mal mit lokaler Musik probieren. Hilfreich sind hier der Server Music Player Daemon und der Client mpc .

  // MPC
  {
    "type": "shellScriptTitledButton",
    "source": {
      "inline": "~/bin/mtmr_music.sh -s"
    },
    "actions": [
      {
        "trigger": "singleTap",
        "action": "shellScript",
        "executablePath": "~/bin/mtmr_music.sh",
        "shellArguments": ["-t"]
      },
      {
        "trigger": "longTap",
        "action": "shellScript",
        "executablePath": "~/bin/mtmr_music.sh",
        "shellArguments": ["-n"]
      },
      {
        "trigger": "doubleTap",
        "action": "shellScript",
        "executablePath": "~/bin/mtmr_music.sh",
        "shellArguments": ["-p"]
      }
    ],
    "refreshInterval": 1,
    "image": {
      "filePath": "~/Library/Application Support/MTMR/terminal.png"
    },
    "bordered": false
  },

Das Script ~/bin/mtmr_music.sh sieht so aus:

#!/bin/bash

pgrep mpd >/dev/null || { echo "mpd not running" ; exit 1 ; }

function status() {
  echo "$(mpc current) $(mpc | awk 'FNR==2{print $1}')"
}

function next() {
  mpc next
}

function toggle() {
  mpc toggle
}

function prev() {
  mpc prev
}

function usage() {
  echo "Usage: $0 [h|n|t|p|s]"
  echo "h: help"
  echo "n: next song"
  echo "t: toggle"
  echo "p: previous song"
  echo "s: status"
}

if [[ $# == 0 ]] ; then
  usage
  exit 1
fi

while getopts "hntps" options; do
  case $options in
    n) next >/dev/null ;;
    t) toggle >/dev/null ;;
    p) prev >/dev/null ;;
    s) status ;;
    *) usage ; exit 1 ;;
  esac
done

Schoen waere jetzt natuerlich noch ein Wechsel zwischen den Playern oder sowas, je nachdem, was gerade aktiv ist. Mopidy anzubinden waere auch noch eine Idee.

Character Viewer #

Unter dem 🎉 (Party Popper ) verbergen sich 2 Modi des Character Viewers, einmal nur die Emojis (singleTap) und einmal der “volle” Character Viewer (longTap), der normalerweise mit ⌃⌘␣ (Control, Command und Space) geoeffnet werden kann.

Bei der Suche, wie ich das in AppleScript abbilden kann, ging ganz schoen viel Zeit drauf. Zuerst mal habe ich dank StackExchange herausgefunden , wie der Code generell auszusehen hat.

Wichtig ist dabei das Boolean CVStartAsLargeWindow. Danach wird quasi nur die Tastenkombination gedrueckt.

Hinweis

Statt keystroke space kann auch key code 49 verwendet werden (vgl. die Liste in Events.h ).

Die meiste Zeit ging drauf herauszufinden, dass der Kram nicht funktioniert, wenn die Berechtigung fuer System Apps fehlt 😬

System Events in Automation erlauben
System Events in Automation erlauben

Hinzufuegen laesst sich diese in den Einstellungen:

🍎 -> System Preferences -> Security and Privacy -> Privacy -> Automation -> MTMR -> System Events.app

Zur Sicherheit habe ich das auch mal in einem Issue bei MTMR notiert .

Jedenfalls sieht die Konfiguration dann so aus:

  {
    "type": "staticButton",
    "title": "🎉 ",
    "actions": [
        {
            "trigger": "singleTap",
            "action": "appleScript",
            "actionAppleScript": {
                "inline": "do shell script \"defaults write com.apple.CharacterPaletteIM CVStartAsLargeWindow -bool false\"\rdelay 0.5\rtell application \"System Events\"\rkeystroke space using {control down, command down}\rend tell\r"
            },
        },
        {
            "trigger": "longTap",
            "action": "appleScript",
            "actionAppleScript": {
                "inline": "do shell script \"defaults write com.apple.CharacterPaletteIM CVStartAsLargeWindow -bool true\"\rdelay 0.5\rtell application \"System Events\"\rkey code 49 using {control down, command down}\rend tell\r"
            }
        }
    ],
    "align": "right",
    "bordered": false
  },

Wichtig ist hier das Leerzeichen nach dem 🎉 , ansonsten wird naemlich nichts oder z.B. im Falle von 🇹🇭 nur das erste Zeichen angezeigt .

Pomodoro #

Hinter der 🍅 (Tomato ) verbirgt sich ein schon eingebautes Kommando, daher ist die Konfiguration ziemlich schmal.

Es geht hierbei um die Pomodoro-Technik . In unserem Fall sind es 2 Modi: einmal die workTime mit 25 Minuten (singleTap) und einmal die restTime mit 5 Minuten (longTap). Ein erneuter singleTap stoppt den gerade aktiven Modus und kehrt zur 🍅 (Tomato ) zurueck.

Pomodoro in Aktion
Pomodoro in Aktion

Im Eintrag Gesundheit am PC liste ich noch ein paar andere Programme auf, die eher Pausen fokusieren und nicht unbedingt etwas mit Zeitmanagement zu tun haben.

  {
    "type": "pomodoro",
    "workTime": 1500, // set time work in seconds. Default 1500 (25 min)
    "restTime": 300, // set time rest in seconds. Default 300 (5 min)
    "align": "right",
    "bordered": false
  },

Battery #

Der Status des Akkus ist in MTMR schon integriert, was ziemlich cool ist:

Hinzugefuegt habe ich nur das Sperren des Bildschirms (longTap), was ueblicherweise via ⌃⌘q (Control, Command und q` gemacht werden kann.

  {
    "type": "battery",
    "align": "right",
    "bordered": false,
    "trigger": "longTap",
    "action": "appleScript",
    "actionAppleScript": {
      "inline": "tell application \"System Events\"\rkey code 12 using {control down, command down}\rend tell\r"
    },
  },

Hinweis

Statt key code 12 kann auch aehnlich wie beim Character Viewer keystroke \"q\" verwendet werden (vgl. die Liste in Events.h ).

Uhrzeit #1 #

Da ich fuer einen laengeren Zeitraum in Thailand war, wollte ich neben der deutschen Uhrzeit auch die thailaendische anzeigen. Daher gibt es 2 Uhrzeiten.

Um ein bisschen schoenere Farben zu haben, habe ich mich statt der deutschen fuer die Regenbogenflagge entschieden 🏳️‍🌈 😉
Die Flagge kommt von Emojipedia und kann statt via base64 auch direkt via filePath genutzt werden.

Und das ist doch auch der ideale Ort, um nicht nur eine Uhrzeit zu haben, sondern auch noch den Digital Colour Meter (longTap), der seit 10.14 an Bord ist.
Uebrigens kann bei geoeffnetem Programm mit ⌘⇧c (Command, Shift und c) der aktuelle Farbwert in die Zwischenablage kopiert werden (Quelle ).

  {
    "type": "shellScriptTitledButton",
    "refreshInterval": 5,
    "source": {
        "inline": "TZ=Europe/Berlin date +%H:%M"
    },
    "align": "right",
    "bordered": false,
    "trigger": "longTap",
    "action": "appleScript",
    "actionAppleScript": {
      "inline": "tell application \"Digital Color Meter\" to activate\r"
    },
    "image": {
        // "filePath": "~/myproject/flag-rainbow.jpg" // or
        "filePath": "/fixed/path/to/flag-rainbow.png"
    }
  },

Ist nur eine Uhrzeit notwendig, kann dies auch wie folgt vereinfacht werden (statt type, refreshInterval und source):

  {
    "type": "timeButton",
    "formatTemplate": "HH:mm",
    "align": "right",
    // ...
  },

Uhrzeit #2 #

Wie in Uhrzeit #1 beschrieben, will ich zusaetzlich zur deutschen auch noch die thailaendische Uhrzeit anzeigen.

Um mal noch eine andere Komponente mit einzubringen, habe ich spasseshalber noch 2 Optionen zur Browsersteuerung hinzugefuegt.
Das Gist von Vítor Galvão hat ein paar mehr Beispiele.

Hier wird nur ein neuer Tab im Standardbrowser bei singleTap geoeffnet und ein neuer incognito Tab im Browser Vivaldi via longTap (Anregung ).

Es gibt natuerlich noch viel mehr Optionen, was mit MTMR alles gemacht werden kann. Ein paar Anregungen sind unter TODO zu finden.

  {
    "type": "shellScriptTitledButton",
    "refreshInterval": 5,
    "source": {
        "inline": "TZ=Asia/Bangkok date +%H:%M"
    },
    "align": "right",
    "bordered": false,
    "actions": [
        {
            "trigger": "singleTap",
            "action": "openUrl",
            "url": "http://localhost"
        },
        {
            "trigger": "longTap",
            "action": "shellScript",
            "executablePath": "/usr/bin/open",
            "shellArguments": ["-a", "Vivaldi", "--new", "--args", "--incognito"]
        }
    ],
    "image": {
        "filePath": "/fixed/path/to/flag-thailand.png"
    }
  }

Optional: Escape Taste #

Virtuelle Escape Taste
Virtuelle Escape Taste

Falls die “echte” Escape Taste fehlt, kann sie uebrigens mit MTMR virtualisiert werden:

  {
    "type": "escape",
    "width": 64,
    "align": "left"
  },

Fertige items.json #

Die komplette Konfiguration ist ja eine JSON-Datei, die eine spezielle Syntax hat. Jeder einzelne Schnipsel von oben kann in ein Array ([]) gepackt werden. Wichtig ist, dass beim letzten Arrayelement das Komma entfernt wird:

[
  {
    "type": "escape",
    "width": 64,
    "align": "left"
  },
  // andere Elemente
  {
    "type": "mute",
    "width": 64,
    "align": "right"
  }
]

Viel Spass beim Hacken 😉

TODO #


 GPG: Adresse hinzufuegen bzw. entfernen

Beitraginfos

 2023-05-07, 22:09:50
 2024-01-05, 18:09:29
  macos, musik, osbn, touchbar
 Permalink

Ähnliche Beiträge