In an osascript/JXA context, I need to map macOS keyCodes and modifiers to Unicode strings (for any keyboard layout, specified at run-time)
The obvious candidate appears to be UCKeyTranslate
, but my attempts to get a reference to it from a JavaScript for Automation context have not been successful so far.
Does anybody know how to do this, perhaps in terms of ObjC.bindFunction
?
When ObjC libraries are imported into the 'JavaScript for Automation' (or 'JXA') JSContext, a global $
symbol is decorated with their methods.
So, for example, evaluating $.NSPasteboard
in a vanilla JXA context evaluates to undefined, but after ObjC.import('Appkit')
, we can write, and successfully evaluate, expressions like:
ObjC.deepUnwrap(
$.NSPasteboard
.generalPasteboard
.propertyListForType(clipType)
);
In this case however, $.UCKeyTranslate
remains undefined in the JSContext after:
ObjC.import("CoreServices")
ObjC.import("CarbonCore")
In such cases we can sometimes bind the names of ObjC functions to a JSContext name using ObjC.bindFunction
, for example, although it would be redundant, we could successfully write and make use of the names function names 'sin' and 'cos' after writing.
['sin', 'cos'].forEach(
k => ObjC.bindFunction(k, ['double', ['double']]));
In this case, however, neither the ObjC.import nor ObjC.bindFunction routes have so far defined the name $.UCKeyTranslate
or UCKeyTranslate
in the JXA JSContext.
One way to go would be to make a Swift or ObjC helper library (or a command line tool), and then use that from JXA. Check some example code to start.
If you wrap this call in an ObjC object method inside a framework, it's possible to ObjC.import()
it and use in your scripts. If you choose to do a command line app, then call it as a shell command.
Using ObjC.bindFunction seems a bit too complicated, because you'd have to bind a few other functions that would get you a UCKeyboardLayout instance, and define a bunch of magic constants, plus do some necessary mapping of strings and pointers.