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:
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):
Mit laufendem MTMR funktionieren uebrigens noch die Funktionstasten (fn) und die Standardkonfiguration, 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”.
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.
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:
- Ein einfacher Touch (singleTap) auf
die Spotifysektion wechselt (toggled) den Abspielmodus (also von Pause
auf Play oder umgekehrt) und zeigt es auch durch ein
(playing)
bzw.(paused)
an. - Eine laengere Beruehrung (longTap) spielt das naechste Lied in der Playlist ab.
- Ein Doppeltouch (doubleTap) springt zum vorherigen Lied zurueck.
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.
Die meiste Zeit ging drauf herauszufinden, dass der Kram nicht funktioniert, wenn die Berechtigung fuer System Apps fehlt 😬
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.
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:
-
Ladekabel dran: es wird - natuerlich nur bei nicht vollem Akku - ein Blitz und die verbleibende Ladezeit neben der aktuellen Prozentzahl angezeigt
-
Ladekabel ab: es wird die ungefaehre verbleibende Restnutzungszeit angezeigt
-
Akku fast leer: die Prozentzahl und ungefaehre Restnutzungszeit wird in rot angezeigt
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
Stattkey 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 #
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 #
- Auslesen von “audible ” Tabs in
$browser
, damit diese auch wie bei Spotify dargestellt bzw. gesteuert werden koennen - GIFs in der Touchbar abspielen
- Doom ? Doom !
- Hue Lampen steuern
- Awesome Touch Bar apps ausprobieren