手機 - Unihertz Titan 2 (None-EEA) - 如何修改Termux-X11按鍵



參考資訊:
https://github.com/steward-fu/website/releases/tag/titan2

termux-x11_mod_key_commit-6d62752.diff

diff --git a/app/src/main/cpp/lorie/activity.c b/app/src/main/cpp/lorie/activity.c
index 8a51c11..066dfcb 100644
--- a/app/src/main/cpp/lorie/activity.c
+++ b/app/src/main/cpp/lorie/activity.c
@@ -22,6 +22,11 @@
 #pragma ide diagnostic ignored "ConstantFunctionResult"
 #define log(prio, ...) __android_log_print(ANDROID_LOG_ ## prio, "LorieNative", __VA_ARGS__)
 
+static struct {
+    jfloat x;
+    jfloat y;
+} mouse;
+
 extern volatile int conn_fd; // The only variable from shared with X server code.
 
 static struct {
@@ -299,6 +304,10 @@ static void sendMouseEvent(__unused JNIEnv* env, __unused jobject cls, jfloat x,
         if (which_button > 0)
             (*env)->CallVoidMethod(env, globalThiz, MainActivity.resetIme);
         lorieEvent e = { .mouse = { .t = EVENT_MOUSE, .x = x, .y = y, .detail = which_button, .down = button_down, .relative = relative } };
+
+        mouse.x = x;
+        mouse.y = y;
+        log(DEBUG, "Sending mouse: %d (x:%f, y:%f, down:%d, relative:%d)", which_button, x, y, button_down, relative);
         write(conn_fd, &e, sizeof(e));
     }
 }
@@ -306,6 +315,7 @@ static void sendMouseEvent(__unused JNIEnv* env, __unused jobject cls, jfloat x,
 static void sendTouchEvent(__unused JNIEnv* env, __unused jobject cls, jint action, jint id, jint x, jint y) {
     if (conn_fd != -1 && action != -1) {
         lorieEvent e = { .touch = { .t = EVENT_TOUCH, .type = action, .id = id, .x = x, .y = y } };
+        log(DEBUG, "Sending touch: %d (x:%d, y:%d, id:%d)", action, x, y, id);
         write(conn_fd, &e, sizeof(e));
     }
 }
@@ -327,10 +337,282 @@ static void requestStylusEnabled(__unused JNIEnv *env, __unused jclass clazz, jb
     }
 }
 
