-1

I would like to be able to get either the key code or the characters/text from an NSEvent/KeyEvent. Absolutely no idea how to do this as the documentation I have found so far has been very limited.

My script is below. I am working on a speedrun macro for Minecraft.

This script is fully functioning as is, but currently all it does is check if the control key has been pressed via checking the modifier flags of NSEvent.

use framework "AppKit"
use scripting additions

global ca
set ca to current application

# you may change the following variables

global seed
set seed to "8398967436125155523"

to isModifierPressed(modifier)
    ((ca's NSEvent's modifierFlags()) / modifier as integer) mod 2 is equal to 1
end isModifierPressed

repeat
    if isModifierPressed(ca's NSEventModifierFlagControl) then execute()
    delay 0.01
end repeat

on execute()
    tell application "System Events"
        delay 0.1
        keystroke tab
        delay 0.02
        keystroke return
        delay 0.02
        repeat 3 times
            keystroke tab
            delay 0.02
        end repeat
        keystroke return
        delay 0.02
        repeat 2 times
            keystroke tab
            delay 0.02
        end repeat
        repeat 3 times
            keystroke return
            delay 0.02
        end repeat
        repeat 4 times
            keystroke tab
            delay 0.02
        end repeat
        keystroke return
        delay 0.02
        repeat 3 times
            keystroke tab
            delay 0.02
        end repeat
        keystroke seed
        delay 0.02
        repeat 6 times
            keystroke tab
            delay 0.02
        end repeat
        keystroke return
    end tell
end execute
  • Here's the documentation: [NSEvent](https://developer.apple.com/documentation/appkit/nsevent/), use property `keyCode` or `characters`. How do you get the `NSEvent`? – Willeke Jun 16 '22 at 08:36
  • I've looked at that documentation, and I've tried keyCode and characters, but I think they can only be accessed through an instance, unlike modifierFlags. I do not know how to create an instance of NSEvent or get a property of an instance of NSEvent. – Liam Kinghouser Jun 16 '22 at 13:46
  • is the question "How to get key code or key text from an NSEvent" or how to catch events in AppleScript? – Willeke Jun 16 '22 at 13:51
  • I need the second question answered to answer the first question :) – Liam Kinghouser Jun 16 '22 at 13:58
  • Suggestion: ask the second question first. – Willeke Jun 16 '22 at 14:17

1 Answers1

0

Getting the key code is is a bit of an ordeal. I wrote Objective-C code that handles it in this StackOverflow answer; basically this uses NSEvent to create a dictionary of all possible key-modifier combinations to back-reference from a given typed character. A bit of overkill, but you may find studying it helpful.

Of course, if you already have the NSEvent object, the you can use the following commands to get basic info:

NSEvent's characters()
NSEvent's charactersIgnoringModifiers()
NSEVent's modifierFlags()
NSEvent's keyCode()

You can create an NSEvent for a particular key code as follows:

use framework "AppKit"
use scripting additions

set ca to current application

set codeForGeneration to 40
set modFlags to 0

set keyEvent to ca's NSEvent's keyEventWithType:(ca's NSKeyDown) ¬
    location:(ca's NSMakePoint(1, 1)) ¬
    modifierFlags:0 ¬
    timestamp:0 ¬
    windowNumber:0 ¬
    context:(missing value) ¬
    |characters|:(missing value) ¬
    charactersIgnoringModifiers:(missing value) ¬
    isARepeat:false ¬
    keyCode:codeForGeneration

set outputCharacter to (keyEvent's charactersByApplyingModifiers:modFlags) as string

Line 6 (set keyEvent to...) creates a key event. You only need to concern yourself with first and last two options: keydown/keyup, repeat, keyCode. The others are dummies, unless you want to try to send a key event to a particular window or GUI element. Line 7 (set outputCharacter to...) extracts the characters from the event. This will produce a small 'k', because 40 is the key code for 'k' and no modifiers are used.

Modifiers are a little annoying to work with. you can use the ObjC constants individually (e.g., ca's NSEventModifierFlagShift or ca's NSEventModifierFlagOption), but to combine them you have to recognize that the flags are defined in terms of binary left-shifts: e.g., NSEventModifierFlagShift is defined as 1 << 17 and NSEventModifierFlagOption as 1 << 19, meaning a 1 bit shifted 17 or 19 bits left, respectively. So to create a shift-option-K event (the Apple logo), you have to set modFlags to 2^17+2^19.

Ted Wrigley
  • 2,921
  • 2
  • 7
  • 17
  • So would I compare an keyEvent object I created with the one caught? Confused on how that would work. How would I create an object for the caught keyEvent? – Liam Kinghouser Jun 19 '22 at 19:09
  • @LiamKinghouser: As I said above in the first quote box, if you have (have caught) and NSEvent object, you can extract the key code, characters, and modifiers from the object itself. But looking at your script a little more carefully, I think you're confused. NSEVent is an abstract class; if you want to receive events from the system when they occur you need to create an event tap, which will send you an NSEvent object when it detects an event occurring. But that's not trivial. I guess I wasn't clear on what you were doing. – Ted Wrigley Jun 19 '22 at 20:22
  • I see. I have tried to find some documentation on how to create an event tap, but I haven't found anything useful. How would I create an event tap? – Liam Kinghouser Jun 19 '22 at 22:27