com.sun.jna.platform.KeyboardUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jna-platform Show documentation
Show all versions of jna-platform Show documentation
Java Native Access Platform
/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.event.KeyEvent;
import com.sun.jna.Platform;
import com.sun.jna.platform.unix.X11;
import com.sun.jna.platform.unix.X11.Display;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser;
/** Provide access to the local keyboard state. Note that this is meaningless
* on a headless system and some VNC setups.
*
* @author twall
*/
// TODO: key clicks
// TODO: auto-repeat
// TODO: keyboard bell
// TODO: led state
public class KeyboardUtils {
static final NativeKeyboardUtils INSTANCE;
static {
if (GraphicsEnvironment.isHeadless()) {
throw new HeadlessException("KeyboardUtils requires a keyboard");
}
if (Platform.isWindows()) {
INSTANCE = new W32KeyboardUtils();
}
else if (Platform.isMac()) {
INSTANCE = new MacKeyboardUtils();
throw new UnsupportedOperationException("No support (yet) for "
+ System.getProperty("os.name"));
}
else {
INSTANCE = new X11KeyboardUtils();
}
}
public static boolean isPressed(int keycode, int location) {
return INSTANCE.isPressed(keycode, location);
}
public static boolean isPressed(int keycode) {
return INSTANCE.isPressed(keycode);
}
private static abstract class NativeKeyboardUtils {
public abstract boolean isPressed(int keycode, int location);
public boolean isPressed(int keycode) {
return isPressed(keycode, KeyEvent.KEY_LOCATION_UNKNOWN);
}
}
private static class W32KeyboardUtils extends NativeKeyboardUtils {
private int toNative(int code, int loc) {
if ((code >= KeyEvent.VK_A && code <= KeyEvent.VK_Z)
|| (code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9)) {
return code;
}
if (code == KeyEvent.VK_SHIFT) {
if ((loc & KeyEvent.KEY_LOCATION_RIGHT) != 0) {
return WinUser.VK_RSHIFT;
}
if ((loc & KeyEvent.KEY_LOCATION_LEFT) != 0) {
return WinUser.VK_LSHIFT;
}
return WinUser.VK_SHIFT;
}
if (code == KeyEvent.VK_CONTROL) {
if ((loc & KeyEvent.KEY_LOCATION_RIGHT) != 0) {
return WinUser.VK_RCONTROL;
}
if ((loc & KeyEvent.KEY_LOCATION_LEFT) != 0) {
return WinUser.VK_LCONTROL;
}
return WinUser.VK_CONTROL;
}
if (code == KeyEvent.VK_ALT) {
if ((loc & KeyEvent.KEY_LOCATION_RIGHT) != 0) {
return WinUser.VK_RMENU;
}
if ((loc & KeyEvent.KEY_LOCATION_LEFT) != 0) {
return WinUser.VK_LMENU;
}
return WinUser.VK_MENU;
}
return 0;
}
public boolean isPressed(int keycode, int location) {
User32 lib = User32.INSTANCE;
return (lib.GetAsyncKeyState(toNative(keycode, location)) & 0x8000) != 0;
}
}
private static class MacKeyboardUtils extends NativeKeyboardUtils {
public boolean isPressed(int keycode, int location) {
return false;
}
}
private static class X11KeyboardUtils extends NativeKeyboardUtils {
// TODO: fully map from X11 keycodes to java keycodes
// this is a minimal implementation
private int toKeySym(int code, int location) {
if (code >= KeyEvent.VK_A && code <= KeyEvent.VK_Z)
return X11.XK_a + (code - KeyEvent.VK_A);
if (code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9)
return X11.XK_0 + (code - KeyEvent.VK_0);
if (code == KeyEvent.VK_SHIFT) {
if ((location & KeyEvent.KEY_LOCATION_RIGHT) != 0)
return X11.XK_Shift_R;
return X11.XK_Shift_L;
}
if (code == KeyEvent.VK_CONTROL) {
if ((location & KeyEvent.KEY_LOCATION_RIGHT) != 0)
return X11.XK_Control_R;
return X11.XK_Control_L;
}
if (code == KeyEvent.VK_ALT) {
if ((location & KeyEvent.KEY_LOCATION_RIGHT) != 0)
return X11.XK_Alt_R;
return X11.XK_Alt_L;
}
if (code == KeyEvent.VK_META) {
if ((location & KeyEvent.KEY_LOCATION_RIGHT) != 0)
return X11.XK_Meta_R;
return X11.XK_Meta_L;
}
return 0;
}
public boolean isPressed(int keycode, int location) {
X11 lib = X11.INSTANCE;
Display dpy = lib.XOpenDisplay(null);
if (dpy == null) {
throw new Error("Can't open X Display");
}
try {
byte[] keys = new byte[32];
// Ignore the return value
lib.XQueryKeymap(dpy, keys);
int keysym = toKeySym(keycode, location);
for (int code=5;code < 256;code++) {
int idx = code / 8;
int shift = code % 8;
if ((keys[idx] & (1 << shift)) != 0) {
int sym = lib.XKeycodeToKeysym(dpy, (byte)code, 0).intValue();
if (sym == keysym)
return true;
}
}
}
finally {
lib.XCloseDisplay(dpy);
}
return false;
}
}
}