@@ -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}
29402948static 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}
29702992static 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
29753006static 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}
31703245static void focus_cb (GLFWwindow*,int f){
0 commit comments