//! Logic taken from https://stackoverflow.com/a/71046488
import Foundation
import Carbon
import Quartz
import AppKit
extension NSEvent.ModifierFlags: Hashable { }
extension OptionSet {
public func first(_ options: Self.Element ...) -> Self.Element? {
for option in options {
if contains(option) {
return option
}
}
return nil
}
}
struct Keys {
static var special = [NSEvent.SpecialKey:CGKeyCode]();
static var specialNames = [String:NSEvent.SpecialKey]();
static var character = [String:(CGKeyCode, UInt16)]();
static var modifierFlag = [NSEvent.ModifierFlags:CGKeyCode]();
}
@_cdecl("initialize")
func initialize() {
for keyCode in (0..<128).map({ CGKeyCode($0) }) {
for modifiers in (0..<4) {
guard let cgevent = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(keyCode), keyDown: true) else { continue };
if modifiers & (1 << 0) != 0 {
cgevent.flags.insert(.maskShift);
}
if modifiers & (1 << 1) != 0 {
cgevent.flags.insert(.maskAlternate);
}
guard let nsevent = NSEvent(cgEvent: cgevent) else { continue };
if nsevent.type == .keyDown {
if let specialKey = nsevent.specialKey {
Keys.special[specialKey] = keyCode;
} else if let characters = nsevent.charactersIgnoringModifiers, !characters.isEmpty && characters != "\u{0010}" {
if Keys.character[characters] == nil {
Keys.character[characters] = (keyCode, UInt16(modifiers));
}
}
} else if nsevent.type == .flagsChanged {
guard let modifierFlag = nsevent.modifierFlags.first(.capsLock, .shift, .control, .option, .command, .help, .function) else {continue};
Keys.modifierFlag[modifierFlag] = keyCode;
}
}
}
// https://developer.apple.com/documentation/appkit/nsevent/specialkey
Keys.specialNames["carriageReturn"] = NSEvent.SpecialKey.carriageReturn;
Keys.specialNames["backspace"] = NSEvent.SpecialKey.backspace;
Keys.specialNames["newline"] = NSEvent.SpecialKey.newline;
Keys.specialNames["enter"] = NSEvent.SpecialKey.enter;
Keys.specialNames["delete"] = NSEvent.SpecialKey.delete;
Keys.specialNames["deleteForward"] = NSEvent.SpecialKey.deleteForward;
Keys.specialNames["backTab"] = NSEvent.SpecialKey.backTab;
Keys.specialNames["tab"] = NSEvent.SpecialKey.tab;
Keys.specialNames["upArrow"] = NSEvent.SpecialKey.upArrow;
Keys.specialNames["downArrow"] = NSEvent.SpecialKey.downArrow;
Keys.specialNames["leftArrow"] = NSEvent.SpecialKey.leftArrow;
Keys.specialNames["rightArrow"] = NSEvent.SpecialKey.rightArrow;
Keys.specialNames["pageUp"] = NSEvent.SpecialKey.pageUp;
Keys.specialNames["pageDown"] = NSEvent.SpecialKey.pageDown;
Keys.specialNames["home"] = NSEvent.SpecialKey.home;
Keys.specialNames["end"] = NSEvent.SpecialKey.end;
Keys.specialNames["prev"] = NSEvent.SpecialKey.prev;
Keys.specialNames["next"] = NSEvent.SpecialKey.next;
Keys.specialNames["begin"] = NSEvent.SpecialKey.begin;
Keys.specialNames["break"] = NSEvent.SpecialKey.break;
Keys.specialNames["clearDisplay"] = NSEvent.SpecialKey.clearDisplay;
Keys.specialNames["clearLine"] = NSEvent.SpecialKey.clearLine;
Keys.specialNames["deleteCharacter"] = NSEvent.SpecialKey.deleteCharacter;
Keys.specialNames["deleteLine"] = NSEvent.SpecialKey.deleteLine;
Keys.specialNames["execute"] = NSEvent.SpecialKey.execute;
Keys.specialNames["find"] = NSEvent.SpecialKey.find;
Keys.specialNames["formFeed"] = NSEvent.SpecialKey.formFeed;
Keys.specialNames["help"] = NSEvent.SpecialKey.help;
Keys.specialNames["insert"] = NSEvent.SpecialKey.insert;
Keys.specialNames["insertCharacter"] = NSEvent.SpecialKey.insertCharacter;
Keys.specialNames["insertLine"] = NSEvent.SpecialKey.insertLine;
Keys.specialNames["lineSeparator"] = NSEvent.SpecialKey.lineSeparator;
Keys.specialNames["menu"] = NSEvent.SpecialKey.menu;
Keys.specialNames["modeSwitch"] = NSEvent.SpecialKey.modeSwitch;
Keys.specialNames["paragraphSeparator"] = NSEvent.SpecialKey.paragraphSeparator;
Keys.specialNames["pause"] = NSEvent.SpecialKey.pause;
Keys.specialNames["print"] = NSEvent.SpecialKey.print;
Keys.specialNames["printScreen"] = NSEvent.SpecialKey.printScreen;
Keys.specialNames["redo"] = NSEvent.SpecialKey.redo;
Keys.specialNames["reset"] = NSEvent.SpecialKey.reset;
Keys.specialNames["scrollLock"] = NSEvent.SpecialKey.scrollLock;
Keys.specialNames["select"] = NSEvent.SpecialKey.select;
Keys.specialNames["stop"] = NSEvent.SpecialKey.stop;
Keys.specialNames["sysReq"] = NSEvent.SpecialKey.sysReq;
Keys.specialNames["system"] = NSEvent.SpecialKey.system;
Keys.specialNames["undo"] = NSEvent.SpecialKey.undo;
Keys.specialNames["user"] = NSEvent.SpecialKey.user;
Keys.specialNames["f1"] = NSEvent.SpecialKey.f1;
Keys.specialNames["f2"] = NSEvent.SpecialKey.f2;
Keys.specialNames["f3"] = NSEvent.SpecialKey.f3;
Keys.specialNames["f4"] = NSEvent.SpecialKey.f4;
Keys.specialNames["f5"] = NSEvent.SpecialKey.f5;
Keys.specialNames["f6"] = NSEvent.SpecialKey.f6;
Keys.specialNames["f7"] = NSEvent.SpecialKey.f7;
Keys.specialNames["f8"] = NSEvent.SpecialKey.f8;
Keys.specialNames["f9"] = NSEvent.SpecialKey.f9;
Keys.specialNames["f10"] = NSEvent.SpecialKey.f10;
Keys.specialNames["f11"] = NSEvent.SpecialKey.f11;
Keys.specialNames["f12"] = NSEvent.SpecialKey.f12;
Keys.specialNames["f13"] = NSEvent.SpecialKey.f13;
Keys.specialNames["f14"] = NSEvent.SpecialKey.f14;
Keys.specialNames["f15"] = NSEvent.SpecialKey.f15;
Keys.specialNames["f16"] = NSEvent.SpecialKey.f16;
Keys.specialNames["f17"] = NSEvent.SpecialKey.f17;
Keys.specialNames["f18"] = NSEvent.SpecialKey.f18;
Keys.specialNames["f19"] = NSEvent.SpecialKey.f19;
Keys.specialNames["f20"] = NSEvent.SpecialKey.f20;
Keys.specialNames["f21"] = NSEvent.SpecialKey.f21;
Keys.specialNames["f22"] = NSEvent.SpecialKey.f22;
Keys.specialNames["f23"] = NSEvent.SpecialKey.f23;
Keys.specialNames["f24"] = NSEvent.SpecialKey.f24;
Keys.specialNames["f25"] = NSEvent.SpecialKey.f25;
Keys.specialNames["f26"] = NSEvent.SpecialKey.f26;
Keys.specialNames["f27"] = NSEvent.SpecialKey.f27;
Keys.specialNames["f28"] = NSEvent.SpecialKey.f28;
Keys.specialNames["f29"] = NSEvent.SpecialKey.f29;
Keys.specialNames["f30"] = NSEvent.SpecialKey.f30;
Keys.specialNames["f31"] = NSEvent.SpecialKey.f31;
Keys.specialNames["f32"] = NSEvent.SpecialKey.f32;
Keys.specialNames["f33"] = NSEvent.SpecialKey.f33;
Keys.specialNames["f34"] = NSEvent.SpecialKey.f34;
Keys.specialNames["f35"] = NSEvent.SpecialKey.f35;
}
@_cdecl("get_special")
public func get_special(name: UnsafePointer<CChar>) -> UInt16 {
let name = String(cString: name);
guard let specialKey = Keys.specialNames[name] else { return UInt16.max };
guard let keyCode = Keys.special[specialKey] else { return 1 };
return keyCode;
}
@_cdecl("get_character")
public func get_character(character: UInt16) -> UInt32 {
guard let (keyCode, modifiers) = Keys.character[String(UnicodeScalar(character)!)] else { return UInt32.max };
return (UInt32(modifiers) << 16) | UInt32(keyCode);
}