Skip to content

Commit c6f3e4e

Browse files
committed
Fix stuck/ghost keys: atomic key translation on release (Bug A), scancode-based press tracking (Bug B)
1 parent ac31fff commit c6f3e4e

1 file changed

Lines changed: 89 additions & 14 deletions

File tree

src/Processing.cpp

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2934,8 +2934,16 @@ static void cursor_pos_cb(GLFWwindow*, double x, double y) {
29342934
p->pmouseY = p->mouseY;
29352935
p->mouseX = (float)x;
29362936
p->mouseY = (float)y;
2937-
if (p->_mousePressed) { p->mouseDragged(); }
2938-
else { p->mouseMoved(); }
2937+
{ auto [sh,ct,al,me] = std::make_tuple(
2938+
(p->g_currentMods&GLFW_MOD_SHIFT)!=0,
2939+
(p->g_currentMods&GLFW_MOD_CONTROL)!=0,
2940+
(p->g_currentMods&GLFW_MOD_ALT)!=0,
2941+
(p->g_currentMods&GLFW_MOD_SUPER)!=0);
2942+
int act = p->_mousePressed ? MouseEvent::DRAG : MouseEvent::MOVE;
2943+
MouseEvent me2{p->mouseX, p->mouseY, p->mouseButton, 0, sh, ct, al, me, act};
2944+
if (p->_mousePressed) { p->mouseDragged(); p->mouseDragged(me2); }
2945+
else { p->mouseMoved(); p->mouseMoved(me2); }
2946+
}
29392947
}
29402948
static void mouse_btn_cb(GLFWwindow*, int btn, int action, int mods) {
29412949
auto* p = PApplet::g_papplet; if(!p) return;
@@ -2949,8 +2957,13 @@ static void mouse_btn_cb(GLFWwindow*, int btn, int action, int mods) {
29492957
else if (btn == GLFW_MOUSE_BUTTON_RIGHT) p->mouseButton = RIGHT;
29502958
else p->mouseButton = CENTER;
29512959
p->_eventDrewSomething=true;
2952-
p->_eventDrewSomething=true;
2953-
p->mousePressed();
2960+
{ auto sh=(p->g_currentMods&GLFW_MOD_SHIFT)!=0;
2961+
auto ct=(p->g_currentMods&GLFW_MOD_CONTROL)!=0;
2962+
auto al=(p->g_currentMods&GLFW_MOD_ALT)!=0;
2963+
auto me=(p->g_currentMods&GLFW_MOD_SUPER)!=0;
2964+
MouseEvent ev{p->mouseX, p->mouseY, p->mouseButton, 1, sh, ct, al, me, MouseEvent::PRESS};
2965+
p->mousePressed(); p->mousePressed(ev);
2966+
}
29542967
p->mouseWasPressed = true;
29552968
} else if (action == GLFW_RELEASE) {
29562969
if(btn>=0&&btn<8) p->mouseButtons[btn]=false;
@@ -2962,14 +2975,32 @@ static void mouse_btn_cb(GLFWwindow*, int btn, int action, int mods) {
29622975
p->mouseButton = p->mouseButtons[GLFW_MOUSE_BUTTON_LEFT] ? LEFT :
29632976
p->mouseButtons[GLFW_MOUSE_BUTTON_RIGHT] ? RIGHT :
29642977
p->mouseButtons[GLFW_MOUSE_BUTTON_MIDDLE] ? CENTER : -1;
2965-
p->mouseReleased();
2966-
if(p->mouseWasPressed) p->mouseClicked();
2978+
{ auto sh=(p->g_currentMods&GLFW_MOD_SHIFT)!=0;
2979+
auto ct=(p->g_currentMods&GLFW_MOD_CONTROL)!=0;
2980+
auto al=(p->g_currentMods&GLFW_MOD_ALT)!=0;
2981+
auto me=(p->g_currentMods&GLFW_MOD_SUPER)!=0;
2982+
MouseEvent ev{p->mouseX, p->mouseY, p->mouseButton, 1, sh, ct, al, me, MouseEvent::RELEASE};
2983+
p->mouseReleased(); p->mouseReleased(ev);
2984+
if(p->mouseWasPressed) {
2985+
MouseEvent ce{p->mouseX, p->mouseY, p->mouseButton, 1, sh, ct, al, me, MouseEvent::CLICK};
2986+
p->mouseClicked(); p->mouseClicked(ce);
2987+
}
2988+
}
29672989
p->mouseWasPressed=false;
29682990
}
29692991
}
29702992
static void scroll_cb(GLFWwindow*,double,double yoffset){
29712993
auto* p = PApplet::g_papplet; if(!p) return;
2972-
if(p->_onMouseWheel)p->_onMouseWheel((int)yoffset);
2994+
int delta = (int)yoffset;
2995+
if(p->_onMouseWheel) p->_onMouseWheel(delta);
2996+
p->mouseWheel(delta);
2997+
{ auto sh=(p->g_currentMods&GLFW_MOD_SHIFT)!=0;
2998+
auto ct=(p->g_currentMods&GLFW_MOD_CONTROL)!=0;
2999+
auto al=(p->g_currentMods&GLFW_MOD_ALT)!=0;
3000+
auto me=(p->g_currentMods&GLFW_MOD_SUPER)!=0;
3001+
MouseEvent ev{p->mouseX, p->mouseY, p->mouseButton, delta, sh, ct, al, me, MouseEvent::WHEEL};
3002+
p->mouseWheel(ev);
3003+
}
29733004
}
29743005

29753006
static void char_cb(GLFWwindow*, unsigned int codepoint) {
@@ -2983,11 +3014,11 @@ static void char_cb(GLFWwindow*, unsigned int codepoint) {
29833014
if (p->g_pendingKeyPressed) {
29843015
p->g_pendingKeyPressed = false;
29853016
p->_eventDrewSomething=true;
2986-
p->keyPressed();
3017+
p->keyPressed(); p->keyPressed(KeyEvent{p->key, p->keyCode, (p->g_currentMods&GLFW_MOD_SHIFT)!=0, (p->g_currentMods&GLFW_MOD_CONTROL)!=0, (p->g_currentMods&GLFW_MOD_ALT)!=0, (p->g_currentMods&GLFW_MOD_SUPER)!=0, KeyEvent::PRESS});
29873018
}
29883019
// keyTyped() -- Processing standard: only printable chars, no action keys
29893020
// Action keys (Ctrl, Shift, Alt, etc.) never reach char_cb, so this is correct.
2990-
p->keyTyped();
3021+
p->keyTyped(); p->keyTyped(KeyEvent{p->key, p->keyCode, (p->g_currentMods&GLFW_MOD_SHIFT)!=0, (p->g_currentMods&GLFW_MOD_CONTROL)!=0, (p->g_currentMods&GLFW_MOD_ALT)!=0, (p->g_currentMods&GLFW_MOD_SUPER)!=0, KeyEvent::TYPE});
29913022
}
29923023

29933024
// Translate GLFW key code to Java KeyEvent.VK_* value.
@@ -3081,10 +3112,48 @@ static int glfw_to_processing_keycode(int k) {
30813112
}
30823113
}
30833114

3084-
static void key_cb(GLFWwindow* w, int k, int /*scancode*/, int action, int mods) {
3115+
// Scancode-based press tracking for Bug B (GLFW #2417 Windows virtual key mismatch)
3116+
static std::unordered_set<int> s_pressedScancodes;
3117+
3118+
// Translate GLFW key to Processing key/keyCode atomically
3119+
static void translate_glfw_key(int k, char16_t* outKey, int* outKeyCode) {
3120+
*outKeyCode = glfw_to_java_keycode(k);
3121+
switch (k) {
3122+
case GLFW_KEY_BACKSPACE: *outKey = 8; return;
3123+
case GLFW_KEY_TAB: *outKey = 9; return;
3124+
case GLFW_KEY_ENTER:
3125+
case GLFW_KEY_KP_ENTER: *outKey = 10; return;
3126+
case GLFW_KEY_ESCAPE: *outKey = 27; return;
3127+
case GLFW_KEY_SPACE: *outKey = 32; return;
3128+
case GLFW_KEY_DELETE: *outKey = 127; return;
3129+
case GLFW_KEY_UP: case GLFW_KEY_DOWN:
3130+
case GLFW_KEY_LEFT: case GLFW_KEY_RIGHT:
3131+
case GLFW_KEY_HOME: case GLFW_KEY_END:
3132+
case GLFW_KEY_PAGE_UP: case GLFW_KEY_PAGE_DOWN:
3133+
case GLFW_KEY_LEFT_SHIFT: case GLFW_KEY_RIGHT_SHIFT:
3134+
case GLFW_KEY_LEFT_CONTROL: case GLFW_KEY_RIGHT_CONTROL:
3135+
case GLFW_KEY_LEFT_ALT: case GLFW_KEY_RIGHT_ALT:
3136+
case GLFW_KEY_LEFT_SUPER: case GLFW_KEY_RIGHT_SUPER:
3137+
case GLFW_KEY_INSERT: case GLFW_KEY_CAPS_LOCK:
3138+
case GLFW_KEY_F1: case GLFW_KEY_F2: case GLFW_KEY_F3:
3139+
case GLFW_KEY_F4: case GLFW_KEY_F5: case GLFW_KEY_F6:
3140+
case GLFW_KEY_F7: case GLFW_KEY_F8: case GLFW_KEY_F9:
3141+
case GLFW_KEY_F10: case GLFW_KEY_F11: case GLFW_KEY_F12:
3142+
*outKey = CODED; return;
3143+
default:
3144+
if (k >= GLFW_KEY_A && k <= GLFW_KEY_Z)
3145+
*outKey = (char16_t)('a' + (k - GLFW_KEY_A));
3146+
else
3147+
*outKey = (char16_t)k;
3148+
return;
3149+
}
3150+
}
3151+
3152+
static void key_cb(GLFWwindow* w, int k, int scancode, int action, int mods) {
30853153
auto* p = PApplet::g_papplet; if(!p) return;
30863154
p->g_currentMods = mods; // capture before callbacks fire
30873155
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
3156+
if (action == GLFW_PRESS) s_pressedScancodes.insert(scancode);
30883157
p->_keyPressed = true;
30893158
if(k>=0&&k<349) p->keys[k]=true;
30903159
{ int pk=glfw_to_processing_keycode(k); if(pk>=0&&pk<256) {
@@ -3147,24 +3216,30 @@ static void key_cb(GLFWwindow* w, int k, int /*scancode*/, int action, int mods)
31473216
// Fire keyPressed() now unless deferred to char_cb
31483217
if (!p->g_pendingKeyPressed) {
31493218
if(action==GLFW_PRESS) p->_eventDrewSomething=true;
3150-
p->keyPressed();
3219+
p->keyPressed(); p->keyPressed(KeyEvent{p->key, p->keyCode, (p->g_currentMods&GLFW_MOD_SHIFT)!=0, (p->g_currentMods&GLFW_MOD_CONTROL)!=0, (p->g_currentMods&GLFW_MOD_ALT)!=0, (p->g_currentMods&GLFW_MOD_SUPER)!=0, KeyEvent::PRESS});
31513220
// Java Processing: ESC closes the sketch unless keyPressed() set p->key=0
31523221
if (p->key == (char16_t)27 && p->gWindow)
31533222
glfwSetWindowShouldClose(p->gWindow, GLFW_TRUE);
31543223
}
31553224

31563225
} else if (action == GLFW_RELEASE) {
3226+
// Bug B guard: drop phantom releases with no matching press scancode
3227+
if (s_pressedScancodes.find(scancode) == s_pressedScancodes.end()) return;
3228+
s_pressedScancodes.erase(scancode);
31573229
if(k>=0&&k<349) p->keys[k]=false;
31583230
{ int pk=glfw_to_processing_keycode(k); if(pk>=0&&pk<256) {
31593231
p->keysDown[pk]=false;
31603232
if(pk>='A'&&pk<='Z') p->keysDown[pk+32]=false;
31613233
if(pk>='a'&&pk<='z') p->keysDown[pk-32]=false;
31623234
} }
3163-
// check if any key still held
31643235
bool anyHeld=false; for(int i=0;i<349;i++) if(p->keys[i]){anyHeld=true;break;}
31653236
p->_keyPressed=anyHeld;
3166-
p->g_currentMods = mods; // update on release too
3167-
p->keyReleased();
3237+
p->g_currentMods = mods;
3238+
// Fix A: translate key/keyCode atomically from k, not from stale globals
3239+
char16_t relKey; int relKeyCode;
3240+
translate_glfw_key(k, &relKey, &relKeyCode);
3241+
p->key = relKey; p->keyCode = relKeyCode;
3242+
p->keyReleased(); p->keyReleased(KeyEvent{p->key, p->keyCode, (p->g_currentMods&GLFW_MOD_SHIFT)!=0, (p->g_currentMods&GLFW_MOD_CONTROL)!=0, (p->g_currentMods&GLFW_MOD_ALT)!=0, (p->g_currentMods&GLFW_MOD_SUPER)!=0, KeyEvent::RELEASE});
31683243
}
31693244
}
31703245
static void focus_cb(GLFWwindow*,int f){

0 commit comments

Comments
 (0)