diff --git a/src/java/org/lwjgl/input/Keyboard.java b/src/java/org/lwjgl/input/Keyboard.java index 00c7652be..d1a24b36d 100644 --- a/src/java/org/lwjgl/input/Keyboard.java +++ b/src/java/org/lwjgl/input/Keyboard.java @@ -282,6 +282,13 @@ public class Keyboard { private static InputImplementation implementation; + /** + * Input method + * input method is disable at default, for backward compatibility. + **/ + private static int imKeyboardBufferSize = 50; + private static String imLocaleModifiers = "@im=none"; + /** * Keyboard cannot be constructed. */ @@ -584,6 +591,47 @@ public static boolean isRepeatEvent() { } } + /** + * returns the byte size of keyborad buffer which receives string from Input method. + */ + public static int getImKeyboardBufferSize() { + return imKeyboardBufferSize; + } + + /** + * Set the byte size of keyborad buffer which receives string from Input method. + * Can receive a long string at a time, so that this value becomes big. + * + * To support long sentence of Japanease or other multibytes languages by Input method, + * It is recommended to set this value to 1000 or more. + * + * @param imKeyboardBufferSize keyborad buffer size for Input mehotd. + */ + public static void setImKeyboardBufferSize(int imKeyboardBufferSize) { + Keyboard.imKeyboardBufferSize = imKeyboardBufferSize; + } + + /** + * returns the Input method locale modifiers. + */ + public static String getImLocaleModifiers() { + return imLocaleModifiers; + } + + /** + * Set the Input method locale modifiers which is specified to XSetLocaleModifiers() + * argument on Linux Xlib. + * "@im=none" is set to this value from old days, + * but to support Japanease or other multibytes languages, this value must be empty string. + * when a empty string is specified to the argument of XSetLocaleModifiers(), + * default Input method is used on the environment. + * + * @param imLocaleModifiers the Input method locale modifiers. + */ + public static void setImLocaleModifiers(String imLocaleModifiers) { + Keyboard.imLocaleModifiers = imLocaleModifiers; + } + private static final class KeyEvent { /** The current keyboard character being examined */ private int character; @@ -607,4 +655,5 @@ private void reset() { repeat = false; } } + } diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index c27f1e9e0..cdba18cb8 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -55,6 +55,7 @@ import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; import org.lwjgl.MemoryUtil; +import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.XRandR.Screen; import org.lwjgl.opengles.EGL; @@ -864,7 +865,9 @@ private void processEvents() { event_buffer.nextEvent(getDisplay()); long event_window = event_buffer.getWindow(); relayEventToParent(event_buffer); - if (event_window != getWindow() || event_buffer.filterEvent(event_window) || + // Regardless of a window where the event occurred, XFilterEvent must send all events to IM. + // So first of all, call org.lwjgl.opengl.LinuxEvent.filterEvent(long). + if (event_buffer.filterEvent(event_window, keyboard) || event_window != getWindow() || (mouse != null && mouse.filterEvent(grab, shouldWarpPointer(), event_buffer)) || (keyboard != null && keyboard.filterEvent(event_buffer))) continue; @@ -1252,7 +1255,7 @@ public int getMaxCursorSize() { public void createKeyboard() throws LWJGLException { lockAWT(); try { - keyboard = new LinuxKeyboard(getDisplay(), getWindow()); + keyboard = new LinuxKeyboard(getDisplay(), getWindow(), Keyboard.getImKeyboardBufferSize(), Keyboard.getImLocaleModifiers()); } finally { unlockAWT(); } diff --git a/src/java/org/lwjgl/opengl/LinuxEvent.java b/src/java/org/lwjgl/opengl/LinuxEvent.java index e8fbe90e3..c8587d0c3 100644 --- a/src/java/org/lwjgl/opengl/LinuxEvent.java +++ b/src/java/org/lwjgl/opengl/LinuxEvent.java @@ -78,8 +78,27 @@ public void sendEvent(long display, long window, boolean propagate, long event_m } private static native void nSendEvent(ByteBuffer event_buffer, long display, long window, boolean propagate, long event_mask); - public boolean filterEvent(long window) { - return nFilterEvent(event_buffer, window); + public boolean filterEvent(long window, LinuxKeyboard keyboard) { + // If nFilterEvent() returns True, then some input method has filtered the event, + // and the client should discard the event. + // If nFilterEvent() returns False, then the client should continue processing the event. + if (nFilterEvent(event_buffer, window)) { + return true; + } + + // setICFocus() and unsetICFocus() must be called + // whenever FocusIn/FocusOut events are caused. + // Because Input method must know that the receiver of inputed string changed. + switch (getType()) { + case LinuxEvent.FocusIn: + keyboard.setICFocus(); + break; + case LinuxEvent.FocusOut: + keyboard.unsetICFocus(); + break; + } + + return false; } private static native boolean nFilterEvent(ByteBuffer event_buffer, long window); @@ -205,4 +224,5 @@ public int getKeyState() { return nGetKeyState(event_buffer); } private static native int nGetKeyState(ByteBuffer event_buffer); + } diff --git a/src/java/org/lwjgl/opengl/LinuxKeyboard.java b/src/java/org/lwjgl/opengl/LinuxKeyboard.java index 7fbb41174..7bad6e690 100644 --- a/src/java/org/lwjgl/opengl/LinuxKeyboard.java +++ b/src/java/org/lwjgl/opengl/LinuxKeyboard.java @@ -42,6 +42,7 @@ import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLUtil; +import org.lwjgl.Sys; import org.lwjgl.input.Keyboard; final class LinuxKeyboard { @@ -68,10 +69,10 @@ final class LinuxKeyboard { private final EventQueue event_queue = new EventQueue(Keyboard.EVENT_SIZE); private final ByteBuffer tmp_event = ByteBuffer.allocate(Keyboard.EVENT_SIZE); - private final int[] temp_translation_buffer = new int[KEYBOARD_BUFFER_SIZE]; - private final ByteBuffer native_translation_buffer = BufferUtils.createByteBuffer(KEYBOARD_BUFFER_SIZE); private final CharsetDecoder utf8_decoder = Charset.forName("UTF-8").newDecoder(); - private final CharBuffer char_buffer = CharBuffer.allocate(KEYBOARD_BUFFER_SIZE); + private final int[] temp_translation_buffer; + private final ByteBuffer native_translation_buffer; + private final CharBuffer char_buffer; // Deferred key released event, to detect key repeat private boolean has_deferred_event; @@ -80,7 +81,7 @@ final class LinuxKeyboard { private long deferred_nanos; private byte deferred_key_state; - LinuxKeyboard(long display, long window) { + LinuxKeyboard(long display, long window, int keyboardBufferSize, String imLocaleModifiers) { long modifier_map = getModifierMapping(display); int tmp_numlock_mask = 0; int tmp_modeswitch_mask = 0; @@ -124,7 +125,7 @@ final class LinuxKeyboard { caps_lock_mask = tmp_caps_lock_mask; shift_lock_mask = tmp_shift_lock_mask; setDetectableKeyRepeat(display, true); - xim = openIM(display); + xim = openIM(display, imLocaleModifiers); if (xim != 0) { xic = createIC(xim, window); if (xic != 0) { @@ -136,6 +137,15 @@ final class LinuxKeyboard { xic = 0; } compose_status = allocateComposeStatus(); + + // Allocate keyborad buffersize. + // When input method send long string to application, it needs a lot of memories. + if (keyboardBufferSize <= 0) { + keyboardBufferSize = KEYBOARD_BUFFER_SIZE; + } + temp_translation_buffer = new int[keyboardBufferSize]; + native_translation_buffer = BufferUtils.createByteBuffer(keyboardBufferSize); + char_buffer = CharBuffer.allocate(keyboardBufferSize); } private static native long getModifierMapping(long display); private static native void freeModifierMapping(long modifier_map); @@ -143,7 +153,7 @@ final class LinuxKeyboard { private static native int lookupModifierMap(long modifier_map, int index); private static native long keycodeToKeySym(long display, int key_code); - private static native long openIM(long display); + private static native long openIM(long display, String locale_modifiers); private static native long createIC(long xim, long window); private static native void setupIMEventMask(long display, long window, long xic); private static native ByteBuffer allocateComposeStatus(); @@ -204,10 +214,13 @@ private int lookupStringUnicode(long event_ptr, int[] translation_buffer) { native_translation_buffer.compact(); char_buffer.flip(); int i = 0; - while (char_buffer.hasRemaining() && i < translation_buffer.length) { - translation_buffer[i++] = char_buffer.get(); + // For lookuped multibyte string, convert all chars in the CharBuffer into a string, + // and return each characters. + for (char c: char_buffer.toString().toCharArray()) { + translation_buffer[i++] = (int)c; } - char_buffer.compact(); + // Because all bytes is converted to lookuped multibyte string, clear the CharBuffer. + char_buffer.clear(); return i; } private static native int utf8LookupString(long xic, long event_ptr, ByteBuffer buffer, int pos, int size); @@ -320,7 +333,11 @@ void releaseAll() { private void handleKeyEvent(long event_ptr, long millis, int event_type, int event_keycode, int event_state) { int keycode = getKeycode(event_ptr, event_state); byte key_state = getKeyState(event_type); - boolean repeat = key_state == key_down_buffer[keycode]; + // To know whether key events are repeating or not, + // compare current keycode and keystate with previous keycode and keystate. + // But, the keycode is Keyborad.KEY_NONE whenever input method sends string, + // So Keyborad.KEY_NONE has nothing to do with events repetition. + boolean repeat = ((keycode != 0) && (key_state == key_down_buffer[keycode])); if ( repeat && event_type == LinuxEvent.KeyRelease ) // This can happen for modifier keys after losing and regaining focus. return; key_down_buffer[keycode] = key_state; @@ -362,4 +379,14 @@ public boolean filterEvent(LinuxEvent event) { } return false; } + + public void setICFocus() { + nSetICFocus(xic); + } + private static native void nSetICFocus(long xic); + + public void unsetICFocus() { + nUnsetICFocus(xic); + } + private static native void nUnsetICFocus(long xic); } diff --git a/src/native/linux/org_lwjgl_opengl_LinuxKeyboard.c b/src/native/linux/org_lwjgl_opengl_LinuxKeyboard.c index ac8bcedaa..b48762895 100644 --- a/src/native/linux/org_lwjgl_opengl_LinuxKeyboard.c +++ b/src/native/linux/org_lwjgl_opengl_LinuxKeyboard.c @@ -82,9 +82,11 @@ JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_keycodeToKeySym(JNIE return key_sym; } -JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_openIM(JNIEnv *env, jclass unused, jlong display_ptr) { +JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_openIM(JNIEnv *env, jclass unused, jlong display_ptr, jstring locale_modifiers_ptr) { Display *disp = (Display *)(intptr_t)display_ptr; - XSetLocaleModifiers ("@im=none"); + const char *locale_modifiers = GetStringNativeChars(env, locale_modifiers_ptr); + + XSetLocaleModifiers(locale_modifiers); XIM xim = XOpenIM(disp, NULL, NULL, NULL); return (intptr_t)xim; } @@ -151,3 +153,17 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_utf8LookupString(JNIE positionBuffer(env, buffer_obj, num_bytes); return status; } + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_nSetICFocus(JNIEnv *env, jclass unused, jlong xic_ptr) { + XIC xic = (XIC)(intptr_t)xic_ptr; + + XSetICFocus(xic); +} + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxKeyboard_nUnsetICFocus(JNIEnv *env, jclass unused, jlong xic_ptr) { + XIC xic = (XIC)(intptr_t)xic_ptr; + + XUnsetICFocus(xic); +} + +