mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-23 09:49:41 +01:00
JBR-7662: Fix key repeat manager sometimes not cancelling properly [WLToolkit]
(cherry picked from commit e1b1116bb9)
This commit is contained in:
committed by
Nikita Gubarkov
parent
c73769e20a
commit
c901b53ba3
@@ -38,13 +38,16 @@ class WLKeyboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class KeyRepeatManager {
|
private class KeyRepeatManager {
|
||||||
|
// Methods and fields should only be accessed from the EDT
|
||||||
private final Timer timer = new Timer("WLKeyboard.KeyRepeatManager", true);
|
private final Timer timer = new Timer("WLKeyboard.KeyRepeatManager", true);
|
||||||
private TimerTask currentRepeatTask;
|
private TimerTask currentRepeatTask;
|
||||||
private int delayBeforeRepeatMillis;
|
private int delayBeforeRepeatMillis;
|
||||||
private int delayBetweenRepeatMillis;
|
private int delayBetweenRepeatMillis;
|
||||||
|
|
||||||
|
// called from native code
|
||||||
void setRepeatInfo(int charsPerSecond, int delayMillis) {
|
void setRepeatInfo(int charsPerSecond, int delayMillis) {
|
||||||
// this function receives (0, 0) when key repeat is disabled
|
// this function receives (0, 0) when key repeat is disabled
|
||||||
|
assert EventQueue.isDispatchThread();
|
||||||
this.delayBeforeRepeatMillis = delayMillis;
|
this.delayBeforeRepeatMillis = delayMillis;
|
||||||
if (charsPerSecond > 0) {
|
if (charsPerSecond > 0) {
|
||||||
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
||||||
@@ -59,26 +62,33 @@ class WLKeyboard {
|
|||||||
return this.delayBeforeRepeatMillis > 0 || this.delayBetweenRepeatMillis > 0;
|
return this.delayBeforeRepeatMillis > 0 || this.delayBetweenRepeatMillis > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from native code
|
||||||
void cancelRepeat() {
|
void cancelRepeat() {
|
||||||
|
assert EventQueue.isDispatchThread();
|
||||||
if (currentRepeatTask != null) {
|
if (currentRepeatTask != null) {
|
||||||
currentRepeatTask.cancel();
|
currentRepeatTask.cancel();
|
||||||
currentRepeatTask = null;
|
currentRepeatTask = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from native code
|
||||||
void startRepeat(long timestamp, int keycode) {
|
void startRepeat(long timestamp, int keycode) {
|
||||||
|
assert EventQueue.isDispatchThread();
|
||||||
cancelRepeat();
|
cancelRepeat();
|
||||||
if (keycode == 0 || !isRepeatEnabled()) {
|
if (keycode == 0 || !isRepeatEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long delta = timestamp - System.currentTimeMillis();
|
long delta = timestamp - System.currentTimeMillis();
|
||||||
|
|
||||||
currentRepeatTask = new TimerTask() {
|
currentRepeatTask = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
EventQueue.invokeAndWait(() -> {
|
EventQueue.invokeAndWait(() -> {
|
||||||
|
if (this == currentRepeatTask) {
|
||||||
handleKeyPress(delta + System.currentTimeMillis(), keycode, true);
|
handleKeyPress(delta + System.currentTimeMillis(), keycode, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (InterruptedException ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
@@ -136,6 +146,7 @@ class WLKeyboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLostFocus() {
|
public void onLostFocus() {
|
||||||
|
assert EventQueue.isDispatchThread();
|
||||||
keyRepeatManager.cancelRepeat();
|
keyRepeatManager.cancelRepeat();
|
||||||
cancelCompose();
|
cancelCompose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1204,6 +1204,9 @@ getJavaKeyCharForKeycode(xkb_keycode_t xkbKeycode) {
|
|||||||
// Posts an XKB keysym as KEY_TYPED events, without consulting the current compose state.
|
// Posts an XKB keysym as KEY_TYPED events, without consulting the current compose state.
|
||||||
static void
|
static void
|
||||||
handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
fprintf(stderr, "handleKeyTypeNoCompose: xkbKeycode = %d\n", xkbKeycode);
|
||||||
|
#endif
|
||||||
int bufSize = xkb.state_key_get_utf8(keyboard.state, xkbKeycode, NULL, 0) + 1;
|
int bufSize = xkb.state_key_get_utf8(keyboard.state, xkbKeycode, NULL, 0) + 1;
|
||||||
char buf[bufSize];
|
char buf[bufSize];
|
||||||
xkb.state_key_get_utf8(keyboard.state, xkbKeycode, buf, bufSize);
|
xkb.state_key_get_utf8(keyboard.state, xkbKeycode, buf, bufSize);
|
||||||
@@ -1213,8 +1216,17 @@ handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
|||||||
// Handles generating KEY_TYPED events for an XKB keysym, translating it using the active compose state
|
// Handles generating KEY_TYPED events for an XKB keysym, translating it using the active compose state
|
||||||
static void
|
static void
|
||||||
handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
fprintf(stderr, "handleKeyType(xkbKeycode = %d)\n", xkbKeycode);
|
||||||
|
#endif
|
||||||
xkb_keysym_t keysym = xkb.state_key_get_one_sym(keyboard.state, xkbKeycode);
|
xkb_keysym_t keysym = xkb.state_key_get_one_sym(keyboard.state, xkbKeycode);
|
||||||
|
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
char buf[256];
|
||||||
|
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||||
|
fprintf(stderr, "handleKeyType: keysym = %d (%s)\n", keysym, buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!keyboard.composeState ||
|
if (!keyboard.composeState ||
|
||||||
(xkb.compose_state_feed(keyboard.composeState, keysym) == XKB_COMPOSE_FEED_IGNORED)) {
|
(xkb.compose_state_feed(keyboard.composeState, keysym) == XKB_COMPOSE_FEED_IGNORED)) {
|
||||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||||
@@ -1250,12 +1262,24 @@ handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
|||||||
// 2. From the key repeat manager. In this case, isRepeat = true and isPressed = true.
|
// 2. From the key repeat manager. In this case, isRepeat = true and isPressed = true.
|
||||||
static void
|
static void
|
||||||
handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
fprintf(stderr, "handleKey(keycode = %d, isPressed = %d, isRepeat = %d)\n", keycode, isPressed, isRepeat);
|
||||||
|
#endif
|
||||||
JNIEnv *env = getEnv();
|
JNIEnv *env = getEnv();
|
||||||
|
|
||||||
xkb_keycode_t xkbKeycode = keycode + 8;
|
xkb_keycode_t xkbKeycode = keycode + 8;
|
||||||
|
bool keyRepeats = xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode);
|
||||||
xkb_keysym_t keysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_ACTIVE_LAYOUT);
|
xkb_keysym_t keysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_ACTIVE_LAYOUT);
|
||||||
xkb_keysym_t qwertyKeysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_QWERTY);
|
xkb_keysym_t qwertyKeysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_QWERTY);
|
||||||
|
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
char buf[256];
|
||||||
|
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||||
|
fprintf(stderr, "handleKey: keysym = %d (%s)\n", keysym, buf);
|
||||||
|
xkb.keysym_get_name(qwertyKeysym, buf, sizeof buf);
|
||||||
|
fprintf(stderr, "handleKey: qwertyKeysym = %d (%s)\n", qwertyKeysym, buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
int javaKeyCode, javaExtendedKeyCode, javaKeyLocation;
|
int javaKeyCode, javaExtendedKeyCode, javaKeyLocation;
|
||||||
|
|
||||||
// If the national layouts support is enabled, and the current keyboard is not ascii-capable,
|
// If the national layouts support is enabled, and the current keyboard is not ascii-capable,
|
||||||
@@ -1288,6 +1312,10 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WL_KEYBOARD_DEBUG
|
||||||
|
fprintf(stderr, "handleKey: javaKeyCode = %d\n", javaKeyCode);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct WLKeyEvent event = {
|
struct WLKeyEvent event = {
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
.id = isPressed ? java_awt_event_KeyEvent_KEY_PRESSED : java_awt_event_KeyEvent_KEY_RELEASED,
|
.id = isPressed ? java_awt_event_KeyEvent_KEY_PRESSED : java_awt_event_KeyEvent_KEY_RELEASED,
|
||||||
@@ -1303,11 +1331,11 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
|||||||
if (isPressed) {
|
if (isPressed) {
|
||||||
handleKeyType(timestamp, xkbKeycode);
|
handleKeyType(timestamp, xkbKeycode);
|
||||||
|
|
||||||
if (!isRepeat && xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode)) {
|
if (!isRepeat && keyRepeats) {
|
||||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, timestamp, keycode);
|
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, timestamp, keycode);
|
||||||
JNU_CHECK_EXCEPTION(env);
|
JNU_CHECK_EXCEPTION(env);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (keyRepeats) {
|
||||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, cancelRepeatMID);
|
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, cancelRepeatMID);
|
||||||
JNU_CHECK_EXCEPTION(env);
|
JNU_CHECK_EXCEPTION(env);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user