From 779166e39ed41b6f1a59e369f931f14083f68003 Mon Sep 17 00:00:00 2001 From: Le Hoang Long Date: Fri, 25 Apr 2025 21:11:03 +0700 Subject: [PATCH 1/4] bugfix: fix keyboard not working on mobile emulator mode --- internal/driver/mobile/app/x11.c | 11 +- internal/driver/mobile/app/x11.go | 216 ++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) diff --git a/internal/driver/mobile/app/x11.c b/internal/driver/mobile/app/x11.c index c83b2fd9c4..561ef55d8f 100644 --- a/internal/driver/mobile/app/x11.c +++ b/internal/driver/mobile/app/x11.c @@ -57,7 +57,7 @@ new_window(Display *x_dpy, EGLDisplay e_dpy, int w, int h, EGLContext *ctx, EGLS } attr.event_mask = StructureNotifyMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | KeyPressMask | KeyReleaseMask; Window win = XCreateWindow( x_dpy, root, 0, 0, w, h, 0, visInfo->depth, InputOutput, visInfo->visual, CWColormap | CWEventMask, &attr); @@ -141,6 +141,7 @@ void processEvents(void) { while (XPending(x_dpy)) { XEvent ev; + KeySym keysym; XNextEvent(x_dpy, &ev); switch (ev.type) { case ButtonPress: @@ -149,6 +150,14 @@ processEvents(void) { case ButtonRelease: onTouchEnd((float)ev.xbutton.x, (float)ev.xbutton.y); break; + case KeyPress: + keysym = XKeycodeToKeysym(x_dpy, ev.xkey.keycode, 0); + onKeyPress(keysym); + break; + case KeyRelease: + keysym = XKeycodeToKeysym(x_dpy, ev.xkey.keycode, 0); + onKeyRelease(keysym); + break; case MotionNotify: onTouchMove((float)ev.xmotion.x, (float)ev.xmotion.y); break; diff --git a/internal/driver/mobile/app/x11.go b/internal/driver/mobile/app/x11.go index da42a69421..83bab3db51 100644 --- a/internal/driver/mobile/app/x11.go +++ b/internal/driver/mobile/app/x11.go @@ -23,9 +23,11 @@ void swapBuffers(void); */ import "C" import ( + "fmt" "runtime" "time" + "fyne.io/fyne/v2/internal/driver/mobile/event/key" "fyne.io/fyne/v2/internal/driver/mobile/event/lifecycle" "fyne.io/fyne/v2/internal/driver/mobile/event/paint" "fyne.io/fyne/v2/internal/driver/mobile/event/size" @@ -117,6 +119,220 @@ func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) } //export onTouchEnd func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) } +//export onKeyPress +func onKeyPress(keycode int) { + theApp.events.In() <- key.Event{ + Direction: key.DirPress, + Code: X11KeySymToFyneKeyCode(keycode), + Rune: X11KeySymToRune(keycode), + } +} + +//export onKeyRelease +func onKeyRelease(keycode int) { + parsedRune := X11KeySymToRune(keycode) + fmt.Println("onKeyRelease", keycode, parsedRune) + theApp.events.In() <- key.Event{ + Direction: key.DirRelease, + Code: X11KeySymToFyneKeyCode(keycode), + Rune: parsedRune, + } +} + +func X11KeySymToRune(keysym int) rune { + if keysym >= 0x0061 && keysym <= 0x007A { // Lowercase a-z + return rune(keysym - 0x0061 + 'a') + } else if keysym >= 0x0041 && keysym <= 0x005A { // Uppercase A-Z + return rune(keysym - 0x0041 + 'A') + } else if keysym >= 0x0030 && keysym <= 0x0039 { // 0-9 + return rune(keysym - 0x0030 + '0') + } else { + return 0 + } +} + +func X11KeySymToFyneKeyCode(keysym int) key.Code { + // Handle alphabetic characters (a-z, A-Z) + if keysym >= 0x0061 && keysym <= 0x007A { // Lowercase a-z + return key.Code(0x04 + (keysym - 0x0061)) + } + if keysym >= 0x0041 && keysym <= 0x005A { // Uppercase A-Z + return key.Code(0x04 + (keysym - 0x0041)) + } + if keysym >= 0x0030 && keysym <= 0x0039 { // 0-9 + return key.Code(30 + (keysym - 0x0030)) + } + + switch keysym { + case 0xFF0D: + return key.CodeReturnEnter // XK_Return + case 0xFF1B: + return key.CodeEscape // XK_Escape + case 0xFF08: + return key.CodeDeleteBackspace // XK_BackSpace + case 0xFF09: + return key.CodeTab // XK_Tab + case 0x0020: + return key.CodeSpacebar // XK_space + case 0x002D: + return key.CodeHyphenMinus // XK_minus + case 0x003D: + return key.CodeEqualSign // XK_equal + case 0x005B: + return key.CodeLeftSquareBracket // XK_bracketleft + case 0x005D: + return key.CodeRightSquareBracket // XK_bracketright + case 0x005C: + return key.CodeBackslash // XK_backslash + case 0x003B: + return key.CodeSemicolon // XK_semicolon + case 0x0027: + return key.CodeApostrophe // XK_apostrophe + case 0x0060: + return key.CodeGraveAccent // XK_grave + case 0x002C: + return key.CodeComma // XK_comma + case 0x002E: + return key.CodeFullStop // XK_period + case 0x002F: + return key.CodeSlash // XK_slash + case 0xFFE5: + return key.CodeCapsLock // XK_Caps_Lock + case 0xFFBE: + return key.CodeF1 // XK_F1 + case 0xFFBF: + return key.CodeF2 // XK_F2 + case 0xFFC0: + return key.CodeF3 // XK_F3 + case 0xFFC1: + return key.CodeF4 // XK_F4 + case 0xFFC2: + return key.CodeF5 // XK_F5 + case 0xFFC3: + return key.CodeF6 // XK_F6 + case 0xFFC4: + return key.CodeF7 // XK_F7 + case 0xFFC5: + return key.CodeF8 // XK_F8 + case 0xFFC6: + return key.CodeF9 // XK_F9 + case 0xFFC7: + return key.CodeF10 // XK_F10 + case 0xFFC8: + return key.CodeF11 // XK_F11 + case 0xFFC9: + return key.CodeF12 // XK_F12 + case 0xFF13: + return key.CodePause // XK_Pause + case 0xFF63: + return key.CodeInsert // XK_Insert + case 0xFF50: + return key.CodeHome // XK_Home + case 0xFF55: + return key.CodePageUp // XK_Page_Up + case 0xFFFF: + return key.CodeDeleteForward // XK_Delete + case 0xFF57: + return key.CodeEnd // XK_End + case 0xFF56: + return key.CodePageDown // XK_Page_Down + case 0xFF53: + return key.CodeRightArrow // XK_Right + case 0xFF51: + return key.CodeLeftArrow // XK_Left + case 0xFF54: + return key.CodeDownArrow // XK_Down + case 0xFF52: + return key.CodeUpArrow // XK_Up + case 0xFF7F: + return key.CodeKeypadNumLock // XK_Num_Lock + case 0xFFAF: + return key.CodeKeypadSlash // XK_KP_Divide + case 0xFFAA: + return key.CodeKeypadAsterisk // XK_KP_Multiply + case 0xFFAD: + return key.CodeKeypadHyphenMinus // XK_KP_Subtract + case 0xFFAB: + return key.CodeKeypadPlusSign // XK_KP_Add + case 0xFF8D: + return key.CodeKeypadEnter // XK_KP_Enter + case 0xFF9C: + return key.CodeKeypad1 // XK_KP_1 + case 0xFF99: + return key.CodeKeypad2 // XK_KP_2 + case 0xFF9B: + return key.CodeKeypad3 // XK_KP_3 + case 0xFF96: + return key.CodeKeypad4 // XK_KP_4 + case 0xFF9D: + return key.CodeKeypad5 // XK_KP_5 + case 0xFF98: + return key.CodeKeypad6 // XK_KP_6 + case 0xFF95: + return key.CodeKeypad7 // XK_KP_7 + case 0xFF97: + return key.CodeKeypad8 // XK_KP_8 + case 0xFF9A: + return key.CodeKeypad9 // XK_KP_9 + case 0xFF9E: + return key.CodeKeypad0 // XK_KP_0 + case 0xFF9F: + return key.CodeKeypadFullStop // XK_KP_Decimal + case 0xFFBD: + return key.CodeKeypadEqualSign // XK_KP_Equal + case 0xFFCA: + return key.CodeF13 // XK_F13 + case 0xFFCB: + return key.CodeF14 // XK_F14 + case 0xFFCC: + return key.CodeF15 // XK_F15 + case 0xFFCD: + return key.CodeF16 // XK_F16 + case 0xFFCE: + return key.CodeF17 // XK_F17 + case 0xFFCF: + return key.CodeF18 // XK_F18 + case 0xFFD0: + return key.CodeF19 // XK_F19 + case 0xFFD1: + return key.CodeF20 // XK_F20 + case 0xFFD2: + return key.CodeF21 // XK_F21 + case 0xFFD3: + return key.CodeF22 // XK_F22 + case 0xFFD4: + return key.CodeF23 // XK_F23 + case 0xFFD5: + return key.CodeF24 // XK_F24 + case 0xFF6A: + return key.CodeHelp // XK_Help + case 0x1008FF12: + return key.CodeMute // XF86AudioMute + case 0x1008FF13: + return key.CodeVolumeUp // XF86AudioRaiseVolume + case 0x1008FF11: + return key.CodeVolumeDown // XF86AudioLowerVolume + case 0xFFE3: + return key.CodeLeftControl // XK_Control_L + case 0xFFE1: + return key.CodeLeftShift // XK_Shift_L + case 0xFFE9: + return key.CodeLeftAlt // XK_Alt_L + case 0xFFEB: + return key.CodeLeftGUI // XK_Super_L + case 0xFFE4: + return key.CodeRightControl // XK_Control_R + case 0xFFE2: + return key.CodeRightShift // XK_Shift_R + case 0xFFEA: + return key.CodeRightAlt // XK_Alt_R + case 0xFFEC: + return key.CodeRightGUI // XK_Super_R + } + + return 0 // Unknown or unmapped key +} + var stopped bool //export onStop From 3b0af98f85b624023c59bf41d6d6d7cf091701fb Mon Sep 17 00:00:00 2001 From: Le Hoang Long Date: Fri, 25 Apr 2025 21:18:23 +0700 Subject: [PATCH 2/4] bugfix: remove debug code --- internal/driver/mobile/app/x11.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/driver/mobile/app/x11.go b/internal/driver/mobile/app/x11.go index 83bab3db51..7ff566547e 100644 --- a/internal/driver/mobile/app/x11.go +++ b/internal/driver/mobile/app/x11.go @@ -23,7 +23,6 @@ void swapBuffers(void); */ import "C" import ( - "fmt" "runtime" "time" @@ -131,7 +130,6 @@ func onKeyPress(keycode int) { //export onKeyRelease func onKeyRelease(keycode int) { parsedRune := X11KeySymToRune(keycode) - fmt.Println("onKeyRelease", keycode, parsedRune) theApp.events.In() <- key.Event{ Direction: key.DirRelease, Code: X11KeySymToFyneKeyCode(keycode), From 14a7e34cd78350ef0a6bff7bbe4e1f4b0169c2c3 Mon Sep 17 00:00:00 2001 From: Le Hoang Long Date: Fri, 25 Apr 2025 21:52:54 +0700 Subject: [PATCH 3/4] Remove debug code and add missing rune --- internal/driver/mobile/app/x11.go | 132 ++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 16 deletions(-) diff --git a/internal/driver/mobile/app/x11.go b/internal/driver/mobile/app/x11.go index 7ff566547e..603493ae80 100644 --- a/internal/driver/mobile/app/x11.go +++ b/internal/driver/mobile/app/x11.go @@ -119,33 +119,133 @@ func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) } func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) } //export onKeyPress -func onKeyPress(keycode int) { +func onKeyPress(keySym int) { + keyCode := X11KeySymToFyneKeyCode(keySym) theApp.events.In() <- key.Event{ Direction: key.DirPress, - Code: X11KeySymToFyneKeyCode(keycode), - Rune: X11KeySymToRune(keycode), + Code: keyCode, + Rune: codeToRune(keyCode), } } //export onKeyRelease -func onKeyRelease(keycode int) { - parsedRune := X11KeySymToRune(keycode) +func onKeyRelease(keySym int) { + keyCode := X11KeySymToFyneKeyCode(keySym) theApp.events.In() <- key.Event{ Direction: key.DirRelease, - Code: X11KeySymToFyneKeyCode(keycode), - Rune: parsedRune, + Code: keyCode, + Rune: codeToRune(keyCode), } } -func X11KeySymToRune(keysym int) rune { - if keysym >= 0x0061 && keysym <= 0x007A { // Lowercase a-z - return rune(keysym - 0x0061 + 'a') - } else if keysym >= 0x0041 && keysym <= 0x005A { // Uppercase A-Z - return rune(keysym - 0x0041 + 'A') - } else if keysym >= 0x0030 && keysym <= 0x0039 { // 0-9 - return rune(keysym - 0x0030 + '0') - } else { - return 0 +func codeToRune(c key.Code) rune { + switch c { + case key.CodeA: + return 'a' + case key.CodeB: + return 'b' + case key.CodeC: + return 'c' + case key.CodeD: + return 'd' + case key.CodeE: + return 'e' + case key.CodeF: + return 'f' + case key.CodeG: + return 'g' + case key.CodeH: + return 'h' + case key.CodeI: + return 'i' + case key.CodeJ: + return 'j' + case key.CodeK: + return 'k' + case key.CodeL: + return 'l' + case key.CodeM: + return 'm' + case key.CodeN: + return 'n' + case key.CodeO: + return 'o' + case key.CodeP: + return 'p' + case key.CodeQ: + return 'q' + case key.CodeR: + return 'r' + case key.CodeS: + return 's' + case key.CodeT: + return 't' + case key.CodeU: + return 'u' + case key.CodeV: + return 'v' + case key.CodeW: + return 'w' + case key.CodeX: + return 'x' + case key.CodeY: + return 'y' + case key.CodeZ: + return 'z' + + case key.Code1: + return '1' + case key.Code2: + return '2' + case key.Code3: + return '3' + case key.Code4: + return '4' + case key.Code5: + return '5' + case key.Code6: + return '6' + case key.Code7: + return '7' + case key.Code8: + return '8' + case key.Code9: + return '9' + case key.Code0: + return '0' + + case key.CodeSpacebar: + return ' ' + case key.CodeHyphenMinus: + return '-' + case key.CodeEqualSign: + return '=' + case key.CodeLeftSquareBracket: + return '[' + case key.CodeRightSquareBracket: + return ']' + case key.CodeBackslash: + return '\\' + case key.CodeSemicolon: + return ';' + case key.CodeApostrophe: + return '\'' + case key.CodeGraveAccent: + return '`' + case key.CodeComma: + return ',' + case key.CodeFullStop: + return '.' + case key.CodeSlash: + return '/' + + case key.CodeReturnEnter: + return '\n' + case key.CodeTab: + return '\t' + + default: + return 0 // Unsupported code or non-printable character } } From 3c252b812d9252d53d443a6ada8f8913939a7f17 Mon Sep 17 00:00:00 2001 From: Le Hoang Long Date: Sat, 26 Apr 2025 13:49:13 +0700 Subject: [PATCH 4/4] bugfix: fix digit mapping --- internal/driver/mobile/app/x11.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/driver/mobile/app/x11.go b/internal/driver/mobile/app/x11.go index 603493ae80..36b30215aa 100644 --- a/internal/driver/mobile/app/x11.go +++ b/internal/driver/mobile/app/x11.go @@ -257,8 +257,11 @@ func X11KeySymToFyneKeyCode(keysym int) key.Code { if keysym >= 0x0041 && keysym <= 0x005A { // Uppercase A-Z return key.Code(0x04 + (keysym - 0x0041)) } - if keysym >= 0x0030 && keysym <= 0x0039 { // 0-9 - return key.Code(30 + (keysym - 0x0030)) + if keysym == 0x0030 { + return key.Code0 + } + if keysym >= 0x0031 && keysym <= 0x0039 { // 1-9 + return key.Code(30 + (keysym - 0x0031)) } switch keysym {