All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bloodshura.ignitium.ntv.keyboard.impl.X11KeyboardWatcher Maven / Gradle / Ivy

The newest version!
package com.github.bloodshura.ignitium.ntv.keyboard.impl;

import com.github.bloodshura.ignitium.collection.list.XList;
import com.github.bloodshura.ignitium.collection.list.impl.XArrayList;
import com.github.bloodshura.ignitium.input.Key;
import com.github.bloodshura.ignitium.ntv.ErrorCodeNativeException;
import com.github.bloodshura.ignitium.ntv.NativeException;
import com.github.bloodshura.ignitium.ntv.keyboard.AbstractKeyboardWatcher;
import com.sun.jna.platform.unix.X11;

public class X11KeyboardWatcher extends AbstractKeyboardWatcher {
	private X11.Display display;
	private final byte[] keyBuffer;
	private long lastPollMillis;
	private int pollMinimumDelay;

	public X11KeyboardWatcher() throws NativeException {
		super(new X11KeyboardMapping());
		this.display = X11.INSTANCE.XOpenDisplay(null);
		this.keyBuffer = new byte[32];
		this.pollMinimumDelay = 50;

		if (display == null) {
			throw new ErrorCodeNativeException("Could not open X11 display");
		}
	}

	@Override
	public void dispose() throws NativeException {
		ensureNotDisposed();

		super.dispose();

		int status;

		// XCloseDisplay can return a X11.BadGC error code, but let's check for anything
		if ((status = X11.INSTANCE.XCloseDisplay(display)) != X11.Success) {
			throw new ErrorCodeNativeException("Could not dispose X11 display", status);
		}

		this.display = null;
	}

	public int getPollMinimumDelay() {
		return pollMinimumDelay;
	}

	@Override
	public void poll() throws NativeException {
		ensureNotDisposed();

		if (System.currentTimeMillis() < lastPollMillis + getPollMinimumDelay()) {
			return;
		}

		int status = X11.INSTANCE.XQueryKeymap(display, keyBuffer);

		if (status != 0x1) {
			throw new ErrorCodeNativeException("Could not query X11 keymap", status);
		}

		XList nowPressed = new XArrayList<>();

		for (int i = 0; i < keyBuffer.length; i++) {
			int test = 1;

			for (int bit = 0; bit < 8; bit++) {
				if ((keyBuffer[i] & test) > 0) {
					byte code = (byte) (i * 8 + bit);
					X11.KeySym sym = X11.INSTANCE.XKeycodeToKeysym(display, code, 0x0);
					Key key = getMapping().keyOf(sym.intValue());

					if (key != null) {
						nowPressed.add(key);
					}
				}

				test *= 2;
			}
		}

		// Get the previously pressed keys, and if they weren't pressed now, remove them from overall pressed keys.
		pressedKeys.selectNot(nowPressed::contains).forEach(pressedKeys::remove);

		// Get the now pressed keys which also were previously pressed, and remove them from the now pressed keys.
		nowPressed.select(pressedKeys::contains).forEach(nowPressed::remove);

		// Add all the now pressed keys to the overall pressed keys.
		pressedKeys.addAll(nowPressed);

		this.lastPollMillis = System.currentTimeMillis();
	}

	public void setPollMinimumDelay(int pollMinimumDelay) {
		this.pollMinimumDelay = pollMinimumDelay;
	}

	private void ensureNotDisposed() throws NativeException {
		if (display == null) {
			throw new NativeException("Keyboard watcher already disposed");
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy