在Mac(JAVA)中使用Carbon注册KeyPress

时间:2019-03-05 13:48:11

标签: java macos

我正在使用碳纤维来检测键盘的输入,当我注册热键(RegisterEventHotKey)时,它可以很好地工作,但是我想要的是注册键盘上按下的任何键,而不必将其声明为热键。

我正在使用Java,这是我所拥有的示例:

public interface Carbon extends Library {

public static Carbon Lib = (Carbon) Native.loadLibrary("Carbon", Carbon.class);

public static final int cmdKey = 0x0100;
public static final int shiftKey = 0x0200;
public static final int optionKey = 0x0800;
public static final int controlKey = 0x1000;

 public Pointer GetEventDispatcherTarget();

public int InstallEventHandler(Pointer inTarget, EventHandlerProcPtr inHandler, int inNumTypes, EventTypeSpec[] inList, Pointer inUserData, PointerByReference outRef);

public int RegisterEventHotKey(int inHotKeyCode, int inHotKeyModifiers, EventHotKeyID.ByValue inHotKeyID, Pointer inTarget, int inOptions, PointerByReference outRef);

public int GetEventParameter(Pointer inEvent, int inName, int inDesiredType, Pointer outActualType, int inBufferSize, IntBuffer outActualSize, EventHotKeyID outData);

public int RemoveEventHandler(Pointer inHandlerRef);

public int UnregisterEventHotKey(Pointer inHotKey);


/* struct EventTypeSpec { UInt32 eventClass; UInt32 eventKind; }; */
public class EventTypeSpec extends Structure {
    public int eventClass;
    public int eventKind;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("eventClass", "eventKind");
    }
}

/* struct EventHotKeyID { OSType signature; UInt32 id; }; */
public static class EventHotKeyID extends Structure {
    public int signature;
    public int id;

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("signature", "id");
    }

    public static class ByValue extends EventHotKeyID implements Structure.ByValue {

    }
}

/* typedef OSStatus (*EventHandlerProcPtr) ( EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData ); */
public static interface EventHandlerProcPtr extends Callback {
    @SuppressWarnings({"UnusedDeclaration"})
    public int callback(Pointer inHandlerCallRef, Pointer inEvent, Pointer inUserData);
}
}

CarbonProvider.class

public class CarbonProvider extends Provider {
private static final Logger LOGGER = LoggerFactory.getLogger(CarbonProvider.class);
private static final int kEventHotKeyPressed = 5;

private static final int kEventClassKeyboard = OS_TYPE("keyb");
private static final int typeEventHotKeyID = OS_TYPE("hkid");
private static final int kEventParamDirectObject = OS_TYPE("----");

private static int idSeq = 1;

private Map<Integer, OSXHotKey> hotKeys = new HashMap<Integer, OSXHotKey>();
private Queue<OSXHotKey> registerQueue = new LinkedList<OSXHotKey>();
private final Object lock = new Object();
private boolean listen;
private boolean reset;

private EventHandlerProcPtr keyListener;
private PointerByReference eventHandlerReference;
public Thread thread;


public void init() {
    thread = new Thread(new Runnable() {
        public void run() {
            synchronized (lock) {
                LOGGER.info("Installing Event Handler");
                eventHandlerReference = new PointerByReference();
                keyListener = new EventHandler();

                EventTypeSpec[] eventTypes = (EventTypeSpec[]) (new EventTypeSpec().toArray(1));
                eventTypes[0].eventClass = kEventClassKeyboard;
                eventTypes[0].eventKind = kEventHotKeyPressed;

                int status = Lib.InstallEventHandler(Lib.GetEventDispatcherTarget(), keyListener, 1, eventTypes, null, eventHandlerReference); //fHandlerRef
                if (status != 0) {
                    LOGGER.warn("Could not register Event Handler, error code: " + status);
                }

                if (eventHandlerReference.getValue() == null) {
                    LOGGER.warn("Event Handler reference is null");
                }
                listen = true;
                while (listen) {
                    if (reset) {
                        resetAll();
                        reset = false;
                        lock.notify();
                    }

                    while (!registerQueue.isEmpty()) {
                        register(registerQueue.poll());
                    }

                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    });

    thread.start();
}

private void resetAll() {
    LOGGER.info("Resetting hotkeys");
    for (OSXHotKey hotKey : hotKeys.values()) {
        int ret = Lib.UnregisterEventHotKey(hotKey.handler.getValue());
        if (ret != 0) {
            LOGGER.warn("Could not unregister hotkey. Error code: " + ret);
        }
    }
    hotKeys.clear();
}

private void register(OSXHotKey hotKey) {
    KeyStroke keyCode = hotKey.keyStroke;
    EventHotKeyID.ByValue hotKeyReference = new EventHotKeyID.ByValue();
    int id = idSeq++;
    hotKeyReference.id = id;
    hotKeyReference.signature = OS_TYPE("hk" + String.format("%02d", id));
    PointerByReference gMyHotKeyRef = new PointerByReference();

    int status = Lib.RegisterEventHotKey(KeyMap.getKeyCode(keyCode), KeyMap.getModifier(keyCode), hotKeyReference, Lib.GetEventDispatcherTarget(), 0, gMyHotKeyRef);

    if (status != 0) {
        LOGGER.warn("Could not register HotKey: " + keyCode + ". Error code: " + status);
        return;
    }

    if (gMyHotKeyRef.getValue() == null) {
        LOGGER.warn("HotKey returned null handler reference");
        return;
    }
    hotKey.handler = gMyHotKeyRef;
    LOGGER.info("Registered hotkey: " + keyCode);
    hotKeys.put(id, hotKey);
}

@Override
public void stop() {
    LOGGER.info("Stopping now");
    try {
        synchronized (lock) {
            listen = false;
            lock.notify();
        }
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    if (eventHandlerReference.getValue() != null) {
        Lib.RemoveEventHandler(eventHandlerReference.getValue());
    }
    super.stop();
}

public void reset() {
    synchronized (lock) {
        reset = true;
        lock.notify();
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public void register(KeyStroke keyCode, HotKeyListener listener) {
    synchronized (lock) {
        registerQueue.add(new OSXHotKey(keyCode, listener));
        lock.notify();
    }
}

public void register(MediaKey mediaKey, HotKeyListener listener) {
    LOGGER.warn("Media keys are not supported on this platform");
}

private static int OS_TYPE(String osType) {
    byte[] bytes = osType.getBytes();
    return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
}

private class EventHandler implements Carbon.EventHandlerProcPtr {
    public int callback(Pointer inHandlerCallRef, Pointer inEvent, Pointer inUserData) {
        EventHotKeyID eventHotKeyID = new EventHotKeyID();
        int ret = Lib.GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, null, eventHotKeyID.size(), null, eventHotKeyID);
        if (ret != 0) {
            LOGGER.warn("Could not get event parameters. Error code: " + ret);
        } else {
            int eventId = eventHotKeyID.id;
            LOGGER.info("Received event id: " + eventId);
            fireEvent(hotKeys.get(eventId));
        }
        return 0;
    }
}

class OSXHotKey extends HotKey {
    PointerByReference handler;

    public OSXHotKey(KeyStroke keyStroke, HotKeyListener listener) {
        super(keyStroke, listener);
    }
}
}

我尝试了CarbonProvider.class的几种变体,更改了kEventClassKeyboard类型和typeEventHotKeyID,但似乎无济于事。

您能为我提供有关如何检测非热键事件的任何指导吗?

感谢您的帮助和时间!

0 个答案:

没有答案