This widget shows native input source icon.
In order to make it work you need to download localebase64icon binary and put it into /usr/local/bin/
. The source of this tool is also available, so you can build it yourself.
Story about trying to get the icon without external binary
So I was quite fascinated by the fact that you actually can almost write an objective-c code with Javascript for Automation (JXA). I wrote a widget that shows a precipitation forecast by using buienalarm API. Had a minor problem with making NSBezierPath
working, but nothing I couldn't figure out. The biggest issue probably was that Mojave just crashes when you try to work with NSRect structure from JXA. You can't use it at all: creating, getting it as a result of another method, even NSZeroRect
. Nothing works - straight crash.
Anyway, I managed to make the widget work and looked at my touch bar. One last missing piece was an input source switcher. There are a couple available on this forum, but all of them suffer from the very same problem - they don't show original macOS input source icon. Usually they just show emoji flag.
It looks like macOS doesn't expose input source icons as files, so you have to use Carbon API to get it:
TISInputSourceRef currentSource = TISCopyCurrentKeyboardInputSource();
IconRef iconRef = (IconRef)TISGetInputSourceProperty(currentSource, kTISPropertyIconRef);
NSImage *image = [[NSImage alloc] initWithIconRef:iconRef];
Fair enough, this could be easily translated to JXA:
var currentSource = $.TISCopyCurrentKeyboardInputSource();
var iconRef = $.TISGetInputSourceProperty(currentSource, $.kTISPropertyIconRef);
var image = $.NSImage.alloc.initWithIconRef(iconRef);
Except this code doesn't work, it produces an error (not a crash luckily) "Ref has incompatible type". Apparently initWithIconRef
expects some other type of IconRef .
So current solution is to use an external binary:
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var localeBase64Script = "/usr/local/bin/localebase64icon"
var icon = app.doShellScript(localeBase64Script)
I believe that this widget should be a part of default widget set. The native code is relatively straightforward, the problem with lag would go away - currently icon refreshes every so often, so when you change input source, it may take some time to reflect the change on touch bar.
Anyway, here's the link to the widget, hope it would be useful for someone . And don't forget to install the localebase64icon binary before using the widget.
https://share.folivora.ai/sharedPreset/f2d4b984-28c8-4ef4-b7b1-c6560648d039
After installing the widget, open the widget's settings and make sure that the combobox says "Java Script for Automation", not "AppleScript"
In order to switch language by tapping on the widget, you need to assign a custom hotkey in the keyboard settings, and add a custom keyboard shortcut to the widget's settings:
Screenshots