Current input source icon

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 :man_shrugging:.

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 :slight_smile:. 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"

Screenshot of settings

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


Screenshots


No luck importing this one --- I did download the binary and installed it in /usr/local/bin (and "chmod +x"ed it) but the preset share upload seems to be broken

Oops, sorry, I didn't use a proper sharing link. This one should work (updated in the post as well).

Thanks! Icon is not showing though. Am using latest stable BTT in conjunction with latest stable version of GoldenTouch

Could you please invoke the script from the terminal and paste its output to this image converter? The output might end with a %, don't copy it, just the part that ends with =

yes, that generates the correct icon in the image converter

Interesting. What happens when you press "Run Script" in the script editor? Does it show any output on the right?

Just a quick note without really adding anything helpful:
Unfortunately Apple seems to have forgotten about JXA, it has soo many bugs and is barely usable.
However one of the next BTT versions will allow to have custom widgets as NSBundles (I will make a Xcode template / example widget available), then it will become very easy to integrate such native code.

2 Likes

These are amazing news, would be happy to alpha-beta-whatever test this feature!

syntax error: a class can't go after this identifier

In fact, could you please make sure that the combobox in the left-center side of the window says "Java Script for Automation"? I don't see anywhere in the preset indication of using it instead of AppleScript.

Actually there's an indication, but it seems to be ignored by BTT:

"BTTScriptType":1

Just tried to import the widget myself, it sets the language to AppleScript
@Andreas_Hegenberg seems to be a bug :slight_smile:

that might ve an export/import bug then. I'll have a look!

1 Like

I deleted and re-imported the script, changed the combobox from "AppleScript" to "JavaScript", and restarted BTT. Now it works

Would be neat if tapping the icon switched to the next language. I tried mapping to CAPS LOCK but no luck. (I have 3 input sources enabled: US, Hebrew-QWERTY, and Greek [for math/sci symbols].)

Yeah, CAPS LOCK doesn't seem to work :-/. I guess the solution would be to assign a custom shortcut to language switch and then use it in BTT:


Yeah, I'll assign something I don't really use — option-space invokes Alfred on my machine...

OK, turns out I had command-space also assigned. I had to briefly turn it off so I could enter the shortcut, then turn it on again. There is, of course, a lag of about two seconds for the icon in the touchbar to be updated, but it updates immediately on the menu. I can live with that

1 Like

One challenge with this script is that IconRef could return NULL if it's not defined for a given input source such as is the case with japanese keyboards.

I've submitted a PR to your code that supports those languages.