+static jboolean sendMySpecialKey(jint s, jint code, jboolean key_down)
+{
+    lorieEvent t = { .key = { .t = EVENT_KEY, .key = code + 8, .state = key_down } };
+
+    if (key_down) {
+        t.key.key = s + 8;
+        t.key.state = 1;
+        t.key.t = EVENT_KEY;
+        write(conn_fd, &t, sizeof(t));
+
+        t.key.key = code + 8;
+        write(conn_fd, &t, sizeof(t));
+    }
+    else {
+        t.key.key = code + 8;
+        t.key.state = 0;
+        t.key.t = EVENT_KEY;
+        write(conn_fd, &t, sizeof(t));
+
+        t.key.key = s + 8;
+        t.key.state = 0;
+        write(conn_fd, &t, sizeof(t));
+    }
+
+    return true;
+}
+
 static jboolean sendKeyEvent(__unused JNIEnv* env, __unused jobject cls, jint scan_code, jint key_code, jboolean key_down) {
     if (conn_fd != -1) {
+        static int alt_press = 0;
+        static int iso3_press = 0;
+        static int ctrl_press = 0;
+        static int shift_press = 0;
+        static int mouse_toggle = 0;
+
         int code = (scan_code) ?: android_to_linux_keycode[key_code];
         log(DEBUG, "Sending key: %d (%d %d %d)", code + 8, scan_code, key_code, key_down);
+
+        switch (code + 8)   {
+        case 50: // Shift
+            shift_press = !!key_down;
+            code = KEY_LEFTSHIFT;
+            break;
+        case 261: // sym
+            alt_press = !!key_down;
+            return true;
+        case 166: // back
+            code = (alt_press || iso3_press) ? KEY_HOME : KEY_LEFT;
+            break;
+        case 588: // AppSwitch
+            code = (alt_press || iso3_press) ? KEY_PAGEUP : KEY_UP;
+            break;
+        case 259: // Back
+            code = (alt_press || iso3_press) ? KEY_PAGEDOWN : KEY_DOWN;
+            break;
+        case 108: // alt
+            code = (alt_press || iso3_press) ? KEY_END : KEY_RIGHT;
+            break;
+        case 257: // Fun1
+            ctrl_press = !!key_down;
+            code = KEY_LEFTCTRL;
+            break;
+        case 258: // Fun2
+            iso3_press = !!key_down;
+            return true;
+        case 24: // Q
+            if (alt_press) {
+                code = KEY_0;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_6, key_down);
+            }
+            break;
+        case 25: // W
+            if (alt_press) {
+                code = KEY_1;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_BACKSLASH, key_down);
+            }
+            break;
+        case 26: // E
+            if (alt_press) {
+                code = KEY_2;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_7, key_down);
+            }
+            break;
+        case 27: // R
+            if (alt_press) {
+                code = KEY_3;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_4, key_down);
+            }
+            break;
+        case 28: // T
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_9, key_down);
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_LEFTBRACE, key_down);
+            }
+            break;
+        case 29: // Y
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_0, key_down);
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_RIGHTBRACE, key_down);
+            }
+            break;
+        case 30: // U
+            if (alt_press) {
+                code = KEY_MINUS;
+            }
+            if (iso3_press) {
+                code = KEY_EQUAL;
+            }
+            break;
+        case 31: // I
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_MINUS, key_down);
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_GRAVE, key_down);
+            }
+            break;
+        case 32: // O
+            if (alt_press) {
+                code = KEY_SLASH;
+            }
+            if (iso3_press) {
+                code = KEY_BACKSLASH;
+            }
+            break;
+        case 33: // P
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_SEMICOLON, key_down);
+            }
+            if (iso3_press) {
+                code = KEY_SEMICOLON;
+            }
+            break;
+        case 38: // A
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_2, key_down);
+            }
+            if (iso3_press) {
+                code = KEY_GRAVE;
+            }
+            break;
+        case 39: // S
+            if (alt_press) {
+                code = KEY_4;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_5, key_down);
+            }
+            break;
+        case 40: // D
+            if (alt_press) {
+                code = KEY_5;
+            }
+            break;
+        case 41: // F
+            if (alt_press) {
+                code = KEY_6;
+            }
+            break;
+        case 42: // G
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_8, key_down);
+            }
+            if (iso3_press) {
+                code = KEY_LEFTBRACE;
+            }
+            break;
+        case 43: // H
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_3, key_down);
+            }
+            if (iso3_press) {
+                code = KEY_RIGHTBRACE;
+            }
+            break;
+        case 44: // J
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_EQUAL, key_down);
+            }
+            if (iso3_press) {
+                mouse_toggle = 0;
+                lorieEvent e = { .mouse = { .t = EVENT_MOUSE, .x = 0, .y = 0, .detail = 1, .down = !!key_down, .relative = 1 } };
+                write(conn_fd, &e, sizeof(e));
+                return true;
+            }
+            break;
+        case 45: // K
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_APOSTROPHE, key_down);
+            }
+            if (iso3_press && key_down) {
+                mouse_toggle ^= 1;
+                lorieEvent e = { .mouse = { .t = EVENT_MOUSE, .x = 0, .y = 0, .detail = 1, .down = mouse_toggle, .relative = 1 } };
+                write(conn_fd, &e, sizeof(e));
+                return true;
+            }
+            break;
+        case 46: // L
+            if (alt_press) {
+                code = KEY_APOSTROPHE;
+            }
+            if (iso3_press) {
+                mouse_toggle = 0;
+                lorieEvent e = { .mouse = { .t = EVENT_MOUSE, .x = 0, .y = 0, .detail = 3, .down = !!key_down, .relative = 1 } };
+                write(conn_fd, &e, sizeof(e));
+                return true;
+            }
+            break;
+        case 22: // BACKSPACE
+            if (alt_press) {
+                code = KEY_TAB;
+            }
+            break;
+        case 52: // Z
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_1, key_down);
+            }
+            break;
+        case 53: // X
+            if (alt_press) {
+                code = KEY_7;
+            }
+            break;
+        case 54: // C
+            if (alt_press) {
+                code = KEY_8;
+            }
+            break;
+        case 55: // V
+            if (alt_press) {
+                code = KEY_9;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_COMMA, key_down);
+            }
+            break;
+        case 56: // B
+            if (alt_press) {
+                code = KEY_DOT;
+            }
+            if (iso3_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_DOT, key_down);
+            }
+            break;
+        case 57: // N
+            if (alt_press) {
+                code = KEY_COMMA;
+            }
+            break;
+        case 58: // M
+            if (alt_press) {
+                return sendMySpecialKey(KEY_LEFTSHIFT, KEY_SLASH, key_down);
+            }
+            if (iso3_press) {
+                code = KEY_F9;
+            }
+            break;
+        case 36: // Enter
+            if (alt_press) {
+                code = KEY_ESC;
+            }
+            break;
+        }
+
         lorieEvent e = { .key = { .t = EVENT_KEY, .key = code + 8, .state = key_down } };
         write(conn_fd, &e, sizeof(e));
     }

編譯步驟:

$ cd
$ wget https://download.oracle.com/java/24/latest/jdk-24_linux-x64_bin.tar.gz
$ tar xvf jdk-24_linux-x64_bin.tar.gz -C ~/
$ export JAVA_HOME=~/jdk-24.0.1
$ export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
$ export PATH=$JAVA_HOME/bin:$PATH

$ cd
$ wget https://dl.google.com/dl/android/studio/ide-zips/2025.2.2.8/android-studio-2025.2.2.8-linux.tar.gz
$ tar xvf android-studio-2025.2.2.8-linux.tar.gz
$ cd android-studio
$ wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
$ unzip commandlinetools-linux-11076708_latest.zip
$ mv cmdline-tools/ latest
$ mkdir cmdline-tools
$ mv latest/ cmdline-tools/
$ yes | ./cmdline-tools/latest/bin/sdkmanager --licenses
$ export ANDROID_HOME=`pwd`/android-studio/

$ cd
$ git clone --recurse-submodules https://github.com/termux/termux-x11 
$ cd termux-x11
$ git checkout 6d62752
$ wget https://github.com/steward-fu/website/releases/download/titan2/termux-x11_mod_key_commit-6d62752.diff
$ git apply termux-x11_mod_key_commit-6d62752.diff
$ ./gradlew build

P.S. 編譯後,安裝app-arm64-v8a-debug.apk即可

安裝後,修改如下設定:
Func1 key:Tab Key
Func2 key:Sym key

Settings => Accessibility => Termux:X11 KeyInterceptor => On
Termux-X11 => Keyboard => Enforce char based input => On
Termux-X11 => Keyboard => Prefer scancodes when possible => On

Titan2按鍵Debian按鍵+MYALT+MYSHIFT
Func1Ctrl
Func2MYSHIFT
ShiftShift
symMYALT
BackLEFTHOMEHOME
AppSwitchUPPAGEUPPAGEUP
fnDOWNPAGEDOWNPAGEDOWN
altRIGHTENDEND
Qq0^
Ww1|
Ee2&
Rr3$
Tt({
Yy)}
Uu_=
Ii-~
Oo/\
Pp:;
Aa@`
Ss4%
Dd5
Ff6
Gg*[
Hh#]
Jj+Mouse Left Button
Kk"Mouse Left Button (Toggle)
Ll'Mouse Right Button
BackspaceBackspaceTab
Zz!
Xx7
Cc8
Vv9<
SPACESPACE
Bb.>
Nn,
Mm?F9
EnterEnterEscape