diff --git a/.gitmodules b/.gitmodules
index b7a790d44..537b59c8d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,27 +1,35 @@
-[submodule "app/src/main/jni/wayland"]
- path = app/src/main/jni/wayland
+[submodule "app/src/main/cpp/wayland"]
+ path = app/src/main/cpp/wayland
url = https://gitlab.freedesktop.org/wayland/wayland
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/libxcb"]
- path = x11-client-experimental/src/main/cpp/libxcb
+[submodule "app/src/main/cpp/libxcb"]
+ path = app/src/main/cpp/libxcb
url = https://gitlab.freedesktop.org/xorg/lib/libxcb
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/xorgproto"]
- path = x11-client-experimental/src/main/cpp/xorgproto
+[submodule "app/src/main/cpp/xorgproto"]
+ path = app/src/main/cpp/xorgproto
url = https://gitlab.freedesktop.org/xorg/proto/xorgproto
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/xcbproto"]
- path = x11-client-experimental/src/main/cpp/xcbproto
+[submodule "app/src/main/cpp/xcbproto"]
+ path = app/src/main/cpp/xcbproto
url = https://gitlab.freedesktop.org/xorg/proto/xcbproto
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/libXau"]
- path = x11-client-experimental/src/main/cpp/libXau
+[submodule "app/src/main/cpp/libXau"]
+ path = app/src/main/cpp/libXau
url = https://gitlab.freedesktop.org/xorg/lib/libxau
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/libxcb-errors"]
- path = x11-client-experimental/src/main/cpp/libxcb-errors
+[submodule "app/src/main/cpp/libxcb-errors"]
+ path = app/src/main/cpp/libxcb-errors
url = https://gitlab.freedesktop.org/xorg/lib/libxcb-errors
ignore = dirty
-[submodule "x11-client-experimental/src/main/cpp/libxcvt"]
- path = x11-client-experimental/src/main/cpp/libxcvt
+[submodule "app/src/main/cpp/libxcvt"]
+ path = app/src/main/cpp/libxcvt
url = https://gitlab.freedesktop.org/xorg/lib/libxcvt
+ ignore = dirty
+[submodule "app/src/main/cpp/libxkbcommon"]
+ path = app/src/main/cpp/libxkbcommon
+ url = https://github.com/xkbcommon/libxkbcommon
+ ignore = dirty
+[submodule "app/src/main/cpp/libandroid-support"]
+ path = app/src/main/cpp/libandroid-support
+ url = https://github.com/termux/libandroid-support/
diff --git a/app/build.gradle b/app/build.gradle
index e68fc7c7a..9d731e317 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,8 +20,8 @@ android {
versionName "1.02.06"
externalNativeBuild {
- ndkBuild {
- arguments "WAYLAND_GENERATED=${waylandOut}"
+ cmake {
+ arguments "-DWAYLAND_GENERATED_DIR=${waylandOut}"
}
}
}
@@ -52,8 +52,8 @@ android {
}
externalNativeBuild {
- ndkBuild {
- path "src/main/jni/Android.mk"
+ cmake {
+ path "src/main/cpp/CMakeLists.txt"
}
}
@@ -69,8 +69,8 @@ android {
task patchWayland {
println("Patch can fail here, it is normal if a patch was already applied")
- ant.patch(patchfile: "${project.projectDir}/src/main/jni/wayland.patch", dir: "${project.projectDir}/src/main/jni/wayland/src", failonerror:false)
- ant.patch(patchfile: "${project.projectDir}/src/main/jni/wayland2.patch", dir: "${project.projectDir}/src/main/jni/wayland", failonerror:false)
+ ant.patch(patchfile: "${project.projectDir}/src/main/cpp/wayland.patch", dir: "${project.projectDir}/src/main/cpp/wayland/src", failonerror:false)
+ ant.patch(patchfile: "${project.projectDir}/src/main/cpp/wayland2.patch", dir: "${project.projectDir}/src/main/cpp/wayland", failonerror:false)
}
tasks.matching { it.name.toLowerCase().contains("ndk") && !it.name.toLowerCase().contains("clean") }
@@ -84,7 +84,7 @@ wayland {
dependencies {
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
- implementation 'com.termux.termux-app:termux-shared:-SNAPSHOT'
+ implementation 'com.termux.termux-app:termux-shared:2f5a6f7de6'
implementation 'com.google.android.material:material:1.8.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
//noinspection GradleDependency
@@ -95,5 +95,5 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.annotation:annotation:1.5.0'
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
- compileOnly project(':app:stub')
+ compileOnly project(':shell-loader:stub')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 83b7f8077..5248e55c2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
@@ -18,13 +19,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
- tools:ignore="GoogleAppIndexingWarning"
- >
-
-
+
+ android:resizeableActivity="true"
+ android:exported="true">
-
diff --git a/app/src/main/aidl/com/termux/x11/ICmdEntryInterface.aidl b/app/src/main/aidl/com/termux/x11/ICmdEntryInterface.aidl
new file mode 100644
index 000000000..c13edb781
--- /dev/null
+++ b/app/src/main/aidl/com/termux/x11/ICmdEntryInterface.aidl
@@ -0,0 +1,8 @@
+package com.termux.x11;
+
+// This interface is used by utility on termux side.
+interface ICmdEntryInterface {
+ void outputResize(int width, int height);
+ ParcelFileDescriptor getXConnection();
+ ParcelFileDescriptor getLogcatOutput();
+}
\ No newline at end of file
diff --git a/app/src/main/aidl/com/termux/x11/ITermuxX11Internal.aidl b/app/src/main/aidl/com/termux/x11/ITermuxX11Internal.aidl
deleted file mode 100644
index d3c4aa868..000000000
--- a/app/src/main/aidl/com/termux/x11/ITermuxX11Internal.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.termux.x11;
-
-// This interface is used by utility on termux side.
-interface ITermuxX11Internal {
- ParcelFileDescriptor getWaylandFD();
- ParcelFileDescriptor getLogFD();
- void finish();
-}
\ No newline at end of file
diff --git a/x11-client-experimental/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt
similarity index 59%
rename from x11-client-experimental/src/main/cpp/CMakeLists.txt
rename to app/src/main/cpp/CMakeLists.txt
index aa5adcf4e..cc36fb0d5 100644
--- a/x11-client-experimental/src/main/cpp/CMakeLists.txt
+++ b/app/src/main/cpp/CMakeLists.txt
@@ -4,6 +4,28 @@ set(CMAKE_CXX_STANDARD 20)
find_package(Python3 REQUIRED)
+####################################################################################################
+######################################### LIBWAYLAND ###############################################
+####################################################################################################
+
+set(WAYLAND_SOURCES connection.c event-loop.c wayland-protocol.c wayland-server.c wayland-shm.c wayland-os.c wayland-util.c)
+list(TRANSFORM WAYLAND_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/wayland/src/)
+add_library(wayland-server SHARED ${WAYLAND_SOURCES})
+target_include_directories(wayland-server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/wayland ${CMAKE_CURRENT_SOURCE_DIR}/wayland/src)
+
+####################################################################################################
+########################################### LORIE ##################################################
+####################################################################################################
+
+file(GLOB WAYLAND_GENERATED "${WAYLAND_GENERATED_DIR}/*.cpp")
+add_library(lorie SHARED
+ ${CMAKE_CURRENT_SOURCE_DIR}/lorie/compositor.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/lorie/lorie_wayland_server.cpp
+ ${WAYLAND_GENERATED}
+ )
+target_include_directories(lorie PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lorie ${WAYLAND_GENERATED_DIR})
+target_link_libraries(lorie wayland-server "-landroid" "-llog")
+
# Nothing special here, only generating xcb headers and building xcb...
####################################################################################################
@@ -73,6 +95,15 @@ target_include_directories(xcb PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libxcb/src/"
target_compile_options(xcb PRIVATE "-DXCB_QUEUE_BUFFER_SIZE=16384" "-DHAVE_SENDMSG")
target_link_libraries(xcb Xau)
+# Those are stubs and needed to check if termux-built xcb behaves the same way
+# All the functions they should contain are contained in libxcb itself
+add_library(xcb-shm SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
+add_library(xcb-xfixes SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
+add_library(xcb-xinput SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
+add_library(xcb-damage SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
+
+# TODO: strip unneded symbols to reduce shared library size...
+
####################################################################################################
####################################### LIBXCB-ERRORS ##############################################
####################################################################################################
@@ -106,13 +137,43 @@ add_library(xcvt "${CMAKE_CURRENT_SOURCE_DIR}/libxcvt/lib/libxcvt.c")
target_include_directories(xcvt PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libxcvt/include")
####################################################################################################
-########################################### LORIE ##################################################
+####################################### LIBXKB-COMMON ##############################################
####################################################################################################
-add_library(xcb-shm SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
-add_library(xcb-xfixes SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
-add_library(xcb-xinput SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
-add_library(xcb-damage SHARED ${CMAKE_CURRENT_SOURCE_DIR}/loading_sign.c)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.h "")
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.c
+ "#include
+ const struct xkb_keymap_format_ops text_v1_keymap_format_ops = {};")
+set(XKBCOMMON_SOURCES atom.c context.c context-priv.c keysym.c keysym-utf.c keymap.c keymap-priv.c
+ state.c text.c utf8.c utils.c x11/keymap.c x11/state.c x11/util.c)
+list(TRANSFORM XKBCOMMON_SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/libxkbcommon/src/)
+set(XKBCOMMON_SOURCES ${XKBCOMMON_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/config.c)
+add_library(xkbcommon ${XKBCOMMON_SOURCES})
+target_compile_options(xkbcommon PRIVATE
+ "-DHAVE_STRNDUP=1" "-DDEFAULT_XKB_LAYOUT=\"us\"" "-DDEFAULT_XKB_MODEL=\"pc105\""
+ "-DDEFAULT_XKB_OPTIONS=NULL" "-DDEFAULT_XKB_RULES=\"evdev\"" "-DDEFAULT_XKB_VARIANT=NULL"
+ "-DDFLT_XKB_CONFIG_EXTRA_PATH=\"/data/data/com.termux.x11\""
+ "-DDFLT_XKB_CONFIG_ROOT=\"/data/data/com.termux.x11\"")
+target_include_directories(xkbcommon PRIVATE "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/libxkbcommon/src")
+target_include_directories(xkbcommon PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libxkbcommon/include")
+target_link_libraries(xkbcommon xcbproto)
+
+####################################################################################################
+#################################### LIBANDROID-SUPPORT ############################################
+####################################################################################################
+
+set(ANDROID_SUPPORT_MUSL_CTYPE iswalnum.c iswalpha.c iswblank.c iswcntrl.c iswctype.c iswdigit.c
+ iswgraph.c iswlower.c iswprint.c iswpunct.c iswspace.c iswupper.c iswxdigit.c towctrans.c
+ wcswidth.c wctrans.c)
+set(ANDROID_SUPPORT_MUSL_MULTIBYTE internal.c mblen.c mbsnrtowcs.c mbsrtowcs.c)
+list(TRANSFORM ANDROID_SUPPORT_MUSL_CTYPE PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/libandroid-support/src/musl-ctype/)
+list(TRANSFORM ANDROID_SUPPORT_MUSL_MULTIBYTE PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/libandroid-support/src/musl-multibyte/)
+add_library(android-support STATIC ${ANDROID_SUPPORT_MUSL_CTYPE} ${ANDROID_SUPPORT_MUSL_MULTIBYTE})
+
+####################################################################################################
+####################################### LORIE-CLIENT ###############################################
+####################################################################################################
-add_library(lorie SHARED lorie/lorie.cpp lorie/lorie_message_queue.cpp)
-target_link_libraries(lorie xcbproto xcb xcb-errors xcb-shm xcb-xfixes xcb-xinput xcb-damage xcvt "-llog" "-landroid")
+add_library(lorie-client SHARED ${CMAKE_CURRENT_SOURCE_DIR}/lorie-client/lorie-client.cpp)
+target_link_libraries(lorie-client android-support xkbcommon xcbproto xcb xcb-errors xcb-shm
+ xcb-xfixes xcb-xinput xcb-damage xcvt "-llog" "-landroid")
diff --git a/app/src/main/cpp/libXau b/app/src/main/cpp/libXau
new file mode 160000
index 000000000..c52f54e95
--- /dev/null
+++ b/app/src/main/cpp/libXau
@@ -0,0 +1 @@
+Subproject commit c52f54e9533046a52edf84bcc02abedc2dbcb1a7
diff --git a/app/src/main/cpp/libandroid-support b/app/src/main/cpp/libandroid-support
new file mode 160000
index 000000000..2c033e0fb
--- /dev/null
+++ b/app/src/main/cpp/libandroid-support
@@ -0,0 +1 @@
+Subproject commit 2c033e0fb6004db5b7d2775ec5512ae3b201e54f
diff --git a/x11-client-experimental/src/main/cpp/libxcb b/app/src/main/cpp/libxcb
similarity index 100%
rename from x11-client-experimental/src/main/cpp/libxcb
rename to app/src/main/cpp/libxcb
diff --git a/x11-client-experimental/src/main/cpp/libxcb-errors b/app/src/main/cpp/libxcb-errors
similarity index 100%
rename from x11-client-experimental/src/main/cpp/libxcb-errors
rename to app/src/main/cpp/libxcb-errors
diff --git a/x11-client-experimental/src/main/cpp/libxcvt b/app/src/main/cpp/libxcvt
similarity index 100%
rename from x11-client-experimental/src/main/cpp/libxcvt
rename to app/src/main/cpp/libxcvt
diff --git a/app/src/main/cpp/libxkbcommon b/app/src/main/cpp/libxkbcommon
new file mode 160000
index 000000000..5b5ec0ee2
--- /dev/null
+++ b/app/src/main/cpp/libxkbcommon
@@ -0,0 +1 @@
+Subproject commit 5b5ec0ee2781fb540c60f7f554787cef1e2aaa87
diff --git a/app/src/main/cpp/loading_sign.c b/app/src/main/cpp/loading_sign.c
new file mode 100644
index 000000000..a89680216
--- /dev/null
+++ b/app/src/main/cpp/loading_sign.c
@@ -0,0 +1,5 @@
+//#include
+
+//static void __attribute__((__constructor__)) load() {
+// puts("libxcb is loaded from apk...\n");
+//}
diff --git a/app/src/main/cpp/lorie-client/android-keycodes-to-x11-keysyms.h b/app/src/main/cpp/lorie-client/android-keycodes-to-x11-keysyms.h
new file mode 100644
index 000000000..d2c81c2eb
--- /dev/null
+++ b/app/src/main/cpp/lorie-client/android-keycodes-to-x11-keysyms.h
@@ -0,0 +1,299 @@
+#define XK_MISCELLANY
+#define XK_LATIN1
+#include
+
+/*
+ * Indexes in this list match to keycode name in comment.
+ * Do not change order, only change values.
+ */
+int android_to_keysyms[] = {
+ /* ANDROID_KEYCODE_UNKNOWN */ 0,
+ /* ANDROID_KEYCODE_SOFT_LEFT */ 0,
+ /* ANDROID_KEYCODE_SOFT_RIGHT */ 0,
+ /* ANDROID_KEYCODE_HOME */ 0,
+ /* ANDROID_KEYCODE_BACK */ XK_Escape,
+ /* ANDROID_KEYCODE_CALL */ 0,
+ /* ANDROID_KEYCODE_ENDCALL */ 0,
+ /* ANDROID_KEYCODE_0 */ XK_0,
+ /* ANDROID_KEYCODE_1 */ XK_1,
+ /* ANDROID_KEYCODE_2 */ XK_2,
+ /* ANDROID_KEYCODE_3 */ XK_3,
+ /* ANDROID_KEYCODE_4 */ XK_4,
+ /* ANDROID_KEYCODE_5 */ XK_5,
+ /* ANDROID_KEYCODE_6 */ XK_6,
+ /* ANDROID_KEYCODE_7 */ XK_7,
+ /* ANDROID_KEYCODE_8 */ XK_8,
+ /* ANDROID_KEYCODE_9 */ XK_9,
+ /* ANDROID_KEYCODE_STAR */ XK_asterisk,
+ /* ANDROID_KEYCODE_POUND */ XK_numbersign,
+ /* ANDROID_KEYCODE_DPAD_UP */ XK_Up,
+ /* ANDROID_KEYCODE_DPAD_DOWN */ XK_Down,
+ /* ANDROID_KEYCODE_DPAD_LEFT */ XK_Left,
+ /* ANDROID_KEYCODE_DPAD_RIGHT */ XK_Right,
+ /* ANDROID_KEYCODE_DPAD_CENTER */ XK_Return,
+ /* ANDROID_KEYCODE_VOLUME_UP */ 0x1008FF13, // XF86XK_AudioRaiseVolume
+ /* ANDROID_KEYCODE_VOLUME_DOWN */ 0x1008FF11, // XF86XK_AudioLowerVolume
+ /* ANDROID_KEYCODE_POWER */ 0,
+ /* ANDROID_KEYCODE_CAMERA */ 0,
+ /* ANDROID_KEYCODE_CLEAR */ 0,
+ /* Latin keysyms from this map will be used
+ * only when there are modifiers with keycode */
+ /* ANDROID_KEYCODE_A */ XK_a,
+ /* ANDROID_KEYCODE_B */ XK_b,
+ /* ANDROID_KEYCODE_C */ XK_c,
+ /* ANDROID_KEYCODE_D */ XK_d,
+ /* ANDROID_KEYCODE_E */ XK_e,
+ /* ANDROID_KEYCODE_F */ XK_f,
+ /* ANDROID_KEYCODE_G */ XK_g,
+ /* ANDROID_KEYCODE_H */ XK_h,
+ /* ANDROID_KEYCODE_I */ XK_i,
+ /* ANDROID_KEYCODE_J */ XK_j,
+ /* ANDROID_KEYCODE_K */ XK_k,
+ /* ANDROID_KEYCODE_L */ XK_l,
+ /* ANDROID_KEYCODE_M */ XK_m,
+ /* ANDROID_KEYCODE_N */ XK_n,
+ /* ANDROID_KEYCODE_O */ XK_o,
+ /* ANDROID_KEYCODE_P */ XK_p,
+ /* ANDROID_KEYCODE_Q */ XK_q,
+ /* ANDROID_KEYCODE_R */ XK_r,
+ /* ANDROID_KEYCODE_S */ XK_s,
+ /* ANDROID_KEYCODE_T */ XK_t,
+ /* ANDROID_KEYCODE_U */ XK_u,
+ /* ANDROID_KEYCODE_V */ XK_v,
+ /* ANDROID_KEYCODE_W */ XK_w,
+ /* ANDROID_KEYCODE_X */ XK_x,
+ /* ANDROID_KEYCODE_Y */ XK_y,
+ /* ANDROID_KEYCODE_Z */ XK_z,
+ /* ANDROID_KEYCODE_COMMA */ XK_comma,
+ /* ANDROID_KEYCODE_PERIOD */ XK_period,
+ /* ANDROID_KEYCODE_ALT_LEFT */ XK_Alt_L,
+ /* ANDROID_KEYCODE_ALT_RIGHT */ XK_Alt_R,
+ /* ANDROID_KEYCODE_SHIFT_LEFT */ XK_Shift_L,
+ /* ANDROID_KEYCODE_SHIFT_RIGHT */ XK_Shift_R,
+ /* ANDROID_KEYCODE_TAB */ XK_Tab,
+ /* ANDROID_KEYCODE_SPACE */ XK_space,
+ /* ANDROID_KEYCODE_SYM */ 0,
+ /* ANDROID_KEYCODE_EXPLORER */ 0,
+ /* ANDROID_KEYCODE_ENVELOPE */ 0,
+ /* ANDROID_KEYCODE_ENTER */ XK_Return,
+ /* ANDROID_KEYCODE_DEL */ XK_BackSpace,
+ /* ANDROID_KEYCODE_GRAVE */ XK_grave,
+ /* ANDROID_KEYCODE_MINUS */ XK_minus,
+ /* ANDROID_KEYCODE_EQUALS */ XK_equal,
+ /* ANDROID_KEYCODE_LEFT_BRACKET */ XK_bracketleft,
+ /* ANDROID_KEYCODE_RIGHT_BRACKET */ XK_bracketright,
+ /* ANDROID_KEYCODE_BACKSLASH */ XK_backslash,
+ /* ANDROID_KEYCODE_SEMICOLON */ XK_semicolon,
+ /* ANDROID_KEYCODE_APOSTROPHE */ XK_apostrophe,
+ /* ANDROID_KEYCODE_SLASH */ XK_slash,
+ /* ANDROID_KEYCODE_AT */ 0,
+ /* ANDROID_KEYCODE_NUM */ 0,
+ /* ANDROID_KEYCODE_HEADSETHOOK */ 0,
+ /* ANDROID_KEYCODE_FOCUS */ 0,
+ /* ANDROID_KEYCODE_PLUS */ 0,
+ /* ANDROID_KEYCODE_MENU */ 0,
+ /* ANDROID_KEYCODE_NOTIFICATION */ 0,
+ /* ANDROID_KEYCODE_SEARCH */ 0,
+ /* ANDROID_KEYCODE_MEDIA_PLAY_PAUSE */ 0,
+ /* ANDROID_KEYCODE_MEDIA_STOP */ 0,
+ /* ANDROID_KEYCODE_MEDIA_NEXT */ 0,
+ /* ANDROID_KEYCODE_MEDIA_PREVIOUS */ 0,
+ /* ANDROID_KEYCODE_MEDIA_REWIND */ 0,
+ /* ANDROID_KEYCODE_MEDIA_FAST_FORWARD */ 0,
+ /* ANDROID_KEYCODE_MUTE */ 0,
+ /* ANDROID_KEYCODE_PAGE_UP */ XK_Page_Up,
+ /* ANDROID_KEYCODE_PAGE_DOWN */ XK_Page_Down,
+ /* ANDROID_KEYCODE_PICTSYMBOLS */ 0,
+ /* ANDROID_KEYCODE_SWITCH_CHARSET */ 0,
+ /* ANDROID_KEYCODE_BUTTON_A */ 0,
+ /* ANDROID_KEYCODE_BUTTON_B */ 0,
+ /* ANDROID_KEYCODE_BUTTON_C */ 0,
+ /* ANDROID_KEYCODE_BUTTON_X */ 0,
+ /* ANDROID_KEYCODE_BUTTON_Y */ 0,
+ /* ANDROID_KEYCODE_BUTTON_Z */ 0,
+ /* ANDROID_KEYCODE_BUTTON_L1 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_R1 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_L2 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_R2 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_THUMBL */ 0,
+ /* ANDROID_KEYCODE_BUTTON_THUMBR */ 0,
+ /* ANDROID_KEYCODE_BUTTON_START */ 0,
+ /* ANDROID_KEYCODE_BUTTON_SELECT */ 0,
+ /* ANDROID_KEYCODE_BUTTON_MODE */ 0,
+ /* ANDROID_KEYCODE_ESCAPE */ XK_Escape,
+ /* ANDROID_KEYCODE_FORWARD_DEL */ XK_Delete,
+ /* ANDROID_KEYCODE_CTRL_LEFT */ XK_Control_L,
+ /* ANDROID_KEYCODE_CTRL_RIGHT */ XK_Control_R,
+ /* ANDROID_KEYCODE_CAPS_LOCK */ XK_Caps_Lock,
+ /* ANDROID_KEYCODE_SCROLL_LOCK */ XK_Scroll_Lock,
+ /* ANDROID_KEYCODE_META_LEFT */ XK_Super_L,
+ /* ANDROID_KEYCODE_META_RIGHT */ XK_Super_R,
+ /* ANDROID_KEYCODE_FUNCTION */ 0,
+ /* ANDROID_KEYCODE_SYSRQ */ XK_Print,
+ /* ANDROID_KEYCODE_BREAK */ XK_Break,
+ /* ANDROID_KEYCODE_MOVE_HOME */ XK_Home,
+ /* ANDROID_KEYCODE_MOVE_END */ XK_End,
+ /* ANDROID_KEYCODE_INSERT */ XK_Insert,
+ /* ANDROID_KEYCODE_FORWARD */ 0,
+ /* ANDROID_KEYCODE_MEDIA_PLAY */ 0,
+ /* ANDROID_KEYCODE_MEDIA_PAUSE */ 0,
+ /* ANDROID_KEYCODE_MEDIA_CLOSE */ 0,
+ /* ANDROID_KEYCODE_MEDIA_EJECT */ 0,
+ /* ANDROID_KEYCODE_MEDIA_RECORD */ 0,
+ /* ANDROID_KEYCODE_F1 */ XK_F1,
+ /* ANDROID_KEYCODE_F2 */ XK_F2,
+ /* ANDROID_KEYCODE_F3 */ XK_F3,
+ /* ANDROID_KEYCODE_F4 */ XK_F4,
+ /* ANDROID_KEYCODE_F5 */ XK_F5,
+ /* ANDROID_KEYCODE_F6 */ XK_F6,
+ /* ANDROID_KEYCODE_F7 */ XK_F7,
+ /* ANDROID_KEYCODE_F8 */ XK_F8,
+ /* ANDROID_KEYCODE_F9 */ XK_F9,
+ /* ANDROID_KEYCODE_F10 */ XK_F10,
+ /* ANDROID_KEYCODE_F11 */ XK_F11,
+ /* ANDROID_KEYCODE_F12 */ XK_F12,
+ /* ANDROID_KEYCODE_NUM_LOCK */ XK_Num_Lock,
+ /* ANDROID_KEYCODE_NUMPAD_0 */ XK_KP_0,
+ /* ANDROID_KEYCODE_NUMPAD_1 */ XK_KP_1,
+ /* ANDROID_KEYCODE_NUMPAD_2 */ XK_KP_2,
+ /* ANDROID_KEYCODE_NUMPAD_3 */ XK_KP_3,
+ /* ANDROID_KEYCODE_NUMPAD_4 */ XK_KP_4,
+ /* ANDROID_KEYCODE_NUMPAD_5 */ XK_KP_5,
+ /* ANDROID_KEYCODE_NUMPAD_6 */ XK_KP_6,
+ /* ANDROID_KEYCODE_NUMPAD_7 */ XK_KP_7,
+ /* ANDROID_KEYCODE_NUMPAD_8 */ XK_KP_8,
+ /* ANDROID_KEYCODE_NUMPAD_9 */ XK_KP_9,
+ /* ANDROID_KEYCODE_NUMPAD_DIVIDE */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_MULTIPLY */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_SUBTRACT */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_ADD */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_DOT */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_COMMA */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_ENTER */ XK_Return,
+ /* ANDROID_KEYCODE_NUMPAD_EQUALS */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_LEFT_PAREN */ 0,
+ /* ANDROID_KEYCODE_NUMPAD_RIGHT_PAREN */ 0,
+ /* ANDROID_KEYCODE_VOLUME_MUTE */ 0,
+ /* ANDROID_KEYCODE_INFO */ 0,
+ /* ANDROID_KEYCODE_CHANNEL_UP */ 0,
+ /* ANDROID_KEYCODE_CHANNEL_DOWN */ 0,
+ /* ANDROID_KEYCODE_ZOOM_IN */ 0,
+ /* ANDROID_KEYCODE_ZOOM_OUT */ 0,
+ /* ANDROID_KEYCODE_TV */ 0,
+ /* ANDROID_KEYCODE_WINDOW */ 0,
+ /* ANDROID_KEYCODE_GUIDE */ 0,
+ /* ANDROID_KEYCODE_DVR */ 0,
+ /* ANDROID_KEYCODE_BOOKMARK */ 0,
+ /* ANDROID_KEYCODE_CAPTIONS */ 0,
+ /* ANDROID_KEYCODE_SETTINGS */ 0,
+ /* ANDROID_KEYCODE_TV_POWER */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT */ 0,
+ /* ANDROID_KEYCODE_STB_POWER */ 0,
+ /* ANDROID_KEYCODE_STB_INPUT */ 0,
+ /* ANDROID_KEYCODE_AVR_POWER */ 0,
+ /* ANDROID_KEYCODE_AVR_INPUT */ 0,
+ /* ANDROID_KEYCODE_PROG_RED */ 0,
+ /* ANDROID_KEYCODE_PROG_GREEN */ 0,
+ /* ANDROID_KEYCODE_PROG_YELLOW */ 0,
+ /* ANDROID_KEYCODE_PROG_BLUE */ 0,
+ /* ANDROID_KEYCODE_APP_SWITCH */ 0,
+ /* ANDROID_KEYCODE_BUTTON_1 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_2 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_3 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_4 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_5 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_6 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_7 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_8 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_9 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_10 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_11 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_12 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_13 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_14 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_15 */ 0,
+ /* ANDROID_KEYCODE_BUTTON_16 */ 0,
+ /* ANDROID_KEYCODE_LANGUAGE_SWITCH */ 0,
+ /* ANDROID_KEYCODE_MANNER_MODE */ 0,
+ /* ANDROID_KEYCODE_3D_MODE */ 0,
+ /* ANDROID_KEYCODE_CONTACTS */ 0,
+ /* ANDROID_KEYCODE_CALENDAR */ 0,
+ /* ANDROID_KEYCODE_MUSIC */ 0,
+ /* ANDROID_KEYCODE_CALCULATOR */ 0,
+ /* ANDROID_KEYCODE_ZENKAKU_HANKAKU */ 0,
+ /* ANDROID_KEYCODE_EISU */ 0,
+ /* ANDROID_KEYCODE_MUHENKAN */ 0,
+ /* ANDROID_KEYCODE_HENKAN */ 0,
+ /* ANDROID_KEYCODE_KATAKANA_HIRAGANA */ 0,
+ /* ANDROID_KEYCODE_YEN */ 0,
+ /* ANDROID_KEYCODE_RO */ 0,
+ /* ANDROID_KEYCODE_KANA */ 0,
+ /* ANDROID_KEYCODE_ASSIST */ 0,
+ /* ANDROID_KEYCODE_BRIGHTNESS_DOWN */ 0,
+ /* ANDROID_KEYCODE_BRIGHTNESS_UP */ 0,
+ /* ANDROID_KEYCODE_MEDIA_AUDIO_TRACK */ 0,
+ /* ANDROID_KEYCODE_SLEEP */ 0,
+ /* ANDROID_KEYCODE_WAKEUP */ 0,
+ /* ANDROID_KEYCODE_PAIRING */ 0,
+ /* ANDROID_KEYCODE_MEDIA_TOP_MENU */ 0,
+ /* ANDROID_KEYCODE_11 */ 0,
+ /* ANDROID_KEYCODE_12 */ 0,
+ /* ANDROID_KEYCODE_LAST_CHANNEL */ 0,
+ /* ANDROID_KEYCODE_TV_DATA_SERVICE */ 0,
+ /* ANDROID_KEYCODE_VOICE_ASSIST */ 0,
+ /* ANDROID_KEYCODE_TV_RADIO_SERVICE */ 0,
+ /* ANDROID_KEYCODE_TV_TELETEXT */ 0,
+ /* ANDROID_KEYCODE_TV_NUMBER_ENTRY */ 0,
+ /* ANDROID_KEYCODE_TV_TERRESTRIAL_ANALOG */ 0,
+ /* ANDROID_KEYCODE_TV_TERRESTRIAL_DIGITAL */ 0,
+ /* ANDROID_KEYCODE_TV_SATELLITE */ 0,
+ /* ANDROID_KEYCODE_TV_SATELLITE_BS */ 0,
+ /* ANDROID_KEYCODE_TV_SATELLITE_CS */ 0,
+ /* ANDROID_KEYCODE_TV_SATELLITE_SERVICE */ 0,
+ /* ANDROID_KEYCODE_TV_NETWORK */ 0,
+ /* ANDROID_KEYCODE_TV_ANTENNA_CABLE */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_HDMI_1 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_HDMI_2 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_HDMI_3 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_HDMI_4 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_COMPOSITE_1 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_COMPOSITE_2 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_COMPONENT_1 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_COMPONENT_2 */ 0,
+ /* ANDROID_KEYCODE_TV_INPUT_VGA_1 */ 0,
+ /* ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION */ 0,
+ /* ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP */ 0,
+ /* ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN */ 0,
+ /* ANDROID_KEYCODE_TV_ZOOM_MODE */ 0,
+ /* ANDROID_KEYCODE_TV_CONTENTS_MENU */ 0,
+ /* ANDROID_KEYCODE_TV_MEDIA_CONTEXT_MENU */ 0,
+ /* ANDROID_KEYCODE_TV_TIMER_PROGRAMMING */ 0,
+ /* ANDROID_KEYCODE_HELP */ 0,
+ /* ANDROID_KEYCODE_NAVIGATE_PREVIOUS */ 0,
+ /* ANDROID_KEYCODE_NAVIGATE_NEXT */ 0,
+ /* ANDROID_KEYCODE_NAVIGATE_IN */ 0,
+ /* ANDROID_KEYCODE_NAVIGATE_OUT */ 0,
+ /* ANDROID_KEYCODE_STEM_PRIMARY */ 0,
+ /* ANDROID_KEYCODE_STEM_1 */ 0,
+ /* ANDROID_KEYCODE_STEM_2 */ 0,
+ /* ANDROID_KEYCODE_STEM_3 */ 0,
+ /* ANDROID_KEYCODE_DPAD_UP_LEFT */ 0,
+ /* ANDROID_KEYCODE_DPAD_DOWN_LEFT */ 0,
+ /* ANDROID_KEYCODE_DPAD_UP_RIGHT */ 0,
+ /* ANDROID_KEYCODE_DPAD_DOWN_RIGHT */ 0,
+ /* ANDROID_KEYCODE_MEDIA_SKIP_FORWARD */ 0,
+ /* ANDROID_KEYCODE_MEDIA_SKIP_BACKWARD */ 0,
+ /* ANDROID_KEYCODE_MEDIA_STEP_FORWARD */ 0,
+ /* ANDROID_KEYCODE_MEDIA_STEP_BACKWARD */ 0,
+ /* ANDROID_KEYCODE_SOFT_SLEEP */ 0,
+ /* ANDROID_KEYCODE_CUT */ 0,
+ /* ANDROID_KEYCODE_COPY */ 0,
+ /* ANDROID_KEYCODE_PASTE */ 0,
+ /* ANDROID_KEYCODE_SYSTEM_NAVIGATION_UP */ 0,
+ /* ANDROID_KEYCODE_SYSTEM_NAVIGATION_DOWN */ 0,
+ /* ANDROID_KEYCODE_SYSTEM_NAVIGATION_LEFT */ 0,
+ /* ANDROID_KEYCODE_SYSTEM_NAVIGATION_RIGHT */ 0,
+ /* ANDROID_KEYCODE_ALL_APPS */ 0,
+ /* ANDROID_KEYCODE_REFRESH */ 0
+ /* ANDROID_KEYCODE_LAST */
+};
diff --git a/app/src/main/cpp/lorie-client/lorie-client.cpp b/app/src/main/cpp/lorie-client/lorie-client.cpp
new file mode 100644
index 000000000..2ba53e9ee
--- /dev/null
+++ b/app/src/main/cpp/lorie-client/lorie-client.cpp
@@ -0,0 +1,630 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if 1
+#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "LorieX11Client", fmt, ## __VA_ARGS__)
+#define ALOGV(fmt, ...) __android_log_print(ANDROID_LOG_VERBOSE, "LorieX11Client", fmt, ## __VA_ARGS__)
+#else
+#define ALOGE(fmt, ...) printf(fmt, ## __VA_ARGS__); printf("\n")
+#endif
+
+#define always_inline inline __attribute__((__always_inline__))
+
+#include "lorie_message_queue.hpp"
+#include "xcb-connection.hpp"
+#include "android-keycodes-to-x11-keysyms.h"
+
+
+// To avoid reopening new segment on every screen resolution
+// change we can open it only once with some maximal size
+#define DEFAULT_SHMSEG_LENGTH 8192*8192*4
+
+#pragma ide diagnostic ignored "ConstantParameter"
+#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions"
+
+static inline int
+os_create_anonymous_file(size_t size) {
+ int fd, ret;
+ long flags;
+ fd = open("/dev/ashmem", O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+ ret = ioctl(fd, /** ASHMEM_SET_SIZE */ _IOW(0x77, 3, size_t), size);
+ if (ret < 0)
+ goto err;
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ goto err;
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ goto err;
+ return fd;
+ err:
+ close(fd);
+ return ret;
+}
+
+// For some reason both static_cast and reinterpret_cast returning 0 when casting b.bits.
+static always_inline uint32_t* cast(void* p) { union { void* a; uint32_t* b; } c {p}; return c.b; } // NOLINT(cppcoreguidelines-pro-type-member-init)
+
+static always_inline void blit_exact(ANativeWindow* win, const uint32_t* src, int width, int height) {
+ if (!win)
+ return;
+
+ if (width == 0 || height == 0) {
+ width = ANativeWindow_getWidth(win);
+ height = ANativeWindow_getHeight(win);
+ }
+
+ ARect bounds{ 0, 0, width, height };
+ ANativeWindow_Buffer b{};
+
+ ANativeWindow_acquire(win);
+ auto ret = ANativeWindow_setBuffersGeometry(win, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+ if (ret != 0) {
+ ALOGE("Failed to set buffers geometry (%d)", ret);
+ return;
+ }
+
+ ret = ANativeWindow_lock(win, &b, &bounds);
+ if (ret != 0) {
+ ALOGE("Failed to lock");
+ return;
+ }
+
+ uint32_t* dst = cast(b.bits);
+ if (src) {
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ uint32_t s = src[width * i + j];
+ // Cast BGRA to RGBA
+ dst[b.stride * i + j] = (s & 0xFF000000) | ((s & 0x00FF0000) >> 16) | (s & 0x0000FF00) | ((s & 0x000000FF) << 16);
+ }
+ }
+ } else
+ memset(dst, 0, b.stride*b.height);
+
+ ret = ANativeWindow_unlockAndPost(win);
+ if (ret != 0) {
+ ALOGE("Failed to post");
+ return;
+ }
+
+ ANativeWindow_release(win);
+}
+
+class lorie_client {
+public:
+ lorie_looper looper;
+ std::thread runner_thread;
+ bool terminate = false;
+ bool paused = false;
+
+ xcb_connection c;
+
+ struct {
+ ANativeWindow* win;
+ u32 width, height;
+
+ i32 shmfd;
+ xcb_shm_seg_t shmseg;
+ u32 *shmaddr;
+ } screen {};
+ struct {
+ ANativeWindow* win;
+ u32 width, height, x, y, xhot, yhot;
+ } cursor{};
+
+
+ lorie_client() {
+ runner_thread = std::thread([=, this] {
+ while(!terminate) {
+ looper.dispatch(1000);
+ }
+ });
+ }
+
+ void post(std::function task) {
+ looper.post(std::move(task));
+ }
+
+ [[maybe_unused]]
+ void post_delayed(std::function task, long ms_delay) {
+ looper.post(std::move(task), ms_delay);
+ }
+
+ void surface_changed(ANativeWindow* win, u32 width, u32 height) {
+ ALOGE("Surface: changing surface %p to %p", screen.win, win);
+ if (screen.win)
+ ANativeWindow_release(screen.win);
+
+ if (win)
+ ANativeWindow_acquire(win);
+ screen.win = win;
+ screen.width = width;
+ screen.height = height;
+
+ refresh_screen();
+ }
+
+ void cursor_changed(ANativeWindow* win) {
+ if (cursor.win)
+ ANativeWindow_release(cursor.win);
+
+ if (win)
+ ANativeWindow_acquire(win);
+ cursor.win = win;
+
+ refresh_cursor();
+ }
+
+ void attach_region() {
+ if (screen.shmaddr)
+ munmap(screen.shmaddr, DEFAULT_SHMSEG_LENGTH);
+ if (screen.shmfd)
+ close(screen.shmfd);
+
+ ALOGE("Creating ashmem file...");
+ screen.shmfd = os_create_anonymous_file(DEFAULT_SHMSEG_LENGTH);
+ if (screen.shmfd < 0) {
+ ALOGE("Error opening file: %s", strerror(errno));
+ } else {
+ fchmod(screen.shmfd, 0777);
+ ALOGE("Attaching file...");
+ screen.shmaddr = static_cast(mmap(nullptr, DEFAULT_SHMSEG_LENGTH,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, screen.shmfd, 0));
+ if (screen.shmaddr == MAP_FAILED) {
+ ALOGE("Map failed: %s", strerror(errno));
+ }
+ }
+ try {
+ c.shm.attach_fd(screen.shmseg, screen.shmfd, 0);
+ return;
+ } catch (std::runtime_error &e) {
+ ALOGE("%s", e.what());
+ if (screen.shmaddr && screen.shmaddr != MAP_FAILED)
+ munmap(screen.shmaddr, DEFAULT_SHMSEG_LENGTH);
+ if (screen.shmfd != -1)
+ close(screen.shmfd);
+
+ ALOGE("Trying to retrieve shared segment...");
+ }
+
+ // There is a chance that Xwayland we are trying to connect is non-termux, try another way
+ screen.shmfd = c.shm.create_segment(screen.shmseg, DEFAULT_SHMSEG_LENGTH, 0);
+ if (screen.shmfd < 0) {
+ ALOGE("Failed to retrieve shared segment file descriptor...");
+ return;
+ } else {
+ struct statfs info{};
+ fstatfs(screen.shmfd, &info);
+ if (info.f_type != TMPFS_MAGIC) {
+ ALOGE("Shared segment is not hosted on tmpfs. You are likely doing something wrong. "
+ "Check if /run/shm, /var/tmp and /tmp are tmpfs.");
+ close(screen.shmfd);
+ screen.shmfd = -1;
+ } else {
+ ALOGE("Attaching shared memory segment...");
+ screen.shmaddr = static_cast(mmap(nullptr, DEFAULT_SHMSEG_LENGTH,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, screen.shmfd, 0));
+ if (screen.shmaddr == MAP_FAILED) {
+ ALOGE("Map failed: %s", strerror(errno));
+ }
+ }
+ }
+ }
+
+ void adopt_connection_fd(int fd) {
+ try {
+ static int old_fd = -1;
+ if (old_fd != -1)
+ looper.remove_fd(old_fd);
+
+ ALOGE("Connecting to fd %d", fd);
+ c.init(fd);
+ xcb_screen_t *scr = xcb_setup_roots_iterator(xcb_get_setup(c.conn)).data;
+
+ xcb_change_window_attributes(c.conn, scr->root, XCB_CW_EVENT_MASK,
+ (const int[]) {XCB_EVENT_MASK_STRUCTURE_NOTIFY});
+ c.fixes.select_input(scr->root, XCB_XFIXES_CURSOR_NOTIFY_MASK_DISPLAY_CURSOR);
+ c.damage.create(scr->root, XCB_DAMAGE_REPORT_LEVEL_RAW_RECTANGLES);
+ struct {
+ xcb_input_event_mask_t head;
+ xcb_input_xi_event_mask_t mask;
+ } mask{};
+ mask.head.deviceid = c.input.client_pointer_id();
+ mask.head.mask_len = sizeof(mask.mask) / sizeof(uint32_t);
+ mask.mask = XCB_INPUT_XI_EVENT_MASK_RAW_MOTION;
+ c.input.select_events(scr->root, 1, &mask.head);
+
+ screen.shmseg = xcb_generate_id(c.conn);
+
+ attach_region();
+ refresh_cursor();
+
+
+ ALOGE("Adding connection with fd %d to poller", fd);
+ u32 events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLET | EPOLLHUP | EPOLLNVAL | EPOLLMSG;
+ looper.add_fd(fd, events, [&] (u32 mask) {
+ if (mask & (EPOLLNVAL | EPOLLHUP | EPOLLERR)) {
+ looper.remove_fd(old_fd);
+ old_fd = -1;
+ xcb_disconnect(c.conn);
+ c.conn = nullptr;
+ set_renderer_visibility(false);
+ ALOGE("Disconnected");
+ return;
+ }
+
+ connection_poll_func();
+ });
+ old_fd = fd;
+
+ set_renderer_visibility(true);
+ refresh_screen();
+ } catch (std::exception& e) {
+ ALOGE("Failed to adopt X connection socket: %s", e.what());
+ }
+ }
+
+ void refresh_cursor() {
+ if (cursor.win && c.conn) {
+ auto reply = c.fixes.get_cursor_image();
+ if (reply) {
+ env->CallVoidMethod(thiz,
+ set_cursor_rect_id,
+ cursor.x - cursor.xhot,
+ cursor.y - cursor.yhot,
+ cursor.width,
+ cursor.height);
+ cursor.width = reply->width;
+ cursor.height = reply->height;
+ cursor.xhot = reply->xhot;
+ cursor.yhot = reply->yhot;
+ u32* image = xcb_xfixes_get_cursor_image_cursor_image(reply);
+ env->CallVoidMethod(thiz,
+ set_cursor_rect_id,
+ cursor.x - cursor.xhot,
+ cursor.y - cursor.yhot,
+ cursor.width,
+ cursor.height);
+ blit_exact(cursor.win, image, reply->width, reply->height);
+ }
+ free(reply);
+ }
+ }
+
+ void refresh_screen() {
+ if (screen.win && c.conn && !paused) {
+ try {
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c.conn)).data;
+ c.shm.get(s->root, 0, 0, s->width_in_pixels, s->height_in_pixels,
+ ~0, // NOLINT(cppcoreguidelines-narrowing-conversions)
+ XCB_IMAGE_FORMAT_Z_PIXMAP, screen.shmseg, 0);
+ blit_exact(screen.win, screen.shmaddr, s->width_in_pixels,
+ s->height_in_pixels);
+ } catch (std::runtime_error &err) {
+ ALOGE("Refreshing screen failed: %s", err.what());
+ }
+ }
+ }
+
+ void send_keysym(xcb_keysym_t keysym, int meta_state) {
+ if (c.conn)
+ post([=] {
+ c.xkb.send_keysym(keysym, meta_state);
+ });
+ }
+
+ void send_key(xcb_keysym_t keysym, u8 type) {
+ if (c.conn)
+ post([=] {
+ c.xkb.send_key(keysym, type);
+ });
+ }
+
+ void connection_poll_func() {
+ try {
+ bool need_redraw = false;
+ xcb_generic_event_t *event;
+ // const char *ext;
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c.conn)).data;
+ while ((event = xcb_poll_for_event(c.conn))) {
+ if (event->response_type == 0) {
+ c.err = reinterpret_cast(event);
+ c.handle_error("Error processing XCB events");
+ } else if (event->response_type == XCB_MAPPING_NOTIFY) {
+ c.xkb.reload_keymaps();
+ } else if (event->response_type == XCB_CONFIGURE_NOTIFY) {
+ auto e = reinterpret_cast(event);
+ s->width_in_pixels = e->width;
+ s->height_in_pixels = e->height;
+ } else if (c.damage.is_damage_notify_event(event)) {
+ need_redraw = true;
+ } else if (c.fixes.is_cursor_notify_event(event)) {
+ refresh_cursor();
+ }
+ }
+
+ if (need_redraw)
+ refresh_screen();
+ } catch (std::exception& e) {
+ ALOGE("Failure during processing X events: %s", e.what());
+ }
+ }
+
+ ~lorie_client() {
+ looper.post([=, this] { terminate = true; });
+ if (runner_thread.joinable())
+ runner_thread.join();
+ }
+
+ JNIEnv* env{};
+ jobject thiz{};
+ jmethodID set_renderer_visibility_id{};
+ jmethodID set_cursor_rect_id{};
+ void init_jni(JavaVM* vm, jobject obj) {
+ post([=, this] {
+ thiz = obj;
+ vm->AttachCurrentThread(&env, nullptr);
+ set_renderer_visibility_id =
+ env->GetMethodID(env->GetObjectClass(thiz),"setRendererVisibility","(Z)V");
+ set_cursor_rect_id =
+ env->GetMethodID(env->GetObjectClass(thiz),"setCursorRect","(IIII)V");
+ });
+ }
+
+ void set_renderer_visibility(bool visible) const {
+ if (!set_renderer_visibility_id) {
+ ALOGE("Something is wrong, `set_renderer_visibility` is null");
+ return;
+ }
+
+ env->CallVoidMethod(thiz, set_renderer_visibility_id, visible);
+ }
+} client; // NOLINT(cert-err58-cpp)
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_init(JNIEnv *env, jobject thiz) {
+ // Of course I could do that from JNI_OnLoad, but anyway I need to register `thiz` as class instance;
+ JavaVM *vm;
+ env->GetJavaVM(&vm);
+ client.init_jni(vm, env->NewGlobalRef(thiz));
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_connect([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz, jint fd) {
+ client.post([fd] { client.adopt_connection_fd(fd); });
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_cursorChanged(JNIEnv *env, [[maybe_unused]] jobject thiz, jobject sfc) {
+ ANativeWindow *win = sfc ? ANativeWindow_fromSurface(env, sfc) : nullptr;
+ if (win)
+ ANativeWindow_acquire(win);
+
+ ALOGE("Cursor: got new surface %p", win);
+ client.post([=] { client.cursor_changed(win); });
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_windowChanged(JNIEnv *env, [[maybe_unused]] jobject thiz, jobject sfc,
+ jint width, jint height) {
+ ANativeWindow *win = sfc ? ANativeWindow_fromSurface(env, sfc) : nullptr;
+ if (win)
+ ANativeWindow_acquire(win);
+
+ ALOGE("Surface: got new surface %p", win);
+ client.post([=] { client.surface_changed(win, width, height); });
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_onPointerMotion(JNIEnv *env, jobject thiz, jint x, jint y) {
+ env->CallVoidMethod(thiz,
+ client.set_cursor_rect_id,
+ x - client.cursor.xhot,
+ y - client.cursor.yhot,
+ client.cursor.width,
+ client.cursor.height);
+
+ client.cursor.x = x;
+ client.cursor.y = y;
+
+ if (client.c.conn) {
+ // XCB is thread safe, no need to post this to dispatch thread.
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(client.c.conn)).data;
+ xcb_test_fake_input(client.c.conn, XCB_MOTION_NOTIFY, false, XCB_CURRENT_TIME, s->root, x,y, 0);
+ xcb_flush(client.c.conn);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_onPointerScroll([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz,
+ [[maybe_unused]] jint axis, [[maybe_unused]] jfloat value) {
+ // TODO: implement onPointerScroll()
+ if (client.c.conn) {
+ bool press_shift = axis == 1; // AXIS_X
+ int button = value < 0 ? XCB_BUTTON_INDEX_4 : XCB_BUTTON_INDEX_5;
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(client.c.conn)).data;
+ if (press_shift)
+ client.send_key(XK_Shift_L, XCB_KEY_PRESS);
+ client.post([=] {
+ xcb_test_fake_input(client.c.conn, XCB_BUTTON_PRESS, button, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ xcb_test_fake_input(client.c.conn, XCB_BUTTON_RELEASE, button, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ });
+ if (press_shift)
+ client.send_key(XK_Shift_L, XCB_KEY_RELEASE);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_onPointerButton([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz, jint button,
+ jint type) {
+ if (client.c.conn) {
+ // XCB is thread safe, no need to post this to dispatch thread.
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(client.c.conn)).data;
+ xcb_test_fake_input(client.c.conn, type, button, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ xcb_flush(client.c.conn);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_onKeySym([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz,
+ jint keycode, jint unicodeChar, jstring str, jint meta_state, jint type) {
+ wchar_t unicode = unicodeChar;
+ mbstate_t ps {};
+
+ /* When event is triggered by software keyboard type is always 0 */
+ if (type) {
+ client.send_key(android_to_keysyms[keycode], type);
+ return;
+ }
+
+ if (unicode && !meta_state) {
+ client.send_keysym(xkb_utf32_to_keysym(unicode), meta_state);
+ return;
+ }
+
+ if (android_to_keysyms[keycode]) {
+ client.send_keysym(android_to_keysyms[keycode], meta_state);
+ return;
+ }
+
+ if (str) {
+ const char *characters = env->GetStringUTFChars(str, nullptr);
+ const char *chars = characters; // mbsrtowcs will set it to nullptr, but we still need to release it
+ if (!chars)
+ return;
+
+ while (mbsrtowcs(&unicode, &chars, 1, &ps) > 0)
+ client.send_keysym(xkb_utf32_to_keysym(unicode), meta_state);
+
+ env->ReleaseStringUTFChars(str, characters);
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_nativeResume([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz) {
+ client.post([] {
+ client.paused = false;
+ client.refresh_screen();
+ });
+}
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_nativePause([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz) {
+ client.paused = true;
+}
+
+// I need this to catch initialisation errors of libxkbcommon.
+#if 1
+// It is needed to redirect stderr to logcat
+[[maybe_unused]] std::thread stderr_to_logcat_thread([]{ // NOLINT(cert-err58-cpp)
+ FILE *fp;
+ int p[2];
+ size_t len;
+ char* line = nullptr;
+ pipe(p);
+ fp = fdopen(p[0], "r");
+
+ dup2(p[1], 2);
+ while ((getline(&line, &len, fp)) != -1) {
+ __android_log_write(ANDROID_LOG_VERBOSE, "stderr", line);
+ }
+});
+#endif
+
+static bool sameUid(int pid) {
+ char path[32] = {0};
+ struct stat s = {0};
+ sprintf(path, "/proc/%d", pid);
+ stat(path, &s);
+ return s.st_uid == getuid();
+}
+
+static void killAllLogcats() {
+ DIR* proc;
+ struct dirent* dir_elem;
+ char path[64] = {0}, link[64] = {0};
+ pid_t pid, self = getpid();
+ if ((proc = opendir("/proc")) == nullptr) {
+ ALOGE("opendir: %s", strerror(errno));
+ return;
+ }
+
+ while((dir_elem = readdir(proc)) != nullptr) {
+ if (!(pid = (pid_t) atoi (dir_elem->d_name)) || pid == self || !sameUid(pid)) // NOLINT(cert-err34-c)
+ continue;
+
+ memset(path, 0, sizeof(path));
+ memset(link, 0, sizeof(link));
+ sprintf(path, "/proc/%d/exe", pid);
+ if (readlink(path, link, sizeof(link)) < 0) {
+ ALOGE("readlink %s: %s", path, strerror(errno));
+ continue;
+ }
+ if (strstr(link, "/logcat") != nullptr) {
+ if (kill(pid, SIGKILL) < 0) {
+ ALOGE("kill %d (%s): %s", pid, link, strerror(errno));
+ }
+ }
+ }
+}
+
+void fork(const std::function& f) {
+ switch(fork()) {
+ case -1: ALOGE("fork: %s", strerror(errno)); return;
+ case 0: f(); return;
+ default: return;
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_MainActivity_startLogcat([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject thiz, jint fd) {
+ killAllLogcats();
+
+ ALOGV("Starting logcat with output to given fd");
+ fork([]() {
+ execl("/system/bin/logcat", "logcat", "-c", nullptr);
+ ALOGE("exec logcat: %s", strerror(errno));
+ });
+
+ fork([fd]() {
+ dup2(fd, 1);
+ dup2(fd, 2);
+ execl("/system/bin/logcat", "logcat", nullptr);
+ ALOGE("exec logcat: %s", strerror(errno));
+ });
+}
\ No newline at end of file
diff --git a/app/src/main/cpp/lorie-client/lorie_message_queue.hpp b/app/src/main/cpp/lorie-client/lorie_message_queue.hpp
new file mode 100644
index 000000000..3eb65b933
--- /dev/null
+++ b/app/src/main/cpp/lorie-client/lorie_message_queue.hpp
@@ -0,0 +1,202 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static always_inline timespec operator+(const timespec& lhs, const timespec& rhs);
+static always_inline timespec operator-(const timespec& lhs, const timespec& rhs);
+static always_inline bool operator<(const timespec& lhs, const timespec& rhs);
+static always_inline timespec now();
+static always_inline timespec ms_to_timespec(long ms);
+[[maybe_unused]] static always_inline long timespec_to_ms(timespec& spec);
+[[maybe_unused]] static always_inline void timespec_to_human_readable(const timespec& ts, const char* comment);
+
+class lorie_looper {
+public:
+ lorie_looper() {
+ efd = epoll_create1(0);
+ if (efd < 0) {
+ ALOGE("Failed to create epoll: %s", strerror(errno));
+ return;
+ }
+
+ evfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+ if (evfd < 0) {
+ ALOGE("Failed to create eventfd: %s", strerror(errno));
+ return;
+ }
+
+ timer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+ if (timer < 0) {
+ ALOGE("Failed to create timerfd: %s", strerror(errno));
+ return;
+ }
+
+ add_fd(evfd, EPOLLIN, [=, this] (uint32_t) { dispatch_queue(); });
+ add_fd(timer, EPOLLIN, [=, this] (uint32_t) { dispatch_delayed_queue(); });
+ }
+
+ ~lorie_looper() {
+ close(efd);
+ close(timer);
+ close(evfd);
+ }
+
+ void post(std::function func, long ms_delay = 0) {
+ std::unique_lock lock(mutex);
+ if (ms_delay <= 0) {
+ queue.push(std::move(func));
+ ::write(evfd, (const uint64_t[]) {1}, sizeof(uint64_t));
+ } else {
+ delayed_queue.emplace(task_t{ now() + ms_to_timespec(ms_delay), std::move(func) });
+ reset_timer();
+ }
+ };
+
+ void add_fd(int fd, uint32_t mask, std::function callback) {
+ struct epoll_event event { .events=mask, .data ={ .fd=fd } };
+ event.data.fd = fd;
+ event.events = mask;
+ {
+ std::lock_guard lock(mutex);
+ callbacks[fd] = std::move(callback);
+ epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event);
+ }
+ }
+
+ void remove_fd(int fd) {
+ std::lock_guard lock(mutex);
+ callbacks.erase(fd);
+ epoll_ctl(efd, EPOLL_CTL_DEL, fd, nullptr);
+ }
+
+ void dispatch(int timeout) {
+ std::vector events(1024);
+ int num_events = epoll_wait(efd, events.data(), events.size(), timeout);
+ for (int i = 0; i < num_events; ++i) {
+ int fd = events[i].data.fd;
+ if (callbacks.count(fd) != 0) {
+ callbacks[fd](events[i].events);
+ }
+ }
+ }
+private:
+ int efd, evfd, timer;
+
+ void dispatch_queue() {
+ std::function fn;
+ std::unique_lock lock(mutex);
+ ::read(evfd, (void*) (const uint64_t[]) {1}, sizeof(uint64_t));
+ while(!queue.empty()){
+ fn = queue.front();
+ queue.pop();
+
+ lock.unlock();
+ fn();
+ lock.lock();
+ }
+ };
+
+ void dispatch_delayed_queue() {
+ std::unique_lock lock(mutex);
+ while (!delayed_queue.empty() && delayed_queue.top().expiration < now()) {
+ auto fn = delayed_queue.top().f;
+ delayed_queue.pop();
+
+ lock.unlock();
+ fn();
+ lock.lock();
+ }
+
+ reset_timer();
+ }
+
+ struct task_t {
+ timespec expiration;
+ std::function f;
+
+ bool operator<(const task_t& rhs) const {
+ return rhs.expiration < expiration;
+ }
+ };
+
+ void reset_timer() {
+ if (delayed_queue.empty()) {
+ timerfd_settime(timer, 0, &zero, nullptr);
+ return;
+ }
+
+ itimerspec t = { {}, delayed_queue.top().expiration };
+ if (timerfd_settime(timer, TFD_TIMER_ABSTIME, &t, nullptr) < 0)
+ ALOGE("Failed to set timerfd: %s", strerror(errno));
+ }
+
+ std::mutex mutex;
+ std::queue> queue;
+ std::priority_queue delayed_queue;
+ std::unordered_map> callbacks;
+
+ static constexpr itimerspec zero = {{0, 0}, {0, 0}};
+};
+
+static always_inline timespec operator+(const timespec& lhs, const timespec& rhs) {
+ timespec result{};
+ result.tv_sec = lhs.tv_sec + rhs.tv_sec;
+ result.tv_nsec = lhs.tv_nsec + rhs.tv_nsec;
+ if (result.tv_nsec >= 1000000000L) {
+ ++result.tv_sec;
+ result.tv_nsec -= 1000000000L;
+ }
+ return result;
+}
+
+static always_inline timespec operator-(const timespec& lhs, const timespec& rhs) {
+ timespec result{};
+ result.tv_sec = lhs.tv_sec - rhs.tv_sec;
+ result.tv_nsec = lhs.tv_nsec - rhs.tv_nsec;
+ if (result.tv_nsec < 0) {
+ --result.tv_sec;
+ result.tv_nsec += 1000000000L;
+ }
+ return result;
+}
+
+static always_inline bool operator<(const timespec& lhs, const timespec& rhs) {
+ if (lhs.tv_sec < rhs.tv_sec) {
+ return true;
+ }
+ if (lhs.tv_sec > rhs.tv_sec) {
+ return false;
+ }
+ return lhs.tv_nsec < rhs.tv_nsec;
+}
+
+static always_inline timespec now() {
+ timespec now; // NOLINT(cppcoreguidelines-pro-type-member-init)
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now;
+}
+
+static always_inline timespec ms_to_timespec(long ms) {
+ return timespec { ms / 1000, (ms % 1000) * 1000000 };
+}
+
+[[maybe_unused]] static always_inline long timespec_to_ms(timespec spec) {
+ return spec.tv_sec * 1000 + spec.tv_nsec / 1000000 ;
+}
+
+[[maybe_unused]] static always_inline void timespec_to_human_readable(const timespec& ts, const char* comment) {
+ time_t sec = ts.tv_sec;
+ tm timeinfo{};
+ gmtime_r(&sec, &timeinfo);
+ ALOGE("%-10s %02d:%02d:%02d.%03ld", comment, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ts.tv_nsec / 1000000);
+}
diff --git a/app/src/main/cpp/lorie-client/xcb-connection.hpp b/app/src/main/cpp/lorie-client/xcb-connection.hpp
new file mode 100644
index 000000000..27826e2ba
--- /dev/null
+++ b/app/src/main/cpp/lorie-client/xcb-connection.hpp
@@ -0,0 +1,520 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define explicit c_explicit
+#include
+#undef explicit
+
+#include
+
+#define xcb(name, ...) xcb_ ## name ## _reply(self.conn, xcb_ ## name(self.conn, ## __VA_ARGS__), &self.err)
+#define xcb_check(name, ...) self.err = xcb_request_check(self.conn, xcb_ ## name(self.conn, ## __VA_ARGS__))
+
+[[maybe_unused]] typedef uint8_t u8;
+[[maybe_unused]] typedef uint16_t u16;
+[[maybe_unused]] typedef uint32_t u32;
+[[maybe_unused]] typedef uint64_t u64;
+[[maybe_unused]] typedef int8_t i8;
+[[maybe_unused]] typedef int16_t i16;
+[[maybe_unused]] typedef int32_t i32;
+[[maybe_unused]] typedef int64_t i64;
+
+class xcb_connection {
+private:
+
+public:
+ xcb_connection_t *conn{};
+ xcb_generic_error_t* err{}; // not thread-safe, but the whole class should be used in separate thread
+ xcb_errors_context_t *err_ctx{};
+
+ template
+ always_inline void handle_error(REPLY* reply, std::string description) { // NOLINT(performance-unnecessary-value-param)
+ if (err) {
+ const char* ext{};
+ const char* err_name = xcb_errors_get_name_for_error(err_ctx, err->error_code, &ext);
+ std::string err_text = description + "\n" +
+ "XCB Error of failed request: " + (ext?:"") + "::" + err_name + "\n" +
+ " Major opcode of failed request: " + std::to_string(err->major_code) + " (" +
+ xcb_errors_get_name_for_major_code(err_ctx, err->major_code) + ")\n" +
+ " Minor opcode of failed request: " + std::to_string(err->minor_code) + " (" +
+ xcb_errors_get_name_for_minor_code(err_ctx, err->major_code, err->minor_code) + ")\n" +
+ " Serial number of failed request: " + std::to_string(err->sequence) + "\n" +
+ " Current serial number in output stream: " + std::to_string(err->full_sequence);
+
+ free(reply);
+ free(err);
+ err = nullptr;
+ throw std::runtime_error(err_text);
+ }
+ }
+
+ always_inline void handle_error(std::string description) { // NOLINT(performance-unnecessary-value-param)
+ if (err) {
+ const char* ext{};
+ const char* err_name = xcb_errors_get_name_for_error(err_ctx, err->error_code, &ext);
+ std::string err_text = description + "\n" +
+ "XCB Error of failed request: " + (ext?:"") + "::" + err_name + "\n" +
+ " Major opcode of failed request: " + std::to_string(err->major_code) + " (" +
+ xcb_errors_get_name_for_major_code(err_ctx, err->major_code) + ")\n" +
+ " Minor opcode of failed request: " + std::to_string(err->minor_code) + " (" +
+ xcb_errors_get_name_for_minor_code(err_ctx, err->major_code, err->minor_code) + ")\n" +
+ " Serial number of failed request: " + std::to_string(err->sequence) + "\n" +
+ " Current serial number in output stream: " + std::to_string(err->full_sequence);
+ free(err);
+ err = nullptr;
+ throw std::runtime_error(err_text);
+ }
+ }
+
+ struct {
+ xcb_connection& self;
+ i32 first_event{};
+ void init() {
+ {
+ auto reply = xcb(shm_query_version);
+ self.handle_error(reply, "Error querying MIT-SHM extension");
+ free(reply);
+ }
+ {
+ auto reply = xcb(query_extension, 6, "DAMAGE");
+ self.handle_error(reply, "Error querying DAMAGE extension");
+ first_event = reply->first_event;
+ free(reply);
+ }
+ };
+
+ void attach_fd(u32 seg, i32 fd, u8 ro) {
+ xcb_check(shm_attach_fd_checked, seg, fd, ro);
+ self.handle_error("Error attaching file descriptor through MIT-SHM extension");
+ };
+
+ int create_segment(u32 seg, u32 size, u8 ro) {
+ int fd;
+ auto reply = xcb(shm_create_segment, seg, size, ro);
+ self.handle_error("Error creating shared segment through MIT-SHM extension");
+ if (reply->nfd != 1) {
+ std::runtime_error("Error creating shared segment through MIT-SHM extension: did not get file descriptor");
+ }
+ fd = xcb_shm_create_segment_reply_fds(self.conn, reply)[0];
+ free(reply);
+ return fd;
+ }
+
+ [[maybe_unused]] void detach(u32 seg) {
+ xcb_check(shm_detach, seg);
+ self.handle_error("Error attaching shared segment through MIT-SHM extension");
+ }
+
+ xcb_shm_get_image_reply_t* get(xcb_drawable_t d, i16 x, i16 y, i16 w, i16 h, u32 m, u8 f, xcb_shm_seg_t s, u32 o) {
+ auto reply = xcb(shm_get_image, d, x, y, w, h, m, f, s, o);
+ self.handle_error(reply, "Error getting shm image through MIT-SHM extension");
+ return reply;
+ };
+ } shm {*this};
+
+ struct {
+ xcb_connection& self;
+ i32 first_event{};
+
+ void init() {
+ {
+ auto reply = xcb(query_extension, 6, "DAMAGE");
+ self.handle_error(reply, "Error querying DAMAGE extension");
+ first_event = reply->first_event;
+ free(reply);
+ }
+ {
+ auto reply = xcb(damage_query_version, 1, 1);
+ self.handle_error(reply, "Error querying DAMAGE extension");
+ free(reply);
+ }
+ }
+
+ void create(xcb_drawable_t d, uint8_t l) {
+ xcb_check(damage_create, xcb_generate_id(self.conn), d, l);
+ self.handle_error("Error creating damage");
+ }
+
+ inline bool is_damage_notify_event(xcb_generic_event_t *ev) const {
+ return ev->response_type == (first_event + XCB_DAMAGE_NOTIFY);
+ }
+ } damage {*this};
+
+ struct {
+ xcb_connection& self;
+ i32 opcode{};
+ void init() {
+ {
+ auto reply = xcb(query_extension, 15, "XInputExtension");
+ self.handle_error(reply, "Error querying XInputExtension extension");
+ opcode = reply->major_opcode;
+ free(reply);
+ }
+ {
+ auto reply = xcb(input_get_extension_version, 15, "XInputExtension");
+ self.handle_error(reply, "Error querying XInputExtension extension");
+ free(reply);
+ }
+ {
+ auto reply = xcb(input_xi_query_version, 2, 2);
+ self.handle_error(reply, "Error querying XInputExtension extension");
+ free(reply);
+ }
+ }
+
+ xcb_input_device_id_t client_pointer_id() {
+ xcb_input_device_id_t id;
+ auto reply = xcb(input_xi_get_client_pointer, XCB_NONE);
+ self.handle_error(reply, "Error getting client pointer device id");
+ id = reply->deviceid;
+ free(reply);
+ return id;
+ }
+
+ void select_events(xcb_window_t window, uint16_t num_mask, const xcb_input_event_mask_t *masks){
+ xcb_check(input_xi_select_events, window, num_mask, masks);
+ self.handle_error("Error selecting Xi events");
+ }
+
+ [[maybe_unused]] inline bool is_raw_motion_event(xcb_generic_event_t *ev) const {
+ union { // NOLINT(cppcoreguidelines-pro-type-member-init)
+ xcb_generic_event_t *event;
+ xcb_ge_event_t *ge;
+ };
+ event = ev;
+ return ev->response_type == XCB_GE_GENERIC && /* cookie */ ge->pad0 == opcode && ge->event_type == XCB_INPUT_RAW_MOTION;
+ }
+ } input {*this};
+
+ struct {
+ xcb_connection& self;
+ int first_event{};
+ void init() {
+ {
+ auto reply = xcb(query_extension, 6, "XFIXES");
+ self.handle_error(reply, "Error querying XFIXES extension");
+ first_event = reply->first_event;
+ free(reply);
+ }
+ {
+ auto reply = xcb(xfixes_query_version, 4, 0);
+ self.handle_error(reply, "Error querying XFIXES extension");
+ free(reply);
+ }
+ }
+
+ void select_input(xcb_window_t window, uint32_t mask) {
+ xcb_check(xfixes_select_cursor_input, window, mask);
+ self.handle_error("Error querying selecting XFIXES input");
+ }
+
+ bool is_cursor_notify_event(xcb_generic_event_t* e) const {
+ return e->response_type == first_event + XCB_XFIXES_CURSOR_NOTIFY;
+ }
+
+ xcb_xfixes_get_cursor_image_reply_t* get_cursor_image() {
+ auto reply = xcb(xfixes_get_cursor_image);
+ self.handle_error(reply, "Error getting XFIXES cursor image");
+ return reply;
+ }
+ } fixes {*this};
+
+ struct {
+ xcb_connection &self;
+ void init() {
+ auto reply = xcb(test_get_version, 2, 2);
+ self.handle_error(reply, "Error querying XFIXES extension");
+ free(reply);
+ }
+ } xtest {*this};
+
+ struct {
+ xcb_connection &self;
+ xkb_context* context{};
+ int core_kbd{};
+
+ struct code {
+ uint32_t ucs;
+ xkb_keysym_t keysym;
+ xkb_keycode_t keycode;
+ xkb_layout_index_t layout;
+ xkb_mod_mask_t modifiers;
+ };
+
+ struct binding {
+ uint32_t ucs;
+ xkb_keycode_t keycode;
+ timespec expires;
+ };
+
+ std::vector codes;
+ std::vector bindings;
+ void init() {
+ if (context) {
+ xkb_context_unref(context);
+ }
+
+ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (!context)
+ throw std::runtime_error("Failed to setup xkb_context");
+
+ if (!xkb_x11_setup_xkb_extension(self.conn,
+ XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION,
+ XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nullptr, nullptr,
+ nullptr, nullptr))
+
+ throw std::runtime_error("Failed to setup xkb extension");
+
+ enum {
+ required_events =
+ (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
+ XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY),
+
+ required_nkn_details =
+ (XCB_XKB_NKN_DETAIL_KEYCODES),
+
+ required_map_parts =
+ (XCB_XKB_MAP_PART_KEY_TYPES |
+ XCB_XKB_MAP_PART_KEY_SYMS |
+ XCB_XKB_MAP_PART_MODIFIER_MAP |
+ XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+ XCB_XKB_MAP_PART_KEY_ACTIONS |
+ XCB_XKB_MAP_PART_VIRTUAL_MODS |
+ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP),
+
+ required_state_details =
+ (XCB_XKB_STATE_PART_MODIFIER_BASE |
+ XCB_XKB_STATE_PART_MODIFIER_LATCH |
+ XCB_XKB_STATE_PART_MODIFIER_LOCK |
+ XCB_XKB_STATE_PART_GROUP_BASE |
+ XCB_XKB_STATE_PART_GROUP_LATCH |
+ XCB_XKB_STATE_PART_GROUP_LOCK),
+ };
+
+ static const xcb_xkb_select_events_details_t details = {
+ .affectNewKeyboard = required_nkn_details,
+ .newKeyboardDetails = required_nkn_details,
+ .affectState = required_state_details,
+ .stateDetails = required_state_details,
+ };
+
+ core_kbd = xkb_x11_get_core_keyboard_device_id(self.conn);
+ if (core_kbd == -1)
+ throw std::runtime_error("Failed to get core keyboard id");
+
+ xcb_check(xkb_select_events, XCB_XKB_ID_USE_CORE_KBD, required_events, 0, 0, required_map_parts, required_map_parts, &details);
+ self.handle_error("Failed to select xkb events");
+
+ reload_keymaps(true);
+ }
+
+ void reload_keymaps(bool reload_bindings = false) {
+ auto keymap = xkb_x11_keymap_new_from_device(context, self.conn, core_kbd, XKB_KEYMAP_COMPILE_NO_FLAGS);
+
+ codes.clear();
+
+ auto iter = [&](xkb_keycode_t key) {
+ int count;
+ const xkb_keysym_t *sym;
+ for (auto &i: bindings) {
+ // in the case if some other app like x11vnc or chrome-remote-desktop rebinded this keycode...
+ if (i.keycode == key) {
+ if (xkb_keymap_num_layouts_for_key(keymap, key) == 0) {
+ if (i.ucs != 0)
+ i = {0, i.keycode, now() + ms_to_timespec(200)};
+ } else {
+ count = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &sym);
+ i = {(count)?(*sym):0, key, now() + ms_to_timespec(200)};
+ }
+ return;
+ }
+ }
+ if (xkb_keymap_num_layouts_for_key(keymap, key) == 0) {
+ // if this key has no bindings it is interesting for rebinding purposes...
+ // it will only happen if this key not in bindings yet...
+ bindings.push_back({0, key, now()});
+ } else {
+ for (xkb_layout_index_t layout=0; layout < xkb_keymap_num_layouts_for_key(keymap, key); layout++)
+ for (xkb_level_index_t level=0; level < xkb_keymap_num_levels_for_key(keymap, key, layout); level++) {
+ count = xkb_keymap_key_get_syms_by_level(keymap, key, layout, level, &sym);
+ if (count && *sym != 0) {
+ uint32_t ucs = xkb_keysym_to_utf32(*sym);
+ xkb_mod_mask_t mod = 0;
+ xkb_keymap_key_get_mods_for_level(keymap, key, layout, level, &mod, 1);
+ codes.push_back({ucs, *sym, key, layout, mod});
+ }
+ }
+ }
+ };
+ xkb_keymap_key_for_each(keymap, [](xkb_keymap *, xkb_keycode_t key, void *d) {
+ (*reinterpret_cast(d))(key);
+ }, static_cast(&iter));
+
+ // `codes` will be used in binary search, so we should sort it by unicode symbol value
+ std::sort(codes.begin(), codes.end(), [](code& a, code& b){ return a.ucs < b.ucs; });
+ }
+
+ void send_keysym(xcb_keysym_t keysym, int meta_state) {
+ char buf[64]{};
+ xkb_keysym_get_name(keysym, buf, sizeof(buf));
+ ALOGV("Sending keysym %s", buf);
+
+ auto code = std::find_if(codes.begin(), codes.end(), [&c = keysym](auto& code) {
+ return code.keysym == c;
+ });
+
+ if (code == codes.end()) {
+ xkb_keysym_get_name(keysym, buf, sizeof(buf));
+ ALOGE("Code for keysym 0x%X (%s) not found...", keysym, buf);
+ return;
+ }
+
+ xcb_flush(self.conn);
+
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(self.conn)).data;
+
+ // Since we do not track state of modifiers we should reset them before we finish here.
+ // Getting current modifiers
+ u32 modifiers = code->modifiers;
+// {
+// auto reply = xcb(query_pointer, s->root);
+// if (reply)
+// modifiers &= ~reply->mask;
+//
+// ALOGE("pointer mods %d", reply->mask);
+// free(reply);
+// }
+
+ u8 current_group = 0;
+ {
+ auto reply = xcb(xkb_get_state, XCB_XKB_ID_USE_CORE_KBD);
+ current_group = reply->group;
+ modifiers &= ~reply->mods;
+ ALOGE("pointer mods %d", reply->mods);
+ free(reply);
+ }
+
+ if (meta_state & AMETA_CTRL_ON)
+ modifiers |= XCB_MOD_MASK_CONTROL;
+
+ if (meta_state & AMETA_SHIFT_ON)
+ modifiers |= XCB_MOD_MASK_SHIFT;
+
+ if (meta_state & AMETA_ALT_ON)
+ modifiers |= XCB_MOD_MASK_1;
+
+ if (meta_state & AMETA_META_ON)
+ modifiers |= XCB_MOD_MASK_4;
+
+ auto reply = xcb(get_modifier_mapping);
+ self.handle_error("Failed to get keyboard modifiers.");
+
+ for (int mod_index = XCB_MAP_INDEX_SHIFT; mod_index <= XCB_MAP_INDEX_5; mod_index++) {
+ if (modifiers & (1 << mod_index)) {
+ for (int mod_key = 0; mod_key < reply->keycodes_per_modifier; mod_key++) {
+ int keycode = xcb_get_modifier_mapping_keycodes(reply)
+ [mod_index * reply->keycodes_per_modifier + mod_key];
+ if (keycode)
+ xcb_test_fake_input(self.conn, XCB_KEY_PRESS, keycode, XCB_CURRENT_TIME,
+ s->root, 0, 0, 0);
+ }
+ }
+ }
+
+ xcb_xkb_latch_lock_state(self.conn, XCB_XKB_ID_USE_CORE_KBD, 0, 0, 1, code->layout, 0, 0, 0);
+ xcb_test_fake_input(self.conn, XCB_KEY_PRESS, code->keycode, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ xcb_test_fake_input(self.conn, XCB_KEY_RELEASE, code->keycode, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ xcb_xkb_latch_lock_state(self.conn, XCB_XKB_ID_USE_CORE_KBD, 0, 0, 1, current_group, 0, 0, 0);
+
+ for (int mod_index = XCB_MAP_INDEX_SHIFT; mod_index <= XCB_MAP_INDEX_5; mod_index++) {
+ if (modifiers & (1 << mod_index)) {
+ for (int mod_key = 0; mod_key < reply->keycodes_per_modifier; mod_key++) {
+ int keycode = xcb_get_modifier_mapping_keycodes(reply)
+ [mod_index * reply->keycodes_per_modifier + mod_key];
+ if (keycode)
+ xcb_test_fake_input(self.conn, XCB_KEY_RELEASE, keycode,
+ XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ }
+ }
+ }
+
+ free(reply);
+ xcb_flush(self.conn);
+ }
+
+ void send_key(xcb_keysym_t keysym, u8 type) {
+ // SurfaceView can only receive Unicode input from a virtual keyboard.
+ // Since SurfaceView is not a text editor, it cannot receive Unicode input from a
+ // physical keyboard. This is actually beneficial for us as we receive original
+ // input events, albeit with encoded keycodes. Since we receive original keycodes
+ // regardless of the layout, we can simply pass them to X11 as is, and the desktop
+ // environment will determine in which layout the user will be typing.
+ // Here we do not change current layout and do not change modifiers because
+ // this function should only be triggered by hardware keyboard or extra key bar.
+ char buf[64]{};
+ xkb_keysym_get_name(keysym, buf, sizeof(buf));
+ ALOGV("Sending keysym %s", buf);
+
+ auto code = std::find_if(codes.begin(), codes.end(), [&c = keysym](auto& code) {
+ return code.keysym == c;
+ });
+
+ if (code == codes.end()) {
+ xkb_keysym_get_name(keysym, buf, sizeof(buf));
+ ALOGE("Code for keysym 0x%X (%s) not found...", keysym, buf);
+ return;
+ }
+
+ xcb_flush(self.conn);
+
+ xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(self.conn)).data;
+ xcb_test_fake_input(self.conn, type, code->keycode, XCB_CURRENT_TIME, s->root, 0, 0, 0);
+ xcb_flush(self.conn);
+ }
+ } xkb {*this};
+
+ void init(int sockfd) {
+ xcb_connection_t* new_conn = xcb_connect_to_fd(sockfd, nullptr);
+ int conn_err = xcb_connection_has_error(new_conn);
+ if (conn_err) {
+ const char *s;
+ switch (conn_err) {
+#define c(name) case name: s = static_cast(#name); break
+ c(XCB_CONN_ERROR);
+ c(XCB_CONN_CLOSED_EXT_NOTSUPPORTED);
+ c(XCB_CONN_CLOSED_MEM_INSUFFICIENT);
+ c(XCB_CONN_CLOSED_REQ_LEN_EXCEED);
+ c(XCB_CONN_CLOSED_PARSE_ERR);
+ c(XCB_CONN_CLOSED_INVALID_SCREEN);
+ c(XCB_CONN_CLOSED_FDPASSING_FAILED);
+ default:
+ s = "UNKNOWN";
+#undef c
+ }
+ throw std::runtime_error(std::string() + "XCB connection has error: " + s);
+ }
+
+ if (err_ctx)
+ xcb_errors_context_free(err_ctx);
+ if (conn)
+ xcb_disconnect(conn);
+ conn = new_conn;
+ xcb_errors_context_new(conn, &err_ctx);
+
+ shm.init();
+ xtest.init();
+ damage.init();
+ input.init();
+ fixes.init();
+ xkb.init();
+ }
+};
diff --git a/app/src/main/jni/lorie/Android.mk b/app/src/main/cpp/lorie/Android.mk
similarity index 77%
rename from app/src/main/jni/lorie/Android.mk
rename to app/src/main/cpp/lorie/Android.mk
index 112e316ae..660ed14b0 100644
--- a/app/src/main/jni/lorie/Android.mk
+++ b/app/src/main/cpp/lorie/Android.mk
@@ -5,16 +5,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE := lorie
LOCAL_SRC_FILES := \
compositor.cpp \
- lorie_message_queue.cpp \
- utils/log.cpp \
- android.cpp \
- \
- backend/android/utils.c \
lorie_wayland_server.cpp \
$(wildcard $(WAYLAND_GENERATED)/*.cpp)
LOCAL_CXXFLAGS := -std=c++20
-#LOCAL_CXXFLAGS += -finstrument-functions
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/../wayland/src $(LOCAL_PATH)/../wayland $(WAYLAND_GENERATED)
LOCAL_LDLIBS := -lEGL -lGLESv2 -llog -landroid
LOCAL_SHARED_LIBRARIES := wayland-server
diff --git a/app/src/main/cpp/lorie/compositor.cpp b/app/src/main/cpp/lorie/compositor.cpp
new file mode 100644
index 000000000..9a82d321b
--- /dev/null
+++ b/app/src/main/cpp/lorie/compositor.cpp
@@ -0,0 +1,379 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#define DEFAULT_SOCKET_NAME "termux-x11"
+#define DEFAULT_SOCKET_PATH "/data/data/com.termux/files/usr/tmp"
+
+#include
+
+#ifndef LOG_TAG
+#define LOG_TAG "LorieNative"
+#endif
+
+#ifndef LOG
+#define LOG(prio, ...) __android_log_print(prio, LOG_TAG, __VA_ARGS__)
+#endif
+
+#define LOGV(...) LOG(ANDROID_LOG_VERBOSE, __VA_ARGS__)
+#define LOGE(...) LOG(ANDROID_LOG_ERROR, __VA_ARGS__)
+
+#pragma ide diagnostic ignored "EndlessLoop"
+#pragma clang diagnostic ignored "-Wshadow"
+
+class lorie_message_queue {
+public:
+ lorie_message_queue() {
+ std::unique_lock lock(mutex);
+
+ fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+ if (fd == -1) {
+ LOGE("Failed to create socketpair for message queue: %s", strerror(errno));
+ return;
+ }
+ };
+
+ void write(std::function func) {
+ static uint64_t i = 1;
+ std::unique_lock lock(mutex);
+ queue.push(std::move(func));
+ ::write(fd, &i, sizeof(uint64_t));
+ };
+
+ static int run(int, uint32_t, void* data) {
+ auto q = reinterpret_cast(data);
+ static uint64_t i = 0;
+ std::unique_lock lock(q->mutex);
+ std::function fn;
+ ::read(q->fd, &i, sizeof(uint64_t));
+ while(!q->queue.empty()){
+ fn = q->queue.front();
+ q->queue.pop();
+
+ lock.unlock();
+ fn();
+ lock.lock();
+ }
+
+ return 0;
+ };
+
+ int fd;
+private:
+ std::mutex mutex;
+ std::queue> queue;
+};
+
+class lorie_compositor: public wayland::display_t {
+public:
+ explicit lorie_compositor(int dpi);
+
+ void report_mode(int width, int height);
+
+ wayland::global_compositor_t global_compositor{this};
+ wayland::global_seat_t global_seat{this};
+ wayland::global_output_t global_output{this};
+ wayland::global_shell_t global_shell{this};
+ wayland::global_xdg_wm_base_t global_xdg_wm_base{this};
+
+ lorie_message_queue queue;
+
+ int dpi;
+};
+
+using namespace wayland;
+
+__asm__ (
+ " .global blob\n"
+ " .global blob_size\n"
+ " .section .rodata\n"
+ " blob:\n"
+ " .incbin \"en_us.xkbmap\"\n"
+ " 1:\n"
+ " blob_size:\n"
+ " .int 1b - blob"
+ );
+
+extern jbyte blob[];
+extern int blob_size;
+
+#include
+#include
+
+#define ASHMEM_SET_SIZE _IOW(0x77, 3, size_t)
+static inline int
+os_create_anonymous_file(size_t size) {
+ int fd, ret;
+ long flags;
+ fd = open("/dev/ashmem", O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+ ret = ioctl(fd, ASHMEM_SET_SIZE, size);
+ if (ret < 0)
+ goto err;
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ goto err;
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ goto err;
+ return fd;
+ err:
+ close(fd);
+ return ret;
+}
+
+lorie_compositor::lorie_compositor(int dpi): dpi(dpi) {
+ // these calls do no overwrite existing values so it is ok.
+ setenv("WAYLAND_DISPLAY", DEFAULT_SOCKET_NAME, 0);
+ setenv("XDG_RUNTIME_DIR", DEFAULT_SOCKET_PATH, 0);
+
+ // wl_display_add_socket creates socket with name $WAYLAND_DISPLAY in folder $XDG_RUNTIME_DIR
+ wl_display_add_socket(*this, nullptr);
+
+ on_client = [=](client_t* client) {
+ client->on_destroy = [=] {};
+ };
+ global_compositor.on_bind = [=] (client_t*, compositor_t* compositor) {
+ compositor->on_create_region = [](region_t* region) { region->on__destroy = [=] { region->destroy(); }; };
+ compositor->on_create_surface = [=](surface_t* surface) {
+ // We need not to send frame callback. That is a sign for Xwayland to send new buffer
+ surface->on_attach = [=](buffer_t* b, int32_t, int32_t) {
+ // sending WL_BUFFER_RELEASE
+ wl_resource_post_event(*b, 0);
+ };
+ surface->on__destroy = [=] { surface->destroy(); };
+ };
+ };
+ global_seat.on_bind = [=](client_t* client, seat_t* seat) {
+ seat->capabilities (seat_capability::keyboard | seat_capability::pointer);
+ seat->name("default");
+
+ seat->on_get_pointer = [](pointer_t* pointer) { pointer->on_release = [=] { pointer->destroy(); }; };
+ seat->on_get_keyboard = [=](keyboard_t* kbd) {
+ kbd->on_release = [=] { kbd->destroy(); };
+ int fd = os_create_anonymous_file(blob_size);
+ if (fd == -1) return;
+ void *dest = mmap(nullptr, blob_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ memcpy(dest, blob, blob_size);
+ munmap(dest, blob_size);
+
+ struct stat s = {};
+ fstat(fd, &s);
+
+ kbd->keymap(wayland::keyboard_keymap_format::xkb_v1, fd, s.st_size);
+ close (fd);
+ };
+ seat->on_get_touch = [](touch_t* touch) { touch->on_release = [=] { touch->destroy(); }; };
+ };
+ global_output.on_bind = [=, this](client_t*, output_t* output) {
+ report_mode(800, 600);
+ output->on_release = [=]{ output->destroy(); };
+ };
+ global_shell.on_bind = [](client_t*, shell_t* shell) {
+ shell->on_get_shell_surface = [](shell_surface_t*, surface_t*){};
+ };
+ global_xdg_wm_base.on_bind = [](client_t*, xdg_wm_base_t* wm_base) {
+ wm_base->on_get_xdg_surface = [](xdg_surface_t*, surface_t*) {};
+ wm_base->on__destroy = [=]() { wm_base->destroy(); };
+ };
+
+ LOGV("Starting compositor");
+ wl_display_init_shm (*this);
+ wl_event_loop_add_fd(wl_display_get_event_loop(*this), queue.fd,
+ WL_EVENT_READABLE, &lorie_message_queue::run, &queue);
+
+ // We do not really need to terminate it, user can terminate the whole process.
+ std::thread([=]{
+ while (true) {
+ wl_display_flush_clients(*this);
+ wl_event_loop_dispatch(wl_display_get_event_loop(*this), 200);
+ }
+ }).detach();
+}
+
+void lorie_compositor::report_mode(int width, int height) {
+ if (width == 0 || height == 0)
+ return;
+ int mm_width = int(width * 25.4 / dpi);
+ int mm_height = int(height * 25.4 / dpi);
+ wl_client* client;
+
+ // We do not store any data of clients so just send it to everybody (but only Xwayland is connected);
+ wl_client_for_each(client, wl_display_get_client_list(*this)) {
+ auto data = std::make_tuple(width, height, mm_width, mm_height);
+ // We do not store pointer to that resource, so iterate
+ wl_client_for_each_resource(client, [](wl_resource *r, void *d) {
+ auto [width, height, mm_width, mm_height] = *(reinterpret_cast(d));
+ const wl_interface *output_interface = &wayland::detail::output_interface;
+ if (wl_resource_instance_of(r, output_interface, output_interface)) {
+ auto output = reinterpret_cast(resource_t::get(r));
+ output->geometry(0, 0, mm_width, mm_height, output_subpixel::unknown, "Lorie", "none", output_transform::normal);
+ output->scale(1.0);
+ output->mode(output_mode::current | output_mode::preferred, width, height, 60000);
+ output->done();
+ return WL_ITERATOR_STOP;
+ }
+ return WL_ITERATOR_CONTINUE;
+ }, &data);
+ }
+}
+
+static lorie_compositor* compositor{};
+static int display = 0;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_CmdEntryPoint_spawnCompositor([[maybe_unused]] JNIEnv *env,
+ [[maybe_unused]] jobject thiz,
+ jint d, jint dpi) {
+ display = d;
+ compositor = new lorie_compositor(dpi);
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_termux_x11_CmdEntryPoint_outputResize([[maybe_unused]] JNIEnv *env,
+ [[maybe_unused]] jobject thiz,
+ jint width, jint height) {
+ if (compositor)
+ compositor->report_mode(width, height);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_termux_x11_CmdEntryPoint_socketExists([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass clazz) {
+ // Here we should try to connect socket...
+ struct sockaddr_un local{ .sun_family=AF_UNIX };
+ int len, fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if(fd == -1) {
+ perror("Unable to create socket");
+ return 1;
+ }
+
+ snprintf(local.sun_path, sizeof(local.sun_path), "%s/%s",
+ getenv("XDG_RUNTIME_DIR") ?: DEFAULT_SOCKET_PATH,
+ getenv("WAYLAND_SOCKET") ?: DEFAULT_SOCKET_NAME);
+
+ len = int(strlen(local.sun_path) + sizeof(local.sun_family));
+ return connect(fd, (struct sockaddr *)&local, len) != -1;
+}
+
+void exit(JNIEnv* env, int code) {
+ // app_process writes exception to logcat if a process dies with exit() or abort(), so
+ jclass systemClass = env->FindClass("java/lang/System");
+ jmethodID exitMethod = env->GetStaticMethodID(systemClass, "exit", "(I)V");
+ env->CallStaticVoidMethod(systemClass, exitMethod, code);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_termux_x11_CmdEntryPoint_exec(JNIEnv *env, [[maybe_unused]] jclass clazz, jobjectArray jargv) {
+ // execv's argv array is a bit incompatible with Java's String[], so we do some converting here...
+ int argc = env->GetArrayLength(jargv) + 2; // Leading executable path and terminating NULL
+ char *argv[argc];
+ memset(argv, 0, sizeof(char*) * argc);
+
+ argv[0] = (char*) "Xwayland";
+ argv[argc] = nullptr; // Terminating NULL
+ for(int i=1; i(env->GetObjectArrayElement(jargv, i - 1));
+ const char *pjc = env->GetStringUTFChars(js, JNI_FALSE);
+ argv[i] = static_cast(calloc(strlen(pjc) + 1, sizeof(char))); //Extra char for the terminating NULL
+ strcpy((char *) argv[i], pjc);
+ env->ReleaseStringUTFChars(js, pjc);
+ }
+
+ // This process should be shut if Xwayland dies...
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC);
+ ALooper_addFd(ALooper_prepare(0), fds[1], ALOOPER_POLL_CALLBACK,
+ ALOOPER_EVENT_INVALID | ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_ERROR,
+ [](int, int, void* data) {
+ dprintf(2, "Xwayland died, no need to go on...\n");
+ exit(reinterpret_cast(data), 0);
+ return 0;
+ }, env);
+
+ switch(fork()) {
+ case -1:
+ perror("fork");
+ exit(env, 1);
+ break;
+ case 0: //child
+ execvp(argv[0], argv);
+ perror("execvp");
+ default: //parent
+ close(fds[0]);
+ break;
+ }
+}
+
+extern "C"
+JNIEXPORT jint JNICALL
+Java_com_termux_x11_CmdEntryPoint_connect([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass clazz) {
+ struct sockaddr_un local { .sun_family=AF_UNIX, .sun_path="/data/data/com.termux/files/usr/tmp/.X11-unix/X0" };
+ int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sockfd == -1) {
+ perror("socket");
+ return -1;
+ }
+
+ snprintf(local.sun_path, sizeof(local.sun_path), "%s/.X11-unix/X%d",
+ getenv("TMPDIR") ?: DEFAULT_SOCKET_PATH, display);
+
+ if (connect(sockfd, reinterpret_cast(&local), sizeof(local)) < 0) {
+ LOGE("Failed to connect %s: %s\n", local.sun_path, strerror(errno));
+ return -1;
+ }
+
+ return sockfd;
+}
+
+extern "C"
+JNIEXPORT jint JNICALL
+Java_com_termux_x11_CmdEntryPoint_stderr(JNIEnv *env, jclass clazz) {
+ const char *debug = getenv("TERMUX_X11_DEBUG");
+ if (debug && !strcmp(debug, "1")) {
+ int p[2];
+ pipe(p);
+ fchmod(p[1], 0777);
+ if (!fork()) {
+ close(p[1]);
+ FILE *fp = fdopen(p[0], "r");
+ size_t len;
+ char *line = nullptr;
+
+ while ((getline(&line, &len, fp)) != -1) {
+ printf("com.termux.x11 logcat: %s", line);
+ }
+ exit(env, 0);
+ }
+ close(p[0]);
+
+ return p[1];
+ }
+
+ return -1;
+}
+
+extern "C"
+JNIEXPORT jint JNICALL
+Java_com_termux_x11_CmdEntryPoint_getuid(JNIEnv *env, jclass clazz) {
+ return getuid();
+}
\ No newline at end of file
diff --git a/app/src/main/jni/lorie/en_us.xkbmap b/app/src/main/cpp/lorie/en_us.xkbmap
similarity index 100%
rename from app/src/main/jni/lorie/en_us.xkbmap
rename to app/src/main/cpp/lorie/en_us.xkbmap
diff --git a/app/src/main/cpp/lorie/lorie_wayland_server.cpp b/app/src/main/cpp/lorie/lorie_wayland_server.cpp
new file mode 100644
index 000000000..2a4856c8c
--- /dev/null
+++ b/app/src/main/cpp/lorie/lorie_wayland_server.cpp
@@ -0,0 +1,100 @@
+#include
+#include
+#include
+#include
+#include
+
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma ide diagnostic ignored "cppcoreguidelines-pro-type-static-cast-downcast"
+
+using namespace wayland;
+
+
+/* display_t methods */
+static void display_destroyed(wl_listener* l, void* data) {
+ auto d = static_cast(l);
+ if (d->on_destroy)
+ d->on_destroy();
+}
+
+static void client_created(wl_listener* l, void* data) {
+ if (!data) return;
+ auto c = static_cast(data);
+ auto d = reinterpret_cast(wl_display_get_destroy_listener(wl_client_get_display(c), &display_destroyed));
+ auto new_client = new client_t(c);
+ if (d->on_client)
+ d->on_client(new_client);
+}
+
+display_t::display_t():
+display(wl_display_create()),
+wl_listener{{}, &display_destroyed},
+client_created_listener{{}, &client_created}{
+ wl_display_add_destroy_listener(display, this);
+ wl_display_add_client_created_listener(display, &client_created_listener);
+}
+
+display_t::~display_t() {
+ wl_display_destroy_clients(display);
+ wl_display_destroy(display);
+}
+
+/* client_t methods */
+wl_listener client_resource_created {{}, [](wl_listener*, void* d) {
+ if (d == nullptr || *(static_cast(d)) != &wl_buffer_interface)
+ return;
+ new buffer_t(static_cast(d));
+}};
+
+static void client_destroy_callback(struct wl_listener *listener, void *) {
+ if (listener == nullptr) return;
+ auto c = static_cast(listener);
+ if (c->on_destroy)
+ c->on_destroy();
+ delete c;
+};
+
+client_t::client_t(wl_client* client): wl_listener{{}, &client_destroy_callback}, client(client) {
+ wl_client_add_destroy_listener(*this, this);
+ wl_client_add_resource_created_listener(*this, &client_resource_created);
+}
+
+client_t* client_t::get(wl_client* client) {
+ return client ? static_cast(wl_client_get_destroy_listener(client, &client_destroy_callback)) : nullptr;
+}
+
+void client_t::destroy() {
+ wl_client_destroy(client);
+}
+
+/* resource_t methods */
+void resource_t::resource_destroyed(wl_listener* that, void*) {
+ auto r = static_cast(that);
+ if (r->on_destroy)
+ r->on_destroy();
+ delete r;
+}
+
+resource_t::resource_t(client_t* client, uint32_t id, uint32_t version,
+wl_interface* iface, wl_dispatcher_func_t dispatcher):
+wl_listener{{}, &resource_destroyed},
+m_client(client), display(wl_client_get_display(*client)),
+resource(wl_resource_create(*client, iface, version, id)),
+version(version) {
+ wl_resource_add_destroy_listener(resource, this);
+ wl_resource_set_dispatcher(resource, dispatcher, iface, nullptr, nullptr);
+}
+
+static inline client_t* client_get(wl_resource* c) {
+ wl_client* client;
+ if (c == nullptr || (client = wl_resource_get_client(c)) == nullptr)
+ return nullptr;
+ return client_t::get(client);
+}
+
+resource_t::resource_t(wl_resource *r):
+wl_listener{{}, &resource_destroyed},
+m_client(client_get(r)), display(wl_client_get_display(*m_client)),
+resource(r), version(wl_resource_get_version(r)) {
+ wl_resource_add_destroy_listener(resource, this);
+}
\ No newline at end of file
diff --git a/app/src/main/jni/lorie/lorie_wayland_server.hpp b/app/src/main/cpp/lorie/lorie_wayland_server.hpp
similarity index 68%
rename from app/src/main/jni/lorie/lorie_wayland_server.hpp
rename to app/src/main/cpp/lorie/lorie_wayland_server.hpp
index c41a22735..2dd97e9e2 100644
--- a/app/src/main/jni/lorie/lorie_wayland_server.hpp
+++ b/app/src/main/cpp/lorie/lorie_wayland_server.hpp
@@ -28,26 +28,6 @@ namespace wayland {
}
~display_t();
-
- void add_fd_listener(int fd, uint32_t mask, std::function listener);
-
- void add_socket_fd(int fd);
-
- inline void add_socket_auto() {
- wl_display_add_socket_auto(display);
- }
-
- inline void adopt_client(int fd) {
- auto r = wl_client_create(display, fd);
- }
-
- inline void init_shm() {
- wl_display_init_shm(display);
- }
-
- inline void terminate() {
- running = false;
- }
inline void run() {
while (running) {
@@ -55,19 +35,9 @@ namespace wayland {
wl_event_loop_dispatch(wl_display_get_event_loop(display), 200);
}
}
-
- inline void set_log_handler(wl_log_func_t f) {
- wl_log_set_handler_server(f);
- }
-
- inline uint32_t next_serial() {
- return wl_display_next_serial(*this);
- };
};
class client_t: public wl_listener {
- protected:
- std::any userdata;
public:
std::function on_destroy = nullptr;
explicit client_t(wl_client* client);
@@ -78,12 +48,6 @@ namespace wayland {
static client_t* get(wl_client*);
- std::any& user_data() {
- return userdata;
- }
-
- void post_implementation_error(const std::string& string);
-
void destroy();
inline bool operator==(const client_t& other) {
@@ -143,10 +107,6 @@ namespace wayland {
static inline resource_t* get(void* r) {
return get(static_cast(r));
};
-
- std::any& user_data() {
- return userdata;
- }
inline int id() {
return wl_resource_get_id(*this);
@@ -159,8 +119,6 @@ namespace wayland {
inline void post_error(uint32_t code, const std::string& msg) const {
wl_resource_post_error(resource, code, "%s", msg.c_str());
};
-
- static uint32_t timestamp();
virtual ~resource_t() = default;
};
@@ -190,41 +148,6 @@ namespace wayland {
operator wl_buffer *() const {
return reinterpret_cast(const_cast(this));
};
-
- inline void release() {
- wl_resource_post_event(resource, 0);
- }
-
- [[nodiscard]]
- inline bool is_shm() {
- return wl_shm_buffer_get(*this) != nullptr;
- }
-
- [[nodiscard]]
- inline void *shm_data() const {
- return wl_shm_buffer_get_data(
- wl_shm_buffer_get(*this));
- }
-
- [[nodiscard]]
- inline int32_t shm_stride() const {
- return wl_shm_buffer_get_stride(wl_shm_buffer_get(*this));
- }
-
- [[nodiscard]]
- inline uint32_t shm_format() const {
- return wl_shm_buffer_get_format(wl_shm_buffer_get(*this));
- }
-
- [[nodiscard]]
- inline int32_t shm_width() const {
- return wl_shm_buffer_get_width(wl_shm_buffer_get(*this));
- }
-
- [[nodiscard]]
- inline int32_t shm_height() const {
- return wl_shm_buffer_get_height(wl_shm_buffer_get(*this));
- }
};
}
diff --git a/app/src/main/cpp/wayland b/app/src/main/cpp/wayland
new file mode 160000
index 000000000..1ef773be7
--- /dev/null
+++ b/app/src/main/cpp/wayland
@@ -0,0 +1 @@
+Subproject commit 1ef773be76ec0f45312622da7720ae6917bdf789
diff --git a/app/src/main/jni/wayland.patch b/app/src/main/cpp/wayland.patch
similarity index 100%
rename from app/src/main/jni/wayland.patch
rename to app/src/main/cpp/wayland.patch
diff --git a/app/src/main/jni/wayland2.patch b/app/src/main/cpp/wayland2.patch
similarity index 100%
rename from app/src/main/jni/wayland2.patch
rename to app/src/main/cpp/wayland2.patch
diff --git a/app/src/main/cpp/xcbproto b/app/src/main/cpp/xcbproto
new file mode 160000
index 000000000..842d91316
--- /dev/null
+++ b/app/src/main/cpp/xcbproto
@@ -0,0 +1 @@
+Subproject commit 842d91316243eb1f2e208231acc1512c2cf43a1f
diff --git a/app/src/main/cpp/xorgproto b/app/src/main/cpp/xorgproto
new file mode 160000
index 000000000..1b6e63b2c
--- /dev/null
+++ b/app/src/main/cpp/xorgproto
@@ -0,0 +1 @@
+Subproject commit 1b6e63b2c38a0cf6cd1c70bfc5483cac0d1710e1
diff --git a/app/src/main/java/com/termux/x11/AdditionalKeyboardView.java b/app/src/main/java/com/termux/x11/AdditionalKeyboardView.java
index e03b6ca65..7dd48f406 100644
--- a/app/src/main/java/com/termux/x11/AdditionalKeyboardView.java
+++ b/app/src/main/java/com/termux/x11/AdditionalKeyboardView.java
@@ -4,6 +4,7 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Rect;
+import android.os.Build;
import android.preference.PreferenceManager;
import androidx.appcompat.widget.AppCompatTextView;
import android.util.AttributeSet;
diff --git a/app/src/main/java/com/termux/x11/CmdEntryPoint.java b/app/src/main/java/com/termux/x11/CmdEntryPoint.java
index 1a63aff60..bcdfa846c 100644
--- a/app/src/main/java/com/termux/x11/CmdEntryPoint.java
+++ b/app/src/main/java/com/termux/x11/CmdEntryPoint.java
@@ -1,236 +1,196 @@
package com.termux.x11;
import android.annotation.SuppressLint;
-import android.app.AppOpsManager;
-import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
-import android.os.Parcel;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.Objects;
-
-import com.termux.x11.starter.ActivityManager;
-import com.termux.x11.starter.Compat;
-
-@SuppressLint("UnsafeDynamicallyLoadedCode")
-@SuppressWarnings({"unused", "RedundantThrows", "SameParameterValue", "FieldCanBeLocal"})
-public class CmdEntryPoint {
- @SuppressLint("SdCardPath")
- private final String XwaylandPath = "/data/data/com.termux/files/usr/bin/Xwayland";
- private final ComponentName TermuxX11Component =
- ComponentName.unflattenFromString("com.termux.x11/.TermuxX11StarterReceiver");
- private String[] args;
- private Service svc;
- private ParcelFileDescriptor logFD;
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.List;
+
+public class CmdEntryPoint extends ICmdEntryInterface.Stub {
+ public static final String ACTION_START = "com.termux.x11.CmdEntryPoint.ACTION_START";
+ public static final int PORT = 7892;
+ public static final byte[] MAGIC = "0xDEADBEEF".getBytes();
+
+ // this constant is used in Xwayland itself
+ // https://github.com/freedesktop/xorg-xserver/blob/ccdd431cd8f1cabae9d744f0514b6533c438908c/hw/xwayland/xwayland-screen.c#L66
+ public static final int DEFAULT_DPI = 96;
+
+ @SuppressLint("StaticFieldLeak")
+ private static Handler handler;
+ private final Context ctx;
/**
* Command-line entry point.
+ * [1]
+ * Application creates socket with name $WAYLAND_DISPLAY in folder $XDG_RUNTIME_DIR
+ * If these environment variables are unset they are specified as
+ * WAYLAND_DISPLAY="termux-x11"
+ * XDG_RUNTIME_DIR="/data/data/com.termux/files/usr/tmp"
+ * Any commandline arguments passed to this program are passed to Xwayland.
+ * The only exception is `--no-xwayland-start`, read [4].
+ *
+ * [2]
+ * Please, do not set WAYLAND_DISPLAY to "wayland-0", lots of programs (primarily GTK-based)
+ * are trying to connect the compositor and crashing. Compositor in termux-x11 is a fake and a stub.
+ * It is only designed to handle Xwayland.
+ *
+ * [3]
+ * Also you should set TMPDIR environment variable in the case if you are running Xwayland in
+ * non-termux environment. That is the only way to localize X connection socket.
+ * TMPDIR should be accessible by termux-x11.
+ *
+ * [4]
+ * You can run `termux-x11 :0 --no-xwayland-start` to spawn compositor, but not to spawn Termux's
+ * Xwayland in the case you want to use Xwayland contained in chroot environment.
+ * Do not forget about [2] to avoid application crashes.
+ * Also you must specify the same display number you will set to Xwayland.
+ * You must start `termux-x11` as root if you want to make it work with chroot'd Xwayland.
+ * `root@termux: ~# WAYLAND_DISPLAY="termux-x11" XDG_RUNTIME_DIR=//var/run/1000/ TMDIR=//tmp/ termux-x11 :0 --no-xwayland-start`
+ * `root@chroot: ~# WAYLAND_DISPLAY="termux-x11" XDG_RUNTIME_DIR=//var/run/1000/ TMDIR=//tmp/ Xwayland :0 -ac`
+ *
+ * [5]
+ * You can specify DPI by using `-dpi` option.
+ * It is Xwayland option, but termux-x11 also handles it.
+ *
+ * [6]
+ * Start termux-x11 with TERMUX_X11_DEBUG=1 flag to redirect Termux:X11 logcat to termux-x11 stderr.
+ * `env TERMUX_X11_DEBUG=1 termux-x11 :0 -ac`
*
* @param args The command-line arguments
*/
public static void main(String[] args) {
- try {
- (new Thread(() -> {
- try {
- (new CmdEntryPoint()).onRun(args);
- } catch (Throwable e) {
- e.printStackTrace();
- }
- })).start();
-
- synchronized (Thread.currentThread()) {
- Looper.loop();
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
+ handler = new Handler();
+ handler.post(() -> new CmdEntryPoint(args));
+ Looper.loop();
}
- Runnable failedToStartActivity = () -> {
- System.err.println("Android reported activity started but we did not get any respond");
- System.err.println("Looks like we failed to start activity.");
- exit(1);
- };
-
- public void onRun(String[] args) throws Throwable {
- CmdEntryPoint.this.args = args;
- checkXdgRuntimeDir();
- prepareLogFD();
- if (!Compat.havePermission(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW)) {
- System.err.println("Looks like " + Compat.callingPackage +
- " lacks \"Draw Over Apps\" permission.");
- System.err.println("You can grant " + Compat.callingPackage +
- " the \"Draw Over Apps\" permission from its App Info activity:");
- System.err.println("\tAndroid Settings -> Apps -> Termux -> Advanced -> Draw over other apps.");
- }
+ @SuppressWarnings("FieldCanBeLocal")
+ private int dpi = DEFAULT_DPI;
+ @SuppressWarnings("FieldCanBeLocal")
+ private int display = 0;
- if (checkWaylandSocket()) {
- System.err.println("termux-x11 is already running");
- startXwayland();
+ CmdEntryPoint(String[] args) {
+ ctx = android.app.ActivityThread.systemMain().getSystemContext();
+ if (socketExists()) {
+ System.err.println("termux-x11 is already running. You can kill it with command `pkill -9 Xwayland`");
+ handler.post(() -> System.exit(0));
} else {
- svc = new Service();
- handler.postDelayed(failedToStartActivity, 2000);
- boolean launched = startActivity(svc);
- }
- }
-
- public void onTransact(int code, Parcel data, Parcel reply, int flags) {
- handler.removeCallbacks(failedToStartActivity);
- }
-
- private void prepareLogFD() {
- logFD = ParcelFileDescriptor.adoptFd(openLogFD());
- }
-
- private ParcelFileDescriptor getWaylandFD() throws Throwable {
- try {
- ParcelFileDescriptor pfd;
- int fd = createWaylandSocket();
- if (fd == -1)
- throw new Exception("Failed to bind a socket");
-
- pfd = ParcelFileDescriptor.adoptFd(fd);
-
- System.err.println(pfd);
- return pfd;
- } finally {
- System.err.println("Lorie requested fd");
- }
- }
+ List a = Arrays.asList(args);
+ try {
+ int dpiIndex = a.lastIndexOf("-dpi");
+ if (dpiIndex != -1 && a.size() >= dpiIndex)
+ dpi = Integer.parseInt(a.get(dpiIndex + 1));
+ } catch (NumberFormatException ignored) {} // No need to handle it, anyway user will see Xwayland error
- private void startXwayland() {
- try {
- boolean started = false;
- for (int i = 0; i < 200; i++) {
- if (checkWaylandSocket()) {
- started = true;
- Thread.sleep(200);
- startXwayland(args);
- break;
- }
- Thread.sleep(100);
+ try {
+ for (String arg: a)
+ if (arg.startsWith(":"))
+ display = Integer.parseInt(arg.substring(1));
+ } catch (NumberFormatException ignored) {} // No need to handle it, anyway user will see Xwayland error
+
+ spawnCompositor(display, dpi);
+ spawnListeningThread();
+ sendBroadcast();
+
+ if (!a.contains("--no-xwayland-start")) {
+ System.err.println("Starting Xwayland");
+ exec(args);
}
- if (!started)
- System.err.println("Failed to connect to Termux:X11. Something went wrong.");
- } catch (Exception e) {
- e.printStackTrace();
}
- exit(0);
}
- private void onFinish() {
- System.err.println("App sent finishing command");
- startXwayland();
- }
-
- private boolean startActivity(IBinder token) throws Throwable {
+ @SuppressLint("WrongConstant")
+ void sendBroadcast() {
+ // We should not care about multiple instances, it should be called only by `Termux:X11` app
+ // which is single instance...
Bundle bundle = new Bundle();
- bundle.putBinder("", token);
-
- Intent intent = new Intent();
- intent.putExtra("com.termux.x11.starter", bundle);
- intent.setComponent(TermuxX11Component);
-
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
- Intent.FLAG_ACTIVITY_SINGLE_TOP);
-
- int res = Compat.startActivity(intent);
-
- PrintStream out = System.err;
- boolean launched = false;
- out.println("res = " + res);
- switch (res) {
- case ActivityManager.START_SUCCESS:
- case ActivityManager.START_SWITCHES_CANCELED:
- case ActivityManager.START_DELIVERED_TO_TOP:
- case ActivityManager.START_TASK_TO_FRONT:
- launched = true;
- break;
- case ActivityManager.START_INTENT_NOT_RESOLVED:
- out.println(
- "Error: Activity not started, unable to "
- + "resolve " + intent);
- break;
- case ActivityManager.START_CLASS_NOT_FOUND:
- out.println("Error: Activity class " +
- Objects.requireNonNull(intent.getComponent()).toShortString()
- + " does not exist.");
- break;
- case ActivityManager.START_PERMISSION_DENIED:
- out.println(
- "Error: Activity not started, you do not "
- + "have permission to access it.");
- break;
- default:
- out.println(
- "Error: Activity not started, unknown error code " + res);
- break;
- }
+ bundle.putBinder("", this);
- System.err.println("Activity is" + (launched?"":" not") + " started");
+ Intent intent = new Intent(ACTION_START);
+ intent.putExtra("", bundle);
+ intent.setPackage("com.termux.x11");
- return launched;
- }
+ if (getuid() == 0 || getuid() == 2000) {
+ intent.setFlags(/* FLAG_RECEIVER_FROM_SHELL */ 0x00400000);
+ }
- private void startXwayland(String[] args) throws IOException {
- System.err.println("Starting Xwayland");
- exec(XwaylandPath, args);
+ ctx.sendBroadcast(intent);
}
- class Service extends ITermuxX11Internal.Stub {
- @Override
- public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException {
- CmdEntryPoint.this.onTransact(code, data, reply, flags);
- return super.onTransact(code, data, reply, flags);
- }
-
- @Override
- public ParcelFileDescriptor getWaylandFD() throws RemoteException {
- System.err.println("Got getWaylandFD");
- try {
- return CmdEntryPoint.this.getWaylandFD();
- } catch (Throwable e) {
- throw new RemoteException(e.getMessage());
+ void spawnListeningThread() {
+ new Thread(() -> { // New thread is needed to avoid android.os.NetworkOnMainThreadException
+ /*
+ The purpose of this function is simple. If the application has not been launched
+ before running termux-x11, the initial sendBroadcast had no effect because no one
+ received the intent. To allow the application to reconnect freely, we will listen on
+ port `PORT` and when receiving a magic phrase, we will send another intent.
+ */
+ try (ServerSocket listeningSocket =
+ new ServerSocket(PORT, 0, InetAddress.getByName("127.0.0.1"))) {
+ listeningSocket.setReuseAddress(true);
+ while(true) {
+ try (Socket client = listeningSocket.accept()) {
+ System.err.println("Somebody connected!");
+ // We should ensure that it is some
+ byte[] b = new byte[MAGIC.length];
+ DataInputStream reader = new DataInputStream(client.getInputStream());
+ reader.readFully(b);
+ if (Arrays.equals(MAGIC, b)) {
+ System.err.println("New client connection!");
+ sendBroadcast();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
}
- }
-
- @Override
- public ParcelFileDescriptor getLogFD() throws RemoteException {
- System.err.println("Got getLogFD");
- System.err.println(logFD);
- return logFD;
- }
+ }).start();
+ }
- @Override
- public void finish() throws RemoteException {
- System.err.println("Got finish request");
- handler.postDelayed(CmdEntryPoint.this::onFinish, 10);
- }
+ public static void requestConnection() {
+ System.err.println("Requesting connection...");
+ new Thread(() -> { // New thread is needed to avoid android.os.NetworkOnMainThreadException
+ try (Socket socket = new Socket("127.0.0.1", CmdEntryPoint.PORT)){
+ socket.getOutputStream().write(CmdEntryPoint.MAGIC);
+ } catch (Exception e) {
+ Log.e("CmdEntryPoint", "Something went wrong when we requested connection", e);
+ }
+ }).start();
}
- private void exit(int status) {
- exit(50, status);
+ @Override
+ public ParcelFileDescriptor getXConnection() {
+ int fd = connect();
+ return fd == -1 ? null : ParcelFileDescriptor.adoptFd(fd);
}
- private void exit(int delay, int status) {
- handler.postDelayed(() -> System.exit(status), delay);
+
+ @Override
+ public ParcelFileDescriptor getLogcatOutput() {
+ int fd = stderr();
+ return fd == -1 ? null : ParcelFileDescriptor.adoptFd(fd);
}
- private native void checkXdgRuntimeDir();
- private native int createWaylandSocket();
- private native boolean checkWaylandSocket();
- private native int openLogFD();
- private static native void exec(String path, String[] argv);
- @SuppressWarnings("FieldMayBeFinal")
- private static Handler handler = new Handler();
+ private native void spawnCompositor(int display, int dpi);
+ public native void outputResize(int width, int height);
+ private static native boolean socketExists();
+ private static native void exec(String[] argv);
+ private static native int connect();
+ private static native int stderr();
+ private static native int getuid();
static {
- System.loadLibrary("x11-starter");
+ System.loadLibrary("lorie");
}
}
diff --git a/app/src/main/java/com/termux/x11/LoriePreferences.java b/app/src/main/java/com/termux/x11/LoriePreferences.java
index 76e396d74..4e8a78ebb 100644
--- a/app/src/main/java/com/termux/x11/LoriePreferences.java
+++ b/app/src/main/java/com/termux/x11/LoriePreferences.java
@@ -1,7 +1,7 @@
package com.termux.x11;
+import android.content.Intent;
import android.content.SharedPreferences;
-import android.inputmethodservice.Keyboard;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
@@ -13,8 +13,9 @@
import android.util.Log;
import android.view.MenuItem;
-public class LoriePreferences extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
+public class LoriePreferences extends AppCompatActivity {
+ static final String ACTION_PREFERENCES_CHANGED = "com.termux.x11.ACTION_PREFERENCES_CHANGED";
static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
LoriePreferenceFragment loriePreferenceFragment;
@@ -33,21 +34,6 @@ protected void onCreate(Bundle savedInstanceState) {
}
}
- @Override
- public void onResume() {
- super.onResume();
- if (loriePreferenceFragment != null)
- loriePreferenceFragment.getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onPause() {
- if (loriePreferenceFragment != null)
- loriePreferenceFragment.getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
- super.onPause();
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
@@ -60,11 +46,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- LorieService.start(LorieService.ACTION_PREFERENCES_CHANGED);
- }
-
+ @SuppressWarnings("deprecation")
public static class LoriePreferenceFragment extends PreferenceFragment implements PreferenceScreen.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
@Override
@@ -113,6 +95,10 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
return false;
}
}
+
+ Intent intent = new Intent(ACTION_PREFERENCES_CHANGED);
+ intent.setPackage("com.termux.x11");
+ getContext().sendBroadcast(intent);
return true;
}
}
diff --git a/app/src/main/java/com/termux/x11/LorieService.java b/app/src/main/java/com/termux/x11/LorieService.java
deleted file mode 100644
index 01f94a994..000000000
--- a/app/src/main/java/com/termux/x11/LorieService.java
+++ /dev/null
@@ -1,495 +0,0 @@
-package com.termux.x11;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.graphics.PixelFormat;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.PowerManager;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.NotificationCompat;
-
-import android.util.Log;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.WindowInsets;
-import android.widget.FrameLayout;
-
-import com.termux.x11.utils.KeyboardUtils;
-import com.termux.x11.utils.SamsungDexUtils;
-
-
-@SuppressWarnings({"ConstantConditions", "SameParameterValue", "SdCardPath"})
-@SuppressLint({"ClickableViewAccessibility", "StaticFieldLeak"})
-public class LorieService extends Service implements View.OnApplyWindowInsetsListener {
- static final String LAUNCHED_BY_COMPATION = "com.termux.x11.launched_by_companion";
- static final String ACTION_STOP_SERVICE = "com.termux.x11.service_stop";
- static final String ACTION_START_FROM_ACTIVITY = "com.termux.x11.start_from_activity";
- static final String ACTION_START_PREFERENCES_ACTIVITY = "com.termux.x11.start_preferences_activity";
- static final String ACTION_PREFERENCES_CHANGED = "com.termux.x11.preferences_changed";
-
- private static LorieService instance = null;
- long compositor;
- private static final ServiceEventListener listener = new ServiceEventListener();
- private static MainActivity act;
-
- private TouchParser mTP;
-
- public LorieService(){
- instance = this;
- }
-
- static void setMainActivity(MainActivity activity) {
- act = activity;
- }
-
- static void start(String action) {
- Intent intent = new Intent(act, LorieService.class);
- intent.setAction(action);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- act.startForegroundService(intent);
- } else {
- act.startService(intent);
- }
- }
-
- @SuppressLint({"BatteryLife", "ObsoleteSdkInt"})
- @Override
- public void onCreate() {
-
- if (isServiceRunningInForeground(this, LorieService.class)) return;
-
- compositor = createLorieThread();
- if (compositor == 0) {
- Log.e("LorieService", "compositor thread was not created");
- return;
- }
-
- instance = this;
- Log.e("LorieService", "created");
-
- Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
- notificationIntent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
- notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
-
- Intent exitIntent = new Intent(getApplicationContext(), LorieService.class);
- exitIntent.setAction(ACTION_STOP_SERVICE);
-
- Intent preferencesIntent = new Intent(getApplicationContext(), LoriePreferences.class);
- preferencesIntent.setAction(ACTION_START_PREFERENCES_ACTIVITY);
-
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- PendingIntent pendingExitIntent = PendingIntent.getService(getApplicationContext(), 0, exitIntent, PendingIntent.FLAG_IMMUTABLE);
- PendingIntent pendingPreferencesIntent = PendingIntent.getActivity(getApplicationContext(), 0, preferencesIntent, PendingIntent.FLAG_IMMUTABLE);
-
- //For creating the Foreground Service
- int priority = Notification.PRIORITY_HIGH;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N)
- priority = NotificationManager.IMPORTANCE_HIGH;
- NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
- Notification notification = new NotificationCompat.Builder(this, channelId)
- .setContentTitle("Termux:X11")
- .setSmallIcon(R.drawable.ic_x11_icon)
- .setContentText("Pull down to show options")
- .setContentIntent(pendingIntent)
- .setOngoing(true)
- .setPriority(priority)
- .setShowWhen(false)
- .setColor(0xFF607D8B)
- .addAction(0, "Preferences", pendingPreferencesIntent)
- .addAction(0, "Exit", pendingExitIntent)
- .build();
- startForeground(1, notification);
-
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- String packageName = getPackageName();
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- if (!pm.isIgnoringBatteryOptimizations(packageName)) {
- Intent whitelist = new Intent();
- whitelist.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
- whitelist.setData(Uri.parse("package:" + packageName));
- whitelist.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(whitelist);
- }
- }
- }
-
- @RequiresApi(Build.VERSION_CODES.O)
- private String getNotificationChannel(NotificationManager notificationManager){
- String channelId = getResources().getString(R.string.app_name);
- String channelName = getResources().getString(R.string.app_name);
- NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
- channel.setImportance(NotificationManager.IMPORTANCE_NONE);
- channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
- notificationManager.createNotificationChannel(channel);
- return channelId;
- }
-
- public static boolean isServiceRunningInForeground(Context context, Class> serviceClass) {
- ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- if (serviceClass.getName().equals(service.service.getClassName())) {
- return service.foreground;
- }
- }
- return false;
- }
-
- private void onPreferencesChanged() {
- if (instance == null || act == null) return;
-
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(instance);
-
- int mode = Integer.parseInt(preferences.getString("touchMode", "1"));
- instance.mTP.setMode(mode);
-
- act.getWindow().getDecorView().setOnApplyWindowInsetsListener(act);
-
- if (preferences.getBoolean("showAdditionalKbd", true))
- act.kbd.setVisibility(View.VISIBLE);
- else
- act.kbd.setVisibility(View.INVISIBLE);
-
- if (preferences.getBoolean("dexMetaKeyCapture", false)) {
- SamsungDexUtils.dexMetaKeyCapture(act, false);
- }
-
- Log.e("LorieService", "Preferences changed");
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.e("LorieService", "start");
- String action = intent.getAction();
-
- if (action.equals(ACTION_START_FROM_ACTIVITY)) {
- act.onLorieServiceStart(this);
- }
-
- if (action.equals(ACTION_STOP_SERVICE)) {
- Log.e("LorieService", action);
- terminate();
- act.finish();
- stopSelf();
- }
-
- onPreferencesChanged();
-
- return START_REDELIVER_INTENT;
- }
-
- private static void sendRunCommandInternal(Context ctx) {
- Intent intent = new Intent();
- intent.setClassName("com.termux", "com.termux.app.RunCommandService");
- intent.setAction("com.termux.RUN_COMMAND");
- intent.putExtra("com.termux.RUN_COMMAND_PATH",
- "/data/data/com.termux/files/usr/libexec/termux-x11/termux-startx11");
- intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
- Log.d("LorieService", "sendRunCommand: " + intent);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- ctx.startForegroundService(intent);
- } else {
- ctx.startService(intent);
- }
- }
-
- public static void sendRunCommand(AppCompatActivity act) {
- final String ERROR_MESSAGE =
- "It is impossible to start without " +
- "com.termux.permission.RUN_COMMAND permission. " +
- "Sorry.";
- if (act.checkSelfPermission("com.termux.permission.RUN_COMMAND") == PackageManager.PERMISSION_GRANTED) {
- LorieService.sendRunCommandInternal(act);
- } else {
- Log.d("MainActivity", "We have no permission to sendRunCommand(). Requesting it.");
- ActivityResultLauncher requestPermissionLauncher =
- act.registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
- if (isGranted) {
- sendRunCommandInternal(act);
- } else {
- new AlertDialog.Builder(act)
- .setTitle("Insufficient permission")
- .setMessage(ERROR_MESSAGE)
- .setPositiveButton(android.R.string.yes,
- (dialog, which) -> act.finish())
- .setIcon(android.R.drawable.ic_dialog_alert)
- .show();
-
- }
- });
- requestPermissionLauncher.launch("com.termux.permission.RUN_COMMAND");
- }
- }
-
-
- @Override
- public void onDestroy() {
- Log.e("LorieService", "destroyed");
- }
-
- static LorieService getInstance() {
- if (instance == null) {
- Log.e("LorieService", "Instance was requested, but no instances available");
- }
- return instance;
- }
-
- void setListeners(@NonNull SurfaceView view, @NonNull SurfaceView cursor) {
- Context a = view.getRootView().findViewById(android.R.id.content).getContext();
- if (!(a instanceof MainActivity)) {
- Log.e("LorieService", "Context is not an activity!!!");
- }
-
- act = (MainActivity) a;
-
- view.setFocusable(true);
- view.setFocusableInTouchMode(true);
- view.requestFocus();
-
- listener.svc = this;
- listener.setAsListenerTo(view, cursor);
-
- mTP = new TouchParser(view, listener);
- onPreferencesChanged();
- }
-
- static View.OnKeyListener getOnKeyListener() {
- return listener;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @SuppressWarnings("SameParameterValue")
- private static class ServiceEventListener implements SurfaceHolder.Callback, View.OnTouchListener, View.OnKeyListener, View.OnHoverListener, View.OnGenericMotionListener, TouchParser.OnTouchParseListener {
- LorieService svc;
-
- @SuppressLint("WrongConstant")
- private void setAsListenerTo(SurfaceView view, SurfaceView cursor) {
- view.getHolder().addCallback(this);
- view.setOnTouchListener(this);
- view.setOnHoverListener(this);
- view.setOnGenericMotionListener(this);
- view.setOnKeyListener(this);
- surfaceChanged(view.getHolder(), PixelFormat.UNKNOWN, view.getWidth(), view.getHeight());
-
- cursor.getHolder().addCallback(new SurfaceHolder.Callback() {
- @Override public void surfaceCreated(@NonNull SurfaceHolder holder) {
- cursor.getHolder().setFormat(PixelFormat.TRANSLUCENT);
- }
- @Override
- public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
- cursor.getHolder().setFormat(PixelFormat.TRANSLUCENT);
- svc.cursorChanged(holder.getSurface());
- }
- @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
- svc.cursorChanged(null);
- }
- });
- }
-
- public void onPointerButton(int button, int state) {
- if (svc == null) return;
- svc.pointerButton(button, state);
- }
-
- public void onPointerMotion(int x, int y) {
- if (svc == null) return;
- svc.pointerMotion(x, y);
- }
-
- public void onPointerScroll(int axis, float value) {
- if (svc == null) return;
- svc.pointerScroll(axis, value);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent e) {
- if (svc == null) return false;
- return svc.mTP.onTouchEvent(e);
- }
-
- @Override
- public boolean onGenericMotion(View v, MotionEvent e) {
- if (svc == null) return false;
- return svc.mTP.onTouchEvent(e);
- }
-
- @Override
- public boolean onHover(View v, MotionEvent e) {
- if (svc == null) return false;
- return svc.mTP.onTouchEvent(e);
- }
-
- private boolean isSource(KeyEvent e, int source) {
- return (e.getSource() & source) == source;
- }
-
- private boolean rightPressed = false; // Prevent right button press event from being repeated
- private boolean middlePressed = false; // Prevent middle button press event from being repeated
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent e) {
- if (svc == null) return false;
- int action = 0;
-
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (
- isSource(e, InputDevice.SOURCE_MOUSE) &&
- rightPressed != (e.getAction() == KeyEvent.ACTION_DOWN)
- ) {
- svc.pointerButton(TouchParser.BTN_RIGHT, (e.getAction() == KeyEvent.ACTION_DOWN) ? TouchParser.ACTION_DOWN : TouchParser.ACTION_UP);
- rightPressed = (e.getAction() == KeyEvent.ACTION_DOWN);
- } else if (e.getAction() == KeyEvent.ACTION_UP) {
- KeyboardUtils.toggleKeyboardVisibility(act);
- if (act.kbd!=null)
- act.kbd.requestFocus();
-
- }
- return true;
- }
-
- if (
- keyCode == KeyEvent.KEYCODE_MENU &&
- isSource(e, InputDevice.SOURCE_MOUSE) &&
- middlePressed != (e.getAction() == KeyEvent.ACTION_DOWN)
- ) {
- svc.pointerButton(TouchParser.BTN_MIDDLE, (e.getAction() == KeyEvent.ACTION_DOWN) ? TouchParser.ACTION_DOWN : TouchParser.ACTION_UP);
- middlePressed = (e.getAction() == KeyEvent.ACTION_DOWN);
- return true;
- }
-
- if (e.getAction() == KeyEvent.ACTION_DOWN) action = TouchParser.ACTION_DOWN;
- if (e.getAction() == KeyEvent.ACTION_UP) action = TouchParser.ACTION_UP;
- svc.keyboardKey(action, keyCode, e.isShiftPressed() ? 1 : 0, e.getCharacters());
- return true;
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- svc.windowChanged(holder.getSurface(), width, height);
- }
-
- @Override public void surfaceCreated(SurfaceHolder holder) {}
- @SuppressLint("WrongConstant")
- @Override public void surfaceDestroyed(SurfaceHolder holder) {
- surfaceChanged(holder, PixelFormat.UNKNOWN, 0, 0);
- }
-
- }
-
- static void sleep(long millis) {
- try {
- Thread.sleep(millis);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- static final Handler handler = new Handler();
- private abstract static class Task implements Runnable {
- public Task() {
- handler.post(this);
- }
- @Override
- public void run() {
- LorieService svc = getInstance();
- if (svc == null || svc.compositor == 0 || act == null) {
- handler.postDelayed(this, 100);
- return;
- }
-
- run(svc);
- }
- public abstract void run(LorieService svc);
- }
-
- public static void adoptWaylandFd(int fd) {
- new Task() {
- @Override
- public void run(LorieService svc) {
- svc.passWaylandFD(fd);
- }
- };
- }
-
- @SuppressLint("WrongConstant")
- @Override
- public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- SurfaceView c = v.getRootView().findViewById(R.id.lorieView);
- SurfaceHolder h = (c != null) ? c.getHolder() : null;
- if (h != null)
- handler.postDelayed(() -> listener.surfaceChanged(h, PixelFormat.UNKNOWN, 0, 0), 100);
- return insets;
- }
-
- @SuppressWarnings("unused")
- // It is used in native code
- void setRendererVisibility(boolean visible) {
- act.runOnUiThread(()-> {
- act.findViewById(R.id.stub).setVisibility(visible?View.INVISIBLE:View.VISIBLE);
- act.findViewById(R.id.lorieView).setVisibility(visible?View.VISIBLE:View.INVISIBLE);
- });
- }
-
- @SuppressWarnings("unused")
- // It is used in native code
- void setCursorVisibility(boolean visible) {
- act.runOnUiThread(()-> act.findViewById(R.id.cursorView).setVisibility(visible?View.VISIBLE:View.INVISIBLE));
- }
-
- @SuppressWarnings("unused")
- // It is used in native code
- void setCursorRect(int x, int y, int w, int h) {
- act.runOnUiThread(()-> {
- SurfaceView v = act.findViewById(R.id.cursorView);
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(w, h);
- params.setMargins(x, y, 0, 0);
-
- v.setLayoutParams(params);
- v.setVisibility(View.VISIBLE);
- });
- }
-
- private native void cursorChanged(Surface surface);
- private native void windowChanged(Surface surface, int width, int height);
- private native void pointerMotion(int x, int y);
- private native void pointerScroll(int axis, float value);
- private native void pointerButton(int button, int type);
- private native void keyboardKey(int key, int type, int shift, String characters);
- private native void passWaylandFD(int fd);
- private native long createLorieThread();
- private native void terminate();
- public static native void startLogcatForFd(int fd);
-
- static {
- System.loadLibrary("lorie");
- }
-}
diff --git a/app/src/main/java/com/termux/x11/MainActivity.java b/app/src/main/java/com/termux/x11/MainActivity.java
index 48098b7c6..596126e2c 100644
--- a/app/src/main/java/com/termux/x11/MainActivity.java
+++ b/app/src/main/java/com/termux/x11/MainActivity.java
@@ -1,20 +1,34 @@
package com.termux.x11;
+import static com.termux.x11.CmdEntryPoint.ACTION_START;
+import static com.termux.x11.CmdEntryPoint.requestConnection;
+import static com.termux.x11.LoriePreferences.ACTION_PREFERENCES_CHANGED;
+
+import android.annotation.SuppressLint;
import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
-import android.graphics.Rect;
+import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
-import android.view.Gravity;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.PointerIcon;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
+import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -24,35 +38,37 @@
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
+import androidx.viewpager.widget.ViewPager;
+import com.termux.shared.termux.extrakeys.ExtraKeysView;
+import com.termux.x11.utils.KeyboardUtils;
import com.termux.x11.utils.PermissionUtils;
import com.termux.x11.utils.SamsungDexUtils;
+import com.termux.x11.utils.TermuxX11ExtraKeys;
+import com.termux.x11.utils.X11ToolbarViewPager;
-import static com.termux.x11.LorieService.ACTION_START_PREFERENCES_ACTIVITY;
-import static com.termux.x11.LorieService.handler;
-
-import java.util.Objects;
-public class MainActivity extends AppCompatActivity implements View.OnApplyWindowInsetsListener {
+public class MainActivity extends AppCompatActivity implements View.OnApplyWindowInsetsListener, TouchParser.OnTouchParseListener {
static final String REQUEST_LAUNCH_EXTERNAL_DISPLAY = "request_launch_external_display";
+ public static final int KeyPress = 2; // synchronized with X.h
+ public static final int KeyRelease = 3; // synchronized with X.h
- private static final int[] keys = {
- KeyEvent.KEYCODE_ESCAPE,
- KeyEvent.KEYCODE_TAB,
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_DPAD_UP,
- KeyEvent.KEYCODE_DPAD_DOWN,
- KeyEvent.KEYCODE_DPAD_LEFT,
- KeyEvent.KEYCODE_DPAD_RIGHT,
- };
-
- AdditionalKeyboardView kbd;
FrameLayout frm;
+ KeyboardUtils.KeyboardHeightProvider kbdHeightListener;
+ private TouchParser mTP;
+ private final ServiceEventListener listener = new ServiceEventListener();
+ private ICmdEntryInterface service = null;
+ public TermuxX11ExtraKeys mExtraKeys;
+ private ExtraKeysView mExtraKeysView;
+
+ private int screenWidth = 0;
+ private int screenHeight = 0;
+
+ public MainActivity() {
+ init();
+ }
- @Override
+ @SuppressLint({"AppCompatMethod", "ObsoleteSdkInt"}) @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -61,8 +77,7 @@ protected void onCreate(Bundle savedInstanceState) {
setFullScreenForExternalDisplay();
}
- LorieService.setMainActivity(this);
- LorieService.start(LorieService.ACTION_START_FROM_ACTIVITY);
+ preferences.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> onPreferencesChanged());
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
@@ -71,29 +86,101 @@ protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main_activity);
- kbd = findViewById(R.id.additionalKbd);
+ //kbd = findViewById(R.id.additionalKbd);
frm = findViewById(R.id.frame);
Button preferencesButton = findViewById(R.id.preferences_button);
preferencesButton.setOnClickListener((l) -> {
Intent i = new Intent(this, LoriePreferences.class);
- i.setAction(ACTION_START_PREFERENCES_ACTIVITY);
+ i.setAction(Intent.ACTION_MAIN);
startActivity(i);
});
+ SurfaceView lorieView = findViewById(R.id.lorieView);
+ SurfaceView cursorView = findViewById(R.id.cursorView);
+
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(1, 1);
+ cursorView.setLayoutParams(params);
+
+ listener.setAsListenerTo(lorieView, cursorView);
+
+ mTP = new TouchParser(lorieView, this);
+ setTerminalToolbarView();
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
getWindow().
getDecorView().
setPointerIcon(PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL));
- Intent i = getIntent();
- if (i != null && i.getBooleanExtra(LorieService.LAUNCHED_BY_COMPATION, false)) {
- LorieService.sendRunCommand(this);
+ IntentFilter filter = new IntentFilter(ACTION_START);
+ filter.addAction(ACTION_PREFERENCES_CHANGED);
+
+ registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_START.equals(intent.getAction())) {
+ try {
+ Log.v("LorieBroadcastReceiver", "Got new ACTION_START intent");
+ IBinder b = intent.getBundleExtra("").getBinder("");
+ service = ICmdEntryInterface.Stub.asInterface(b);
+ service.asBinder().linkToDeath(() -> {
+ service = null;
+ CmdEntryPoint.requestConnection();
+ }, 0);
+ onReceiveConnection();
+
+ ParcelFileDescriptor logcatOutput = service.getLogcatOutput();
+ if (logcatOutput != null) {
+ startLogcat(logcatOutput.detachFd());
+ }
+ } catch (Exception e) {
+ Log.e("MainActivity", "Something went wrong while we extracted connection details from binder.", e);
+ }
+ } else if (ACTION_PREFERENCES_CHANGED.equals(intent.getAction())) {
+ onPreferencesChanged();
+ }
+ }
+ }, filter);
+
+ requestConnection();
+
+ lorieView.setFocusable(true);
+ lorieView.setFocusableInTouchMode(true);
+ lorieView.requestFocus();
+ }
+
+ void onReceiveConnection() {
+ try {
+ if (service != null && service.asBinder().isBinderAlive()) {
+ Log.v("LorieBroadcastReceiver", "trying to extract X connection socket.");
+ ParcelFileDescriptor fd = service.getXConnection();
+ if (fd != null) {
+ connect(fd.detachFd());
+ service.outputResize(screenWidth, screenHeight);
+ }
+ else
+ handler.postDelayed(this::onReceiveConnection, 500);
+ }
+ } catch (Exception e) {
+ Log.e("MainActivity", "Something went wrong while we were establishing connection", e);
+ }
+ }
+
+ void onPreferencesChanged() {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ int mode = Integer.parseInt(preferences.getString("touchMode", "1"));
+ mTP.setMode(mode);
+
+ if (preferences.getBoolean("dexMetaKeyCapture", false)) {
+ SamsungDexUtils.dexMetaKeyCapture(this, false);
}
+
+ setTerminalToolbarView();
}
@Override
public void onResume() {
super.onResume();
+ nativeResume();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getBoolean("dexMetaKeyCapture", false)) {
SamsungDexUtils.dexMetaKeyCapture(this, true);
@@ -106,6 +193,9 @@ public void onPause() {
if (preferences.getBoolean("dexMetaKeyCapture", false)) {
SamsungDexUtils.dexMetaKeyCapture(this, false);
}
+
+ // We do not really need to draw while application is in background.
+ nativePause();
super.onPause();
}
@@ -117,6 +207,57 @@ public void setTheme(int resId) {
R.style.FullScreen_ExternalDisplay : R.style.NoActionBar);
}
+ public ExtraKeysView getExtraKeysView() {
+ return mExtraKeysView;
+ }
+
+ public void setExtraKeysView(ExtraKeysView extraKeysView) {
+ mExtraKeysView = extraKeysView;
+ }
+
+ public SurfaceView getLorieView() {
+ return findViewById(R.id.lorieView);
+ }
+
+ public ViewPager getTerminalToolbarViewPager() {
+ return findViewById(R.id.terminal_toolbar_view_pager);
+ }
+
+ private void setTerminalToolbarView() {
+ final ViewPager terminalToolbarViewPager = getTerminalToolbarViewPager();
+
+ terminalToolbarViewPager.setAdapter(new X11ToolbarViewPager.PageAdapter(this, listener));
+ terminalToolbarViewPager.addOnPageChangeListener(new X11ToolbarViewPager.OnPageChangeListener(this, terminalToolbarViewPager));
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean showNow = preferences.getBoolean("showAdditionalKbd", true);
+
+ terminalToolbarViewPager.setVisibility(showNow ? View.VISIBLE : View.GONE);
+ findViewById(R.id.terminal_toolbar_view_pager).requestFocus();
+
+ if (mExtraKeys == null) {
+ handler.postDelayed(() -> {
+ if (mExtraKeys != null) {
+ ViewGroup.LayoutParams layoutParams = terminalToolbarViewPager.getLayoutParams();
+ layoutParams.height = Math.round(layoutParams.height *
+ (mExtraKeys.getExtraKeysInfo() == null ? 0 : mExtraKeys.getExtraKeysInfo().getMatrix().length));
+ terminalToolbarViewPager.setLayoutParams(layoutParams);
+ }
+ }, 200);
+ }
+ }
+
+ @Override
+ public void toggleExtraKeys() {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ if (!preferences.getBoolean("showAdditionalKbd", true))
+ return;
+
+ int visibility = getTerminalToolbarViewPager().getVisibility();
+ int newVisibility = (visibility != View.VISIBLE) ? View.VISIBLE : View.GONE;
+ getTerminalToolbarViewPager().setVisibility(newVisibility);
+ }
+
private boolean didRequestLaunchExternalDisplay() {
return getIntent().getBooleanExtra(REQUEST_LAUNCH_EXTERNAL_DISPLAY, false);
}
@@ -137,24 +278,18 @@ private void setFullScreenForExternalDisplay() {
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- if (newConfig.orientation != orientation && kbd != null && kbd.getVisibility() == View.VISIBLE) {
+ if (newConfig.orientation != orientation /*&& kbd != null && kbd.getVisibility() == View.VISIBLE*/) {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
View view = getCurrentFocus();
if (view == null) {
- view = new View(this);
+ view = findViewById(R.id.lorieView);
+ view.requestFocus();
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
orientation = newConfig.orientation;
- }
-
- public void onLorieServiceStart(LorieService instance) {
- SurfaceView lorieView = findViewById(R.id.lorieView);
- SurfaceView cursorView = findViewById(R.id.cursorView);
-
- instance.setListeners(lorieView, cursorView);
- kbd.reload(keys, lorieView, LorieService.getOnKeyListener());
+ setTerminalToolbarView();
}
@Override
@@ -185,49 +320,236 @@ public void onUserLeaveHint() {
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, @NonNull Configuration newConfig) {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ ViewPager pager = getTerminalToolbarViewPager();
+ ViewGroup parent = (ViewGroup) pager.getParent();
if (isInPictureInPictureMode) {
- if (kbd.getVisibility() != View.INVISIBLE)
- kbd.setVisibility(View.INVISIBLE);
- frm.setPadding(0, 0, 0, 0);
- } else {
- if (kbd.getVisibility() != View.VISIBLE)
- if (preferences.getBoolean("showAdditionalKbd", true)) {
- kbd.setVisibility(View.VISIBLE);
- int paddingDp = 35;
- float density = this.getResources().getDisplayMetrics().density;
- int paddingPixel = (int) (paddingDp * density);
- frm.setPadding(0, 0, 0, paddingPixel);
- }
- }
+ parent.removeView(pager);
+ parent.addView(pager, 0);
+ } else
+ pager.bringToFront();
+
+ frm.setPadding(0, 0, 0, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}
}
+ @SuppressLint("WrongConstant")
@Override
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(LorieService.getInstance());
- if (preferences.getBoolean("showAdditionalKbd", true) && kbd != null) {
- handler.postDelayed(() -> {
- Rect r = new Rect();
- getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
- WindowInsetsCompat rootInsets = WindowInsetsCompat.toWindowInsetsCompat(kbd.getRootWindowInsets());
- boolean isSoftKbdVisible = rootInsets.isVisible(WindowInsetsCompat.Type.ime());
- kbd.setVisibility(isSoftKbdVisible ? View.VISIBLE : View.INVISIBLE);
-
- FrameLayout.LayoutParams p = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
- if (preferences.getBoolean("Reseed", true)) {
- p.gravity = Gravity.BOTTOM | Gravity.CENTER;
- } else {
- p.topMargin = r.bottom - r.top - kbd.getHeight();
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+// if (preferences.getBoolean("showAdditionalKbd", true) && kbd != null) {
+// handler.postDelayed(() -> {
+// Rect r = new Rect();
+// getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+// WindowInsetsCompat rootInsets = WindowInsetsCompat.toWindowInsetsCompat(kbd.getRootWindowInsets());
+// boolean isSoftKbdVisible = rootInsets.isVisible(WindowInsetsCompat.Type.ime());
+//// kbd.setVisibility(isSoftKbdVisible ? View.VISIBLE : View.INVISIBLE);
+//
+// FrameLayout.LayoutParams p = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
+// if (preferences.getBoolean("Reseed", true)) {
+// p.gravity = Gravity.BOTTOM | Gravity.CENTER;
+// } else {
+// p.topMargin = r.bottom - r.top - kbd.getHeight();
+// }
+//
+//// kbd.setLayoutParams(p);
+// }, 100);
+// }
+
+ SurfaceView c = v.getRootView().findViewById(R.id.lorieView);
+ SurfaceHolder h = (c != null) ? c.getHolder() : null;
+ if (h != null)
+ handler.postDelayed(() -> windowChanged(h.getSurface(), 0, 0), 100);
+ return insets;
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private class ServiceEventListener implements View.OnKeyListener {
+ @SuppressLint({"WrongConstant", "ClickableViewAccessibility"})
+ private void setAsListenerTo(SurfaceView view, SurfaceView cursor) {
+ view.setOnTouchListener((v, e) -> mTP.onTouchEvent(e));
+ view.setOnHoverListener((v, e) -> mTP.onTouchEvent(e));
+ view.setOnGenericMotionListener((v, e) -> mTP.onTouchEvent(e));
+ view.setOnKeyListener(this);
+ windowChanged(view.getHolder().getSurface(), view.getWidth(), view.getHeight());
+
+ cursor.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override public void surfaceCreated(@NonNull SurfaceHolder holder) {
+ cursor.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+ @Override public void surfaceChanged(@NonNull SurfaceHolder holder, int f, int w, int h) {
+ cursor.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ cursorChanged(holder.getSurface());
+ }
+ @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+ cursorChanged(null);
+ }
+ });
+
+ view.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override public void surfaceCreated(@NonNull SurfaceHolder holder) {}
+ @Override public void surfaceChanged(@NonNull SurfaceHolder holder, int f, int w, int h) {
+ windowChanged(holder.getSurface(), w, h);
+ if (service != null) {
+ try {
+ screenWidth = w;
+ screenHeight = h;
+ service.outputResize(w, h);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ @Override public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+ windowChanged(null, 0, 0);
+ }
+ });
+ }
+
+ private boolean isSource(KeyEvent e, int source) {
+ return (e.getSource() & source) == source;
+ }
+
+ private boolean rightPressed = false; // Prevent right button press event from being repeated
+ private boolean middlePressed = false; // Prevent middle button press event from being repeated
+ @SuppressWarnings("DanglingJavadoc")
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent e) {
+ // Ignoring Android's autorepeat.
+ if (e.getRepeatCount() > 0)
+ return true;
+
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (isSource(e, InputDevice.SOURCE_MOUSE) &&
+ rightPressed != (e.getAction() == KeyEvent.ACTION_DOWN)) {
+ onPointerButton(TouchParser.BTN_RIGHT, (e.getAction() == KeyEvent.ACTION_DOWN) ? TouchParser.ACTION_DOWN : TouchParser.ACTION_UP);
+ rightPressed = (e.getAction() == KeyEvent.ACTION_DOWN);
+ } else if (e.getAction() == KeyEvent.ACTION_UP) {
+ KeyboardUtils.toggleKeyboardVisibility(MainActivity.this);
+ findViewById(R.id.lorieView).requestFocus();
}
+ return true;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_MENU &&
+ isSource(e, InputDevice.SOURCE_MOUSE) &&
+ middlePressed != (e.getAction() == KeyEvent.ACTION_DOWN)) {
+ onPointerButton(TouchParser.BTN_MIDDLE, (e.getAction() == KeyEvent.ACTION_DOWN) ? TouchParser.ACTION_DOWN : TouchParser.ACTION_UP);
+ middlePressed = (e.getAction() == KeyEvent.ACTION_DOWN);
+ return true;
+ }
- kbd.setLayoutParams(p);
- }, 100);
+ /**
+ * A KeyEvent is generated in Android when the user interacts with the device's
+ * physical keyboard or software keyboard. If the KeyEvent is generated by a physical key,
+ * or a software key that has a corresponding physical key, it will contain a key code.
+ * If the key that is pressed generates a symbol, such as a letter or number,
+ * the symbol can be retrieved by calling the KeyEvent::getUnicodeChar() method.
+ * If the physical key requires the user to press the Shift key to enter the symbol,
+ * the software keyboard will emulate the Shift key press.
+ * However, in the case of a non-English keyboard layout, KeyEvent::getUnicodeChar()
+ * will not return 0 symbol for non-English keyboard layouts, keycode also will be set to 0,
+ * action will be set to KeyEvent.ACTION_MULTIPLE and the symbol data can only be retrieved
+ * by calling the KeyEvent::getCharacters() method.
+ *
+ * For special keys like Tab and Return, both the key code and Unicode symbol are set in
+ * the KeyEvent object. However, this is not the case for all keys, so to determine whether
+ * a key is special or not, we will rely only on the keycode value.
+ *
+ * Android sends emulated Shift key press event along with some key events.
+ * Since we cannot determine the event source from JNI, we ignore the emulated Shift
+ * key press in JNI. In this case, it becomes much easier to handle Shift key press events
+ * coming from a physical keyboard or ExtraKeysView.
+ *
+ * To avoid handling modifier states we will simply ignore modifier keys and
+ * ACTION_DOWN if they come from soft keyboard.
+ *
+ */
+ if (e.getDevice() == null || e.getDevice().isVirtual()) {
+ if (e.getAction() == KeyEvent.ACTION_UP || e.getAction() == KeyEvent.ACTION_MULTIPLE) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_SHIFT_LEFT:
+ case KeyEvent.KEYCODE_SHIFT_RIGHT:
+ case KeyEvent.KEYCODE_ALT_LEFT:
+ case KeyEvent.KEYCODE_ALT_RIGHT:
+ case KeyEvent.KEYCODE_CTRL_LEFT:
+ case KeyEvent.KEYCODE_CTRL_RIGHT:
+ case KeyEvent.KEYCODE_META_LEFT:
+ case KeyEvent.KEYCODE_META_RIGHT:
+ break;
+ default:
+ onKeySym(keyCode, e.getUnicodeChar(), e.getCharacters(), e.getMetaState(), 0);
+ }
+ }
+ } else
+ /**
+ * Android does not send us non-latin symbols from physical keyboard
+ * so we can trust those events and not emulate typing.
+ */
+ switch(e.getAction()) {
+ case KeyEvent.ACTION_DOWN:
+ onKeySym(keyCode, 0, null, 0, KeyPress);
+ break;
+ case KeyEvent.ACTION_UP:
+ onKeySym(keyCode, 0, null, 0, KeyRelease);
+ break;
+ }
+ return true;
}
+ }
+
+ @SuppressWarnings("unused")
+ // It is used in native code
+ void setRendererVisibility(boolean visible) {
+ runOnUiThread(()-> {
+ findViewById(R.id.stub).setVisibility(visible?View.INVISIBLE:View.VISIBLE);
+ findViewById(R.id.lorieView).setVisibility(visible?View.VISIBLE:View.INVISIBLE);
+ findViewById(R.id.cursorView).setVisibility(visible?View.VISIBLE:View.INVISIBLE);
+ });
+ }
+
+ @SuppressWarnings("unused")
+ // It is used in native code
+ void setCursorVisibility(boolean visible) {
+ View cursor = findViewById(R.id.cursorView);
+ int visibility = visible?View.VISIBLE:View.INVISIBLE;
+ if (cursor.getVisibility() != visibility)
+ runOnUiThread(()-> findViewById(R.id.cursorView).setVisibility(visibility));
+ }
+
+ @SuppressWarnings("unused")
+ // It is used in native code
+ void setCursorRect(int x, int y, int w, int h) {
+ runOnUiThread(()-> {
+ SurfaceView v = findViewById(R.id.cursorView);
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(w, h);
+ params.setMargins(x, y, 0, 0);
+
+ v.setLayoutParams(params);
+ v.setVisibility(View.VISIBLE);
+ });
+ }
+
+ public static Handler handler = new Handler();
+
+ private native void init();
+ private native void connect(int fd);
+ private native void cursorChanged(Surface surface);
+ private native void windowChanged(Surface surface, int width, int height);
+ public native void onPointerMotion(int x, int y);
+ public native void onPointerScroll(int axis, float value);
+
+ public native void onPointerButton(int button, int type);
+ public native void onKeySym(int keyCode, int unicode, String str, int metaState, int type);
+ private native void nativeResume();
+ private native void nativePause();
+
+ private native void startLogcat(int fd);
- return LorieService.getInstance().onApplyWindowInsets(v, insets);
+ static {
+ System.loadLibrary("lorie-client");
}
}
diff --git a/app/src/main/java/com/termux/x11/TermuxX11StarterReceiver.java b/app/src/main/java/com/termux/x11/TermuxX11StarterReceiver.java
deleted file mode 100644
index a27138ef9..000000000
--- a/app/src/main/java/com/termux/x11/TermuxX11StarterReceiver.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.termux.x11;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.Display;
-import android.widget.Toast;
-
-import androidx.annotation.Nullable;
-import androidx.core.hardware.display.DisplayManagerCompat;
-
-public class TermuxX11StarterReceiver extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Intent intent = getIntent();
- if (intent != null)
- handleIntent(intent);
-
- Intent launchIntent = new Intent(this, MainActivity.class);
- launchIntent.putExtra(LorieService.LAUNCHED_BY_COMPATION, true);
- launchIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-
- Bundle bundle = createLaunchParams(launchIntent);
- startActivity(launchIntent, bundle);
- finish();
- }
-
- /**
- * Creates bundle for launching on external display (if supported) and
- * adds any necessary intent flags.
- * @param launchIntent
- * @return Bundle
- */
- private Bundle createLaunchParams(Intent launchIntent) {
- Display externalDisplay = findExternalDisplay();
-
- /*
- Multi-display support was added back in Oreo, but proper keyboard / mouse input mapping to display wasn't. So we would only
- be able to view, but not interact with anything on external display. So instead, also checking to see if Android 10 desktop
- mode is enabled, which does have proper keyboard + mouse support on external displays.
- */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !hasEnabledAndroidDesktopModeSetting() || externalDisplay == null) {
- return Bundle.EMPTY;
- }
- ActivityOptions options = ActivityOptions
- .makeBasic()
- .setLaunchDisplayId(externalDisplay.getDisplayId());
-
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
- launchIntent.putExtra(MainActivity.REQUEST_LAUNCH_EXTERNAL_DISPLAY, true);
- return options.toBundle();
- }
-
- /**
- * Finds first display that is not our built-in.
- * @return - External display if found, otherwise null.
- */
- @Nullable
- private Display findExternalDisplay() {
- DisplayManagerCompat displayManager = DisplayManagerCompat.getInstance(this);
- for (Display display : displayManager.getDisplays()) {
- // id 0 is built-in screen
- if (display.getDisplayId() != 0) {
- return display;
- }
- }
- return null;
- }
-
- /**
- * Checks to see if experimental Android Desktop mode developer setting is enabled,
- * which was introduced in Android 10.
- * @return true if enabled, false otherwise
- */
- private boolean hasEnabledAndroidDesktopModeSetting() {
- try {
- int value = Settings.Global.getInt(getContentResolver(), "force_desktop_mode_on_external_displays");
- return value == 1;
- } catch (Settings.SettingNotFoundException e) {
- return false;
- }
- }
-
- private void log(String s) {
- Log.e("NewIntent", s);
- }
-
- private void handleIntent(Intent intent) {
- final String extraName = "com.termux.x11.starter";
- Bundle bundle;
- IBinder token;
- ITermuxX11Internal svc;
- ParcelFileDescriptor pfd = null;
- String toastText;
-
- // We do not use Object.equals(Object obj) for the case same intent was passed twice
- if (intent == null)
- return;
-
- toastText = intent.getStringExtra("toast");
- if (toastText != null)
- Toast.makeText(this, toastText, Toast.LENGTH_LONG).show();
-
- bundle = intent.getBundleExtra(extraName);
- if (bundle == null) {
- log("Got intent without " + extraName + " bundle");
- return;
- }
-
- token = bundle.getBinder("");
- if (token == null) {
- log("got " + extraName + " extra but it has no Binder token");
- return;
- }
-
- svc = ITermuxX11Internal.Stub.asInterface(token);
- if (svc == null) {
- log("Could not create " + extraName + " service proxy");
- return;
- }
-
- try {
- pfd = svc.getWaylandFD();
- if (pfd != null)
- LorieService.adoptWaylandFd(pfd.getFd());
- } catch (Exception e) {
- log("Failed to receive ParcelFileDescriptor");
- e.printStackTrace();
- }
-
- try {
- pfd = svc.getLogFD();
- if (pfd != null) {
- LorieService.startLogcatForFd(pfd.getFd());
- }
- } catch (Exception e) {
- log("Failed to receive ParcelFileDescriptor");
- e.printStackTrace();
- }
-
- try {
- svc.finish();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/app/src/main/java/com/termux/x11/TouchParser.java b/app/src/main/java/com/termux/x11/TouchParser.java
index a39deb22b..c0ab88f27 100644
--- a/app/src/main/java/com/termux/x11/TouchParser.java
+++ b/app/src/main/java/com/termux/x11/TouchParser.java
@@ -30,8 +30,8 @@
@SuppressWarnings("unused")
public class TouchParser {
- private static final int WL_STATE_PRESSED = 1;
- private static final int WL_STATE_RELEASED = 0;
+ private static final int XCB_BUTTON_PRESS = 4;
+ private static final int XCB_BUTTON_RELEASE = 5;
private static final int WL_POINTER_AXIS_VERTICAL_SCROLL = 0;
private static final int WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1;
@@ -39,12 +39,12 @@ public class TouchParser {
static final int TOUCH_MODE_MOUSE = 0;
static final int TOUCH_MODE_TOUCHPAD = 1;
- static final int BTN_LEFT = 0x110;
- static final int BTN_RIGHT = 0x111;
- static final int BTN_MIDDLE = 0x112;
+ static final int BTN_LEFT = 1;
+ static final int BTN_MIDDLE = 2;
+ static final int BTN_RIGHT = 3;
- static final int ACTION_DOWN = WL_STATE_PRESSED;
- static final int ACTION_UP = WL_STATE_RELEASED;
+ static final int ACTION_DOWN = XCB_BUTTON_PRESS;
+ static final int ACTION_UP = XCB_BUTTON_RELEASE;
private static final int AXIS_X = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
private static final int AXIS_Y = WL_POINTER_AXIS_VERTICAL_SCROLL;
@@ -53,6 +53,7 @@ public interface OnTouchParseListener {
void onPointerButton(int button, int state);
void onPointerMotion(int x, int y);
void onPointerScroll(int axis, float value);
+ void toggleExtraKeys();
}
private int mTouchSlopSquare;
@@ -67,6 +68,7 @@ public interface OnTouchParseListener {
private static final int TOUCH_SLOP = 8;
private static final int DOUBLE_TAP_SLOP = 100;
private static final int DOUBLE_TAP_TOUCH_SLOP = TOUCH_SLOP;
+ private static final int TRIPLE_FINGER_SWING_TRESHOLD = 10;
// constants for Message.what used by GestureHandler below
private static final int SHOW_PRESS = 1;
@@ -321,6 +323,8 @@ && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
case MotionEvent.ACTION_UP:
mStillDown = false;
+ currentTripleFingerTriggered = false;
+ currentTripleFingerScrollValue = 0;
MotionEvent currentUpEvent = MotionEvent.obtain(ev);
if (mMode == TOUCH_MODE_MOUSE) {
stopDrag();
@@ -368,6 +372,8 @@ && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
return handled;
}
+ float currentTripleFingerScrollValue = 0;
+ boolean currentTripleFingerTriggered = false;
private void onScroll(MotionEvent ev, float scrollX, float scrollY) {
if (ev.getPointerCount() == 1) {
if (mMode == TOUCH_MODE_MOUSE) {
@@ -392,6 +398,20 @@ private void onScroll(MotionEvent ev, float scrollX, float scrollY) {
mListener.onPointerScroll(MotionEvent.AXIS_Y, (int)scrollX);
if (scrollY != 0)
mListener.onPointerScroll(MotionEvent.AXIS_X, (int)scrollY);
+ } else if (ev.getPointerCount() == 3) {
+ if (currentTripleFingerTriggered)
+ return;
+
+ if (scrollY > 0)
+ currentTripleFingerScrollValue = 0; // some kind of reset
+ if (scrollY < 0)
+ currentTripleFingerScrollValue -= scrollY;
+
+ if (currentTripleFingerScrollValue < -30 || currentTripleFingerScrollValue > 30) {
+ mListener.toggleExtraKeys();
+ currentTripleFingerScrollValue = 0;
+ currentTripleFingerTriggered = true;
+ }
}
}
diff --git a/app/src/main/java/com/termux/x11/starter/ActivityManager.java b/app/src/main/java/com/termux/x11/starter/ActivityManager.java
deleted file mode 100644
index 5f2d96597..000000000
--- a/app/src/main/java/com/termux/x11/starter/ActivityManager.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package com.termux.x11.starter;
-
-/**
- * \@hide-hidden constants
- */
-public class ActivityManager {
- private static final int FIRST_START_FATAL_ERROR_CODE = -100;
- private static final int LAST_START_FATAL_ERROR_CODE = -1;
- private static final int FIRST_START_SUCCESS_CODE = 0;
- private static final int LAST_START_SUCCESS_CODE = 99;
- private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100;
- private static final int LAST_START_NON_FATAL_ERROR_CODE = 199;
-
- /**
- * Result for IActivityManager.startVoiceActivity: active session is currently hidden.
- * @hide
- */
- public static final int START_VOICE_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE;
-
- /**
- * Result for IActivityManager.startVoiceActivity: active session does not match
- * the requesting token.
- * @hide
- */
- public static final int START_VOICE_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 1;
-
- /**
- * Result for IActivityManager.startActivity: trying to start a background user
- * activity that shouldn't be displayed for all users.
- * @hide
- */
- public static final int START_NOT_CURRENT_USER_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 2;
-
- /**
- * Result for IActivityManager.startActivity: trying to start an activity under voice
- * control when that activity does not support the VOICE category.
- * @hide
- */
- public static final int START_NOT_VOICE_COMPATIBLE = FIRST_START_FATAL_ERROR_CODE + 3;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * start had to be canceled.
- * @hide
- */
- public static final int START_CANCELED = FIRST_START_FATAL_ERROR_CODE + 4;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * thing being started is not an activity.
- * @hide
- */
- public static final int START_NOT_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 5;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * caller does not have permission to start the activity.
- * @hide
- */
- public static final int START_PERMISSION_DENIED = FIRST_START_FATAL_ERROR_CODE + 6;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * caller has requested both to forward a result and to receive
- * a result.
- * @hide
- */
- public static final int START_FORWARD_AND_REQUEST_CONFLICT = FIRST_START_FATAL_ERROR_CODE + 7;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * requested class is not found.
- * @hide
- */
- public static final int START_CLASS_NOT_FOUND = FIRST_START_FATAL_ERROR_CODE + 8;
-
- /**
- * Result for IActivityManager.startActivity: an error where the
- * given Intent could not be resolved to an activity.
- * @hide
- */
- public static final int START_INTENT_NOT_RESOLVED = FIRST_START_FATAL_ERROR_CODE + 9;
-
- /**
- * Result for IActivityManager.startAssistantActivity: active session is currently hidden.
- * @hide
- */
- public static final int START_ASSISTANT_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE + 10;
-
- /**
- * Result for IActivityManager.startAssistantActivity: active session does not match
- * the requesting token.
- * @hide
- */
- public static final int START_ASSISTANT_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 11;
-
- /**
- * Result for IActivityManaqer.startActivity: the activity was started
- * successfully as normal.
- * @hide
- */
- public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE;
-
- /**
- * Result for IActivityManaqer.startActivity: the caller asked that the Intent not
- * be executed if it is the recipient, and that is indeed the case.
- * @hide
- */
- public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1;
-
- /**
- * Result for IActivityManaqer.startActivity: activity wasn't really started, but
- * a task was simply brought to the foreground.
- * @hide
- */
- public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2;
-
- /**
- * Result for IActivityManaqer.startActivity: activity wasn't really started, but
- * the given Intent was given to the existing top activity.
- * @hide
- */
- public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3;
-
- /**
- * Result for IActivityManaqer.startActivity: request was canceled because
- * app switches are temporarily canceled to ensure the user's last request
- * (such as pressing home) is performed.
- * @hide
- */
- public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE;
-
- /**
- * Result for IActivityManaqer.startActivity: a new activity was attempted to be started
- * while in Lock Task Mode.
- * @hide
- */
- public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION =
- FIRST_START_NON_FATAL_ERROR_CODE + 1;
-
- /**
- * Result for IActivityManaqer.startActivity: a new activity start was aborted. Never returned
- * externally.
- * @hide
- */
- public static final int START_ABORTED = FIRST_START_NON_FATAL_ERROR_CODE + 2;
-
- /**
- * Flag for IActivityManaqer.startActivity: do special start mode where
- * a new activity is launched only if it is needed.
- * @hide
- */
- public static final int START_FLAG_ONLY_IF_NEEDED = 1<<0;
-
- /**
- * Flag for IActivityManaqer.startActivity: launch the app for
- * debugging.
- * @hide
- */
- public static final int START_FLAG_DEBUG = 1<<1;
-
- /**
- * Flag for IActivityManaqer.startActivity: launch the app for
- * allocation tracking.
- * @hide
- */
- public static final int START_FLAG_TRACK_ALLOCATION = 1<<2;
-
- /**
- * Flag for IActivityManaqer.startActivity: launch the app with
- * native debugging support.
- * @hide
- */
- public static final int START_FLAG_NATIVE_DEBUGGING = 1<<3;
-
- /**
- * Result for IActivityManaqer.broadcastIntent: success!
- * @hide
- */
- public static final int BROADCAST_SUCCESS = 0;
-
- /**
- * Result for IActivityManaqer.broadcastIntent: attempt to broadcast
- * a sticky intent without appropriate permission.
- * @hide
- */
- public static final int BROADCAST_STICKY_CANT_HAVE_PERMISSION = -1;
-
- /**
- * Result for IActivityManager.broadcastIntent: trying to send a broadcast
- * to a stopped user. Fail.
- * @hide
- */
- public static final int BROADCAST_FAILED_USER_STOPPED = -2;
-
-
-}
diff --git a/app/src/main/java/com/termux/x11/starter/Compat.java b/app/src/main/java/com/termux/x11/starter/Compat.java
deleted file mode 100644
index 0524d1638..000000000
--- a/app/src/main/java/com/termux/x11/starter/Compat.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.termux.x11.starter;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManagerNative;
-import android.app.ActivityTaskManager;
-import android.app.AppOpsManager;
-import android.app.IActivityManager;
-import android.app.IActivityTaskManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.Process;
-
-import com.android.internal.app.IAppOpsService;
-
-import java.lang.reflect.InvocationTargetException;
-
-public class Compat {
- public static final String callingPackage = "com.termux";
- public static int startActivity(Intent i) {
- try {
- if (Build.VERSION.SDK_INT >= 30) {
- IActivityTaskManager taskManager = ActivityTaskManager.getService();
- return taskManager.startActivity(null, callingPackage, null, i, null, null, null, -1, 0, null, null);
- } else if (Build.VERSION.SDK_INT == 29) {
- IActivityTaskManager taskManager = ActivityTaskManager.getService();
- return taskManager.startActivity(null, callingPackage, i, null, null, null, -1, 0, null, null);
- } else {
- IActivityManager activityManager;
- IBinder binder = ServiceManager.getService("activity");
- if (Build.VERSION.SDK_INT >= 26)
- activityManager = IActivityManager.Stub.asInterface(binder);
- else
- activityManager = ActivityManagerNative.asInterface(binder);
-
- return activityManager.startActivityAsUser(null, callingPackage, i, null, null, null, -1, 0, null, null, 0);
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- return ActivityManager.START_PERMISSION_DENIED;
- }
-
- @SuppressWarnings({"JavaReflectionMemberAccess", "SameParameterValue"})
- @SuppressLint("PrivateApi")
- public static boolean havePermission(String permission) {
- try {
- // We do not need Context to use checkOpNoThrow/unsafeCheckOpNoThrow so it can be null
- IBinder binder = ServiceManager.getService("appops");
- IAppOpsService service = IAppOpsService.Stub.asInterface(binder);
- AppOpsManager appops = (AppOpsManager) Class.forName("android.app.AppOpsManager")
- .getDeclaredConstructor(Context.class, IAppOpsService.class)
- .newInstance(null, service);
-
- if (appops == null) return false;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- int allowed;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- allowed = appops.unsafeCheckOpNoThrow(permission, Process.myUid(), callingPackage);
- } else {
- allowed = appops.checkOpNoThrow(permission, Process.myUid(), callingPackage);
- }
-
- return (allowed == AppOpsManager.MODE_ALLOWED);
- } else {
- return false;
- }
- } catch ( ClassNotFoundException | NoSuchMethodException | IllegalAccessException
- | InstantiationException | InvocationTargetException e) {
- e.printStackTrace();
- }
- return false;
- }
-}
diff --git a/app/src/main/java/com/termux/x11/utils/KeyboardUtils.java b/app/src/main/java/com/termux/x11/utils/KeyboardUtils.java
index cfc408b71..0ad4cbc86 100644
--- a/app/src/main/java/com/termux/x11/utils/KeyboardUtils.java
+++ b/app/src/main/java/com/termux/x11/utils/KeyboardUtils.java
@@ -1,12 +1,19 @@
package com.termux.x11.utils;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.content.Context;
+import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
import java.util.HashMap;
@@ -25,15 +32,13 @@ public class KeyboardUtils implements ViewTreeObserver.OnGlobalLayoutListener
private float mScreenDensity;
private static HashMap sListenerMap = new HashMap<>();
- public interface SoftKeyboardToggleListener
- {
+ public interface SoftKeyboardToggleListener {
void onToggleSoftKeyboard(boolean isVisible);
}
@Override
- public void onGlobalLayout()
- {
+ public void onGlobalLayout() {
Rect r = new Rect();
mRootView.getWindowVisibleDisplayFrame(r);
@@ -52,8 +57,7 @@ public void onGlobalLayout()
* @param act calling activity
* @param listener callback
*/
- public static void addKeyboardToggleListener(Activity act, SoftKeyboardToggleListener listener)
- {
+ public static void addKeyboardToggleListener(Activity act, SoftKeyboardToggleListener listener) {
removeKeyboardToggleListener(listener);
sListenerMap.put(listener, new KeyboardUtils(act, listener));
@@ -63,8 +67,7 @@ public static void addKeyboardToggleListener(Activity act, SoftKeyboardToggleLis
* Remove a registered listener
* @param listener {@link SoftKeyboardToggleListener}
*/
- public static void removeKeyboardToggleListener(SoftKeyboardToggleListener listener)
- {
+ public static void removeKeyboardToggleListener(SoftKeyboardToggleListener listener) {
if(sListenerMap.containsKey(listener))
{
KeyboardUtils k = sListenerMap.get(listener);
@@ -77,8 +80,7 @@ public static void removeKeyboardToggleListener(SoftKeyboardToggleListener liste
/**
* Remove all registered keyboard listeners
*/
- public static void removeAllKeyboardToggleListeners()
- {
+ public static void removeAllKeyboardToggleListeners() {
for(SoftKeyboardToggleListener l : sListenerMap.keySet())
sListenerMap.get(l).removeListener();
@@ -89,8 +91,7 @@ public static void removeAllKeyboardToggleListeners()
* Manually toggle soft keyboard visibility
* @param context calling context
*/
- public static void toggleKeyboardVisibility(Context context)
- {
+ public static void toggleKeyboardVisibility(Context context) {
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if(inputMethodManager != null)
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
@@ -100,23 +101,20 @@ public static void toggleKeyboardVisibility(Context context)
* Force closes the soft keyboard
* @param activeView the view with the keyboard focus
*/
- public void forceCloseKeyboard(View activeView)
- {
+ public void forceCloseKeyboard(View activeView) {
InputMethodManager inputMethodManager = (InputMethodManager) activeView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if(inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(activeView.getWindowToken(), 0);
- }
+ }
}
- private void removeListener()
- {
+ private void removeListener() {
mCallback = null;
mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
- private KeyboardUtils(Activity act, SoftKeyboardToggleListener listener)
- {
+ private KeyboardUtils(Activity act, SoftKeyboardToggleListener listener) {
mCallback = listener;
mRootView = ((ViewGroup) act.findViewById(android.R.id.content)).getChildAt(0);
@@ -124,5 +122,48 @@ private KeyboardUtils(Activity act, SoftKeyboardToggleListener listener)
mScreenDensity = act.getResources().getDisplayMetrics().density;
}
+ public static class KeyboardHeightProvider extends PopupWindow {
+ public KeyboardHeightProvider(Context context, WindowManager windowManager, View parentView, KeyboardHeightListener listener) {
+ super(context);
+
+ LinearLayout popupView = new LinearLayout(context);
+ popupView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ popupView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
+ DisplayMetrics metrics = new DisplayMetrics();
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+
+ Rect rect = new Rect();
+ popupView.getWindowVisibleDisplayFrame(rect);
+
+ int keyboardHeight = metrics.heightPixels - (rect.bottom - rect.top);
+ @SuppressLint("InternalInsetResource")
+ int resourceID = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceID > 0) {
+ keyboardHeight -= context.getResources().getDimensionPixelSize(resourceID);
+ }
+ if (keyboardHeight < 100) {
+ keyboardHeight = 0;
+ }
+ boolean isLandscape = metrics.widthPixels > metrics.heightPixels;
+ boolean keyboardOpen = keyboardHeight > 0;
+ if (listener != null) {
+ listener.onKeyboardHeightChanged(keyboardHeight, keyboardOpen, isLandscape);
+ }
+ });
+
+ setContentView(popupView);
+
+ setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+ setWidth(0);
+ setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
+ setBackgroundDrawable(new ColorDrawable(0));
+
+ parentView.post(() -> showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0));
+ }
+ }
+ public interface KeyboardHeightListener {
+ void onKeyboardHeightChanged(int keyboardHeight, boolean keyboardOpen, boolean isLandscape);
+ }
}
diff --git a/app/src/main/java/com/termux/x11/utils/TermuxX11ExtraKeys.java b/app/src/main/java/com/termux/x11/utils/TermuxX11ExtraKeys.java
new file mode 100644
index 000000000..74c648ab9
--- /dev/null
+++ b/app/src/main/java/com/termux/x11/utils/TermuxX11ExtraKeys.java
@@ -0,0 +1,195 @@
+package com.termux.x11.utils;
+
+import static com.termux.shared.termux.extrakeys.ExtraKeysConstants.PRIMARY_KEY_CODES_FOR_STRINGS;
+import static com.termux.x11.MainActivity.KeyPress;
+import static com.termux.x11.MainActivity.KeyRelease;
+
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.material.button.MaterialButton;
+import com.termux.shared.logger.Logger;
+import com.termux.shared.termux.extrakeys.ExtraKeyButton;
+import com.termux.shared.termux.extrakeys.ExtraKeysConstants;
+import com.termux.shared.termux.extrakeys.ExtraKeysInfo;
+import com.termux.shared.termux.extrakeys.ExtraKeysView;
+import com.termux.shared.termux.extrakeys.SpecialButton;
+import com.termux.shared.termux.settings.properties.TermuxPropertyConstants;
+import com.termux.x11.LoriePreferences;
+import com.termux.x11.MainActivity;
+import com.termux.x11.R;
+
+import org.json.JSONException;
+
+public class TermuxX11ExtraKeys implements ExtraKeysView.IExtraKeysView {
+
+ private final View.OnKeyListener mEventListener;
+ private final MainActivity mActivity;
+ private final ExtraKeysView mExtraKeysView;
+ private ExtraKeysInfo mExtraKeysInfo;
+
+ private boolean ctrlDown;
+ private boolean altDown;
+ private boolean shiftDown;
+
+ public TermuxX11ExtraKeys(@NonNull View.OnKeyListener eventlistener, MainActivity activity, ExtraKeysView extrakeysview) {
+ mEventListener = eventlistener;
+ mActivity = activity;
+ mExtraKeysView = extrakeysview;
+ }
+
+ private final KeyCharacterMap mVirtualKeyboardKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ static final String ACTION_START_PREFERENCES_ACTIVITY = "com.termux.x11.start_preferences_activity";
+
+ @Override
+ public void onExtraKeyButtonClick(View view, ExtraKeyButton buttonInfo, MaterialButton button) {
+ Log.e("keys", "key " + buttonInfo.getDisplay());
+ if (buttonInfo.isMacro()) {
+ String[] keys = buttonInfo.getKey().split(" ");
+ boolean ctrlDown = false;
+ boolean altDown = false;
+ boolean shiftDown = false;
+ boolean fnDown = false;
+ for (String key : keys) {
+ if (SpecialButton.CTRL.getKey().equals(key)) {
+ ctrlDown = true;
+ } else if (SpecialButton.ALT.getKey().equals(key)) {
+ altDown = true;
+ } else if (SpecialButton.SHIFT.getKey().equals(key)) {
+ shiftDown = true;
+ } else if (SpecialButton.FN.getKey().equals(key)) {
+ fnDown = true;
+ } else {
+ ctrlDown = false;
+ altDown = false;
+ shiftDown = false;
+ fnDown = false;
+ }
+ onLorieExtraKeyButtonClick(view, key, ctrlDown, altDown, shiftDown, fnDown);
+ }
+ } else {
+ onLorieExtraKeyButtonClick(view, buttonInfo.getKey(), false, false, false, false);
+ }
+ }
+
+ protected void onTerminalExtraKeyButtonClick(View view, String key, boolean ctrlDown, boolean altDown, boolean shiftDown, boolean fnDown) {
+ if (this.ctrlDown != ctrlDown) {
+ this.ctrlDown = ctrlDown;
+ mActivity.onKeySym(KeyEvent.KEYCODE_CTRL_LEFT, 0, null, 0, ctrlDown ? KeyPress : KeyRelease);
+ }
+
+ if (this.altDown != altDown) {
+ this.altDown = altDown;
+ mActivity.onKeySym(KeyEvent.KEYCODE_ALT_LEFT, 0, null, 0, altDown ? KeyPress : KeyRelease);
+ }
+
+ if (this.shiftDown != shiftDown) {
+ this.shiftDown = shiftDown;
+ mActivity.onKeySym(KeyEvent.KEYCODE_SHIFT_LEFT, 0, null, 0, shiftDown ? KeyPress : KeyRelease);
+ }
+
+ if (PRIMARY_KEY_CODES_FOR_STRINGS.containsKey(key)) {
+ Integer keyCode = PRIMARY_KEY_CODES_FOR_STRINGS.get(key);
+ if (keyCode == null) return;
+
+ mActivity.onKeySym(keyCode, 0, null, 0, 0);
+ } else {
+ // not a control char
+ key.codePoints().forEach(codePoint -> mActivity.onKeySym(0, codePoint, null, 0, 0));
+ }
+ }
+
+ @Override
+ public boolean performExtraKeyButtonHapticFeedback(View view, ExtraKeyButton buttonInfo, MaterialButton button) {
+ MainActivity.handler.postDelayed(() -> {
+ int pressed;
+ switch (buttonInfo.getKey()) {
+ case "CTRL":
+ pressed = Boolean.TRUE.equals(mExtraKeysView.readSpecialButton(SpecialButton.CTRL, false))
+ ? KeyPress : KeyRelease;
+ mActivity.onKeySym(KeyEvent.KEYCODE_CTRL_LEFT, 0, null, 0, pressed);
+ break;
+ case "ALT":
+ pressed = Boolean.TRUE.equals(mExtraKeysView.readSpecialButton(SpecialButton.ALT, false))
+ ? KeyPress : KeyRelease;
+ mActivity.onKeySym(KeyEvent.KEYCODE_ALT_LEFT, 0, null, 0, pressed);
+ break;
+ case "SHIFT":
+ pressed = Boolean.TRUE.equals(mExtraKeysView.readSpecialButton(SpecialButton.SHIFT, false))
+ ? KeyPress : KeyRelease;
+ mActivity.onKeySym(KeyEvent.KEYCODE_SHIFT_LEFT, 0, null, 0, pressed);
+ break;
+ }
+ }, 100);
+
+ return false;
+ }
+
+ public void paste(CharSequence input) {
+ KeyEvent[] events = mVirtualKeyboardKeyCharacterMap.getEvents(input.toString().toCharArray());
+ if (events != null) {
+ for (KeyEvent event : events) {
+ int keyCode = event.getKeyCode();
+ mEventListener.onKey(mActivity.getLorieView(), keyCode, event);
+ }
+ }
+ }
+
+ private ViewPager getToolbarViewPager() {
+ return mActivity.findViewById(R.id.terminal_toolbar_view_pager);
+ }
+
+ @SuppressLint("RtlHardcoded")
+ public void onLorieExtraKeyButtonClick(View view, String key, boolean ctrlDown, boolean altDown, boolean shiftDown, boolean fnDown) {
+ if ("KEYBOARD".equals(key)) {
+ if (getToolbarViewPager()!=null) {
+ getToolbarViewPager().requestFocus();
+ KeyboardUtils.toggleKeyboardVisibility(mActivity);
+ }
+ } else if ("DRAWER".equals(key)) {
+ Intent preferencesIntent = new Intent(mActivity, LoriePreferences.class);
+ preferencesIntent.setAction(ACTION_START_PREFERENCES_ACTIVITY);
+ mActivity.startActivity(preferencesIntent);
+ } else if ("PASTE".equals(key)) {
+ ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clipData = clipboard.getPrimaryClip();
+ if (clipData != null) {
+ CharSequence pasted = clipData.getItemAt(0).coerceToText(mActivity);
+ if (!TextUtils.isEmpty(pasted)) paste(pasted);
+ }
+ } else {
+ onTerminalExtraKeyButtonClick(view, key, ctrlDown, altDown, shiftDown, fnDown);
+ }
+ }
+
+ /**
+ * Set the terminal extra keys and style.
+ */
+ private void setExtraKeys() {
+ mExtraKeysInfo = null;
+ try {
+ mExtraKeysInfo = new ExtraKeysInfo(TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS, TermuxPropertyConstants.DEFAULT_IVALUE_EXTRA_KEYS_STYLE, ExtraKeysConstants.CONTROL_CHARS_ALIASES);
+ } catch (JSONException e2) {
+ Logger.showToast(mActivity, "Can't create default extra keys",true);
+ Logger.logStackTraceWithMessage("TermuxX11ExtraKeys", "Could create default extra keys: ", e2);
+ mExtraKeysInfo = null;
+ }
+ }
+
+ public ExtraKeysInfo getExtraKeysInfo() {
+ if (mExtraKeysInfo == null)
+ setExtraKeys();
+ return mExtraKeysInfo;
+ }
+}
diff --git a/app/src/main/java/com/termux/x11/utils/X11ToolbarViewPager.java b/app/src/main/java/com/termux/x11/utils/X11ToolbarViewPager.java
new file mode 100644
index 000000000..9fce33efe
--- /dev/null
+++ b/app/src/main/java/com/termux/x11/utils/X11ToolbarViewPager.java
@@ -0,0 +1,102 @@
+package com.termux.x11.utils;
+
+import android.view.InputDevice;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.KeyEvent;
+import android.view.KeyCharacterMap;
+
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.termux.shared.termux.extrakeys.ExtraKeysView;
+import com.termux.x11.MainActivity;
+import com.termux.x11.R;
+
+public class X11ToolbarViewPager {
+ public static class PageAdapter extends PagerAdapter {
+
+ final MainActivity act;
+ private final View.OnKeyListener mEventListener;
+ private final KeyCharacterMap mVirtualKeyboardKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+
+ public PageAdapter(MainActivity activity, View.OnKeyListener listen) {
+ this.act = activity;
+ this.mEventListener = listen;
+ }
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
+ return view == object;
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup collection, int position) {
+ LayoutInflater inflater = LayoutInflater.from(act);
+ View layout;
+ if (position == 0) {
+ layout = inflater.inflate(R.layout.view_terminal_toolbar_extra_keys, collection, false);
+ ExtraKeysView extraKeysView = (ExtraKeysView) layout;
+ act.mExtraKeys = new TermuxX11ExtraKeys(mEventListener, act, extraKeysView);
+ int mTerminalToolbarDefaultHeight = act.getTerminalToolbarViewPager().getLayoutParams().height;
+ int height = mTerminalToolbarDefaultHeight *
+ ((act.mExtraKeys.getExtraKeysInfo() == null) ? 0 : act.mExtraKeys.getExtraKeysInfo().getMatrix().length);
+ extraKeysView.reload(act.mExtraKeys.getExtraKeysInfo(), height);
+ extraKeysView.setExtraKeysViewClient(act.mExtraKeys);
+ act.setExtraKeysView(extraKeysView);
+ } else {
+ layout = inflater.inflate(R.layout.view_terminal_toolbar_text_input, collection, false);
+ final EditText editText = layout.findViewById(R.id.terminal_toolbar_text_input);
+
+ editText.setOnEditorActionListener((v, actionId, event) -> {
+ String textToSend = editText.getText().toString();
+ if (textToSend.length() == 0) textToSend = "\r";
+ KeyEvent e = new KeyEvent(0, textToSend, KeyCharacterMap.VIRTUAL_KEYBOARD, 0);
+ mEventListener.onKey(act.getLorieView(), 0, e);
+
+ editText.setText("");
+ return true;
+ });
+ }
+ collection.addView(layout);
+ return layout;
+ }
+
+ @Override
+ public void destroyItem(@NonNull ViewGroup collection, int position, @NonNull Object view) {
+ collection.removeView((View) view);
+ }
+
+ }
+
+ public static class OnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
+
+ final MainActivity act;
+ final ViewPager mTerminalToolbarViewPager;
+
+ public OnPageChangeListener(MainActivity activity, ViewPager viewPager) {
+ this.act = activity;
+ this.mTerminalToolbarViewPager = viewPager;
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (position == 0) {
+ act.getLorieView().requestFocus();
+ } else {
+ final EditText editText = mTerminalToolbarViewPager.findViewById(R.id.terminal_toolbar_text_input);
+ if (editText != null) editText.requestFocus();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
deleted file mode 100644
index 1714bd259..000000000
--- a/app/src/main/jni/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-ROOT_PATH := $(call my-dir)
-include $(ROOT_PATH)/lorie/Android.mk
-include $(ROOT_PATH)/starter/Android.mk
-
-LOCAL_PATH:= $(ROOT_PATH)/wayland/src
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := wayland-server
-LOCAL_SRC_FILES := \
- connection.c \
- event-loop.c \
- wayland-protocol.c \
- wayland-server.c \
- wayland-shm.c \
- wayland-os.c \
- wayland-util.c
-
-#LOCAL_SRC_FILES += ../../lorie/utils/log.cpp
-#LOCAL_CFLAGS := -finstrument-functions
-#LOCAL_LDFLAGS := -llog
-
-LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/..
-include $(BUILD_SHARED_LIBRARY)
diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk
deleted file mode 100644
index ce095350e..000000000
--- a/app/src/main/jni/Application.mk
+++ /dev/null
@@ -1 +0,0 @@
-APP_STL := c++_static
diff --git a/app/src/main/jni/lorie/android.cpp b/app/src/main/jni/lorie/android.cpp
deleted file mode 100644
index bf5ceb7d4..000000000
--- a/app/src/main/jni/lorie/android.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-#include
-#include "lorie_compositor.hpp"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#define DEFAULT_DPI 96
-
-#pragma ide diagnostic ignored "hicpp-signed-bitwise"
-#define unused __attribute__((__unused__))
-#define always_inline __attribute__((always_inline)) inline
-
-JavaVM *vm{};
-
-jfieldID lorie_compositor::compositor_field_id{};
-
-lorie_compositor::lorie_compositor(jobject thiz): lorie_compositor() {
- this->thiz = thiz;
- self = std::thread([=, this]{
- vm->AttachCurrentThread(&env, nullptr);
- compositor_field_id = env->GetFieldID(env->GetObjectClass(thiz), "compositor", "J");
- set_renderer_visibility_id = env->GetMethodID(env->GetObjectClass(thiz), "setRendererVisibility", "(Z)V");
- set_cursor_visibility_id = env->GetMethodID(env->GetObjectClass(thiz), "setCursorVisibility", "(Z)V");
- set_cursor_rect_id =env->GetMethodID( env->GetObjectClass(thiz), "setCursorRect", "(IIII)V");
-
- set_renderer_visibility = [=](bool visible) {
- env->CallVoidMethod(thiz, set_renderer_visibility_id, visible);
- };
-
- set_cursor_visibility = [=](JNIEnv* jenv, bool visible) {
- jenv->CallVoidMethod(thiz, set_cursor_visibility_id, visible);
- if (!visible || !screen.sfc)
- set_cursor_position = [=](JNIEnv*, int, int) {};
- else
- set_cursor_position = [=](JNIEnv* jenv, int x, int y) {
- if (!cursor.sfc)
- return;
- auto data = cursor.sfc ? any_cast(cursor.sfc->user_data()) : nullptr;
- auto b = data->buffer ?: nullptr;
- int sx = x - cursor.hotspot_x;
- int sy = y - cursor.hotspot_y;
- int w = b ? b->shm_width() : 0;
- int h = b ? b->shm_height() : 0;
- jenv->CallVoidMethod(thiz, set_cursor_rect_id, sx, sy, w, h);
- };
- };
-
- run();
-
- vm->DetachCurrentThread();
- });
-}
-
-__asm__ (
- " .global blob\n"
- " .global blob_size\n"
- " .section .rodata\n"
- " blob:\n"
- " .incbin \"en_us.xkbmap\"\n"
- " 1:\n"
- " blob_size:\n"
- " .int 1b - blob"
-);
-
-extern jbyte blob[];
-extern int blob_size;
-
-void lorie_compositor::get_keymap(int *fd, int *size) { // NOLINT(readability-convert-member-functions-to-static)
- int keymap_fd = os_create_anonymous_file(blob_size);
- void *dest = mmap(nullptr, blob_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymap_fd, 0);
- memcpy(dest, blob, blob_size);
- munmap(dest, blob_size);
-
- struct stat s = {};
- fstat(keymap_fd, &s);
- *size = s.st_size; // NOLINT(cppcoreguidelines-narrowing-conversions)
- *fd = keymap_fd;
-}
-
-// For some reason both static_cast and reinterpret_cast returning 0 when casting b.bits.
-static always_inline uint32_t* cast(void* p) { union { void* a; uint32_t* b; } c {p}; return c.b; } // NOLINT(cppcoreguidelines-pro-type-member-init)
-
-static always_inline void blit_exact(EGLNativeWindowType win, const uint32_t* src, int width, int height) {
- if (width == 0 || height == 0) {
- width = ANativeWindow_getWidth(win);
- height = ANativeWindow_getHeight(win);
- }
- ARect bounds{ 0, 0, width, height };
- ANativeWindow_Buffer b{};
-
- ANativeWindow_acquire(win);
- auto ret = ANativeWindow_setBuffersGeometry(win, width, height, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
- if (ret != 0) {
- LOGE("Failed to set buffers geometry (%d)", ret);
- return;
- }
-
- ret = ANativeWindow_lock(win, &b, &bounds);
- if (ret != 0) {
- LOGE("Failed to lock");
- return;
- }
-
- uint32_t* dst = cast(b.bits);
- if (src) {
- for (int i = 0; i < height; i++) {
- for (int j = 0; j < width; j++) {
- uint32_t s = src[width * i + j];
- // Cast BGRA to RGBA
- dst[b.stride * i + j] = (s & 0xFF000000) | ((s & 0x00FF0000) >> 16) | (s & 0x0000FF00) | ((s & 0x000000FF) << 16);
- }
- }
- } else
- memset(dst, 0, b.stride*b.height);
-
- ret = ANativeWindow_unlockAndPost(win);
- if (ret != 0) {
- LOGE("Failed to post");
- return;
- }
-
- ANativeWindow_release(win);
-}
-
-void lorie_compositor::blit(EGLNativeWindowType win, wayland::surface_t* sfc) {
- if (!win)
- return;
-
- auto buffer = sfc ? any_cast(sfc->user_data())->buffer : nullptr;
- if (buffer && buffer->is_shm() && buffer->shm_data())
- blit_exact(win, cast(buffer->shm_data()), buffer->shm_width(), buffer->shm_height());
- else
- blit_exact(win, nullptr, 0, 0);
-}
-
-template struct wrapper_impl;
-template
-struct wrapper_impl {
- // Be careful and do passing jobjects here!!!
- [[maybe_unused]] static always_inline R execute(JNIEnv* env, jobject obj, A... args) {
- auto native = lorie_compositor::compositor_field_id ? reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) : nullptr;
- if (native != nullptr)
- return (native->*f)(args...);
- return static_cast(defaultValue);
- }
-
- [[maybe_unused]] static always_inline void queue(JNIEnv* env, jobject obj, A... args) {
- auto native = lorie_compositor::compositor_field_id ? reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) : nullptr;
- if (native != nullptr)
- native->post([=]{ (native->*f)(args...); });
- }
-};
-template
-auto execute = wrapper_impl::execute;
-template
-auto queue = wrapper_impl::queue;
-
-[[maybe_unused]] static always_inline lorie_compositor* get(JNIEnv* env, jobject obj) {
- return lorie_compositor::compositor_field_id ?
- reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id)) :
- nullptr;
-}
-
-///////////////////////////////////////////////////////////
-
-#define JNI_DECLARE_INNER(package, classname, methodname ) \
- Java_ ## package ## _ ## classname ## _ ## methodname
-#define JNI_DECLARE(classname, methodname) \
- JNI_DECLARE_INNER(com_termux_x11, classname, methodname)
-
-extern "C" JNIEXPORT jlong JNICALL
-JNI_DECLARE(LorieService, createLorieThread)(JNIEnv *env, jobject thiz) {
-#if 0
- // It is needed to redirect stderr to logcat
- setenv("WAYLAND_DEBUG", "1", 1);
- new std::thread([]{
- FILE *fp;
- int p[2];
- size_t read, len;
- char* line = nullptr;
- pipe(p);
- fp = fdopen(p[0], "r");
-
- dup2(p[1], 2);
- while ((read = getline(&line, &len, fp)) != -1) {
- __android_log_write(ANDROID_LOG_VERBOSE, "WAYLAND_STDERR", line);
- }
- });
-#endif
- return (jlong) new lorie_compositor(env->NewGlobalRef(thiz));
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, passWaylandFD)(JNIEnv *env, jobject thiz, jint fd) {
- LOGI("JNI: got fd %d", fd);
- execute<&lorie_compositor::add_socket_fd>(env, thiz, fd);
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, terminate)(JNIEnv *env, jobject obj) {
- auto b = reinterpret_cast(env->GetLongField(obj, lorie_compositor::compositor_field_id));
- b->terminate();
- b->post([]{});
- b->self.join();
- env->SetLongField(obj, lorie_compositor::compositor_field_id, 0);
- delete b;
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, cursorChanged)(JNIEnv *env, jobject thiz, jobject surface) {
- EGLNativeWindowType win = surface?ANativeWindow_fromSurface(env, surface):nullptr;
- auto c = get(env, thiz);
- c->post([=]{ c->cursor.win = win; });
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, windowChanged)(JNIEnv *env, jobject thiz, jobject surface, jint w, jint h) {
- EGLNativeWindowType win = surface?ANativeWindow_fromSurface(env, surface):nullptr;
- queue<&lorie_compositor::output_resize>(env, thiz, win, w, h, int(w*25.4/DEFAULT_DPI), int(h*25.4/DEFAULT_DPI));
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, pointerMotion)(JNIEnv *env, jobject thiz, jint x, jint y) {
- queue<&lorie_compositor::pointer_motion>(env, thiz, x, y);
- if (lorie_compositor::compositor_field_id) {
- auto native =
- lorie_compositor::compositor_field_id ?
- reinterpret_cast(env->GetLongField(thiz,lorie_compositor::compositor_field_id)):
- nullptr;
- if (native) {
- native->set_cursor_visibility(env, true);
- native->set_cursor_position(env, x, y);
- }
- }
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, pointerScroll)(JNIEnv *env, jobject thiz, jint axis, jfloat value) {
- queue<&lorie_compositor::pointer_scroll>(env, thiz, axis, value);
- if (lorie_compositor::compositor_field_id) {
- auto native =
- lorie_compositor::compositor_field_id ?
- reinterpret_cast(env->GetLongField(thiz,lorie_compositor::compositor_field_id)):
- nullptr;
- if (native) {
- native->set_cursor_visibility(env, true);
- }
- }
-}
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, pointerButton)(JNIEnv *env, jobject thiz, jint button, jint type) {
- queue<&lorie_compositor::pointer_button>(env, thiz, uint32_t(button), uint32_t(type));
- if (lorie_compositor::compositor_field_id) {
- auto native =
- lorie_compositor::compositor_field_id ?
- reinterpret_cast(env->GetLongField(thiz,lorie_compositor::compositor_field_id)):
- nullptr;
- if (native) {
- native->set_cursor_visibility(env, true);
- }
- }
-}
-
-extern "C" void get_character_data(char** layout, int *shift, int *ec, char *ch);
-extern "C" void android_keycode_get_eventcode(int kc, int *ec, int *shift);
-
-extern "C" JNIEXPORT void JNICALL
-JNI_DECLARE(LorieService, keyboardKey)(JNIEnv *env, jobject thiz,
- jint type, jint key_code, jint jshift, jstring characters_) {
- char *characters = nullptr;
-
- int event_code = 0;
- int shift = jshift;
- if (characters_ != nullptr) characters = (char*) env->GetStringUTFChars(characters_, nullptr);
- if (key_code && !characters) {
- android_keycode_get_eventcode(key_code, &event_code, &shift);
- LOGE("kc: %d ec: %d", key_code, event_code);
- }
- if (!key_code && characters) {
- char *layout = nullptr;
- get_character_data(&layout, &shift, &event_code, characters);
- }
- LOGE("Keyboard input: keyCode: %d; eventCode: %d; characters: %s; shift: %d, type: %d", key_code, event_code, characters, shift, type);
-
- if (shift || jshift)
- queue<&lorie_compositor::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::pressed);
-
- // For some reason Android do not send ACTION_DOWN for non-English characters
- if (characters)
- queue<&lorie_compositor::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state::pressed);
-
- queue<&lorie_compositor::keyboard_key>(env, thiz, event_code, wayland::keyboard_key_state(type));
-
- if (shift || jshift)
- queue<&lorie_compositor::keyboard_key>(env, thiz, 42, wayland::keyboard_key_state::released);
-
- if (characters_ != nullptr) env->ReleaseStringUTFChars(characters_, characters);
-}
-
-static bool sameUid(int pid) {
- char path[32] = {0};
- struct stat s = {0};
- sprintf(path, "/proc/%d", pid);
- stat(path, &s);
- return s.st_uid == getuid();
-}
-
-static void killAllLogcats() {
- DIR* proc;
- struct dirent* dir_elem;
- char path[64] = {0}, link[64] = {0};
- pid_t pid, self = getpid();
- if ((proc = opendir("/proc")) == nullptr) {
- LOGE("opendir: %s", strerror(errno));
- return;
- }
-
- while((dir_elem = readdir(proc)) != nullptr) {
- if (!(pid = (pid_t) atoi (dir_elem->d_name)) || pid == self || !sameUid(pid)) // NOLINT(cert-err34-c)
- continue;
-
- memset(path, 0, sizeof(path));
- memset(link, 0, sizeof(link));
- sprintf(path, "/proc/%d/exe", pid);
- if (readlink(path, link, sizeof(link)) < 0) {
- LOGE("readlink %s: %s", path, strerror(errno));
- continue;
- }
- if (strstr(link, "/logcat") != nullptr) {
- if (kill(pid, SIGKILL) < 0) {
- LOGE("kill %d (%s): %s", pid, link, strerror(errno));
- }
- }
- }
-}
-
-void fork(const std::function& f) {
- switch(fork()) {
- case -1: LOGE("fork: %s", strerror(errno)); return;
- case 0: f(); return;
- default: return;
- }
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_termux_x11_LorieService_startLogcatForFd(unused JNIEnv *env, unused jclass clazz, jint fd) {
- killAllLogcats();
-
- LOGI("Starting logcat with output to given fd");
- fork([]() {
- execl("/system/bin/logcat", "logcat", "-c", nullptr);
- LOGE("exec logcat: %s", strerror(errno));
- });
-
- fork([fd]() {
- dup2(fd, 1);
- dup2(fd, 2);
- execl("/system/bin/logcat", "logcat", nullptr);
- LOGE("exec logcat: %s", strerror(errno));
- });
-}
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wshadow"
-extern "C" jint JNI_OnLoad(JavaVM* vm, [[maybe_unused]] void* reserved) {
- ::vm = vm;
- return JNI_VERSION_1_6;
-}
-#pragma clang diagnostic pop
diff --git a/app/src/main/jni/lorie/backend/android/keymaps.h b/app/src/main/jni/lorie/backend/android/keymaps.h
deleted file mode 100644
index 2f433858b..000000000
--- a/app/src/main/jni/lorie/backend/android/keymaps.h
+++ /dev/null
@@ -1,245 +0,0 @@
-#include
-#define SYM_LENGTH 7
-#define KEYCODE_MIN 8
-#define KEYCODE_MAX 255
-#define NOSYM {{0}, {0}}
-struct lorie_keymap {
- char *name;
- struct keysym {
- char normal[SYM_LENGTH];
- char shift[SYM_LENGTH];
- } keysyms[KEYCODE_MAX - KEYCODE_MIN];
-};
-
-struct lorie_keymap lorie_keymap_ru = {
- .name = (char*) "ru",
- .keysyms = {
- NOSYM, // eventCode: 0
- NOSYM, // eventCode: 1
- {{49, 0, 0, 0, 0, 0, 0}, {33, 0, 0, 0, 0, 0, 0}}, // eventCode: 2; normal: "1"; shift: "!";
- {{50, 0, 0, 0, 0, 0, 0}, {34, 0, 0, 0, 0, 0, 0}}, // eventCode: 3; normal: "2"; shift: """;
- {{51, 0, 0, 0, 0, 0, 0}, {-30, -124, -106, 0, 0, 0, 0}}, // eventCode: 4; normal: "3"; shift: "№";
- {{52, 0, 0, 0, 0, 0, 0}, {59, 0, 0, 0, 0, 0, 0}}, // eventCode: 5; normal: "4"; shift: ";";
- {{53, 0, 0, 0, 0, 0, 0}, {37, 0, 0, 0, 0, 0, 0}}, // eventCode: 6; normal: "5"; shift: "%";
- {{54, 0, 0, 0, 0, 0, 0}, {58, 0, 0, 0, 0, 0, 0}}, // eventCode: 7; normal: "6"; shift: ":";
- {{55, 0, 0, 0, 0, 0, 0}, {63, 0, 0, 0, 0, 0, 0}}, // eventCode: 8; normal: "7"; shift: "?";
- {{56, 0, 0, 0, 0, 0, 0}, {42, 0, 0, 0, 0, 0, 0}}, // eventCode: 9; normal: "8"; shift: "*";
- {{57, 0, 0, 0, 0, 0, 0}, {40, 0, 0, 0, 0, 0, 0}}, // eventCode: 10; normal: "9"; shift: "(";
- {{48, 0, 0, 0, 0, 0, 0}, {41, 0, 0, 0, 0, 0, 0}}, // eventCode: 11; normal: "0"; shift: ")";
- {{45, 0, 0, 0, 0, 0, 0}, {95, 0, 0, 0, 0, 0, 0}}, // eventCode: 12; normal: "-"; shift: "_";
- {{61, 0, 0, 0, 0, 0, 0}, {43, 0, 0, 0, 0, 0, 0}}, // eventCode: 13; normal: "="; shift: "+";
- {{8, 0, 0, 0, 0, 0, 0}, {8, 0, 0, 0, 0, 0, 0}}, // eventCode: 14;
- NOSYM, // eventCode: 15; normal: " ";
- {{-48, -71, 0, 0, 0, 0, 0}, {-48, -103, 0, 0, 0, 0, 0}}, // eventCode: 16; normal: "й"; shift: "Й";
- {{-47, -122, 0, 0, 0, 0, 0}, {-48, -90, 0, 0, 0, 0, 0}}, // eventCode: 17; normal: "ц"; shift: "Ц";
- {{-47, -125, 0, 0, 0, 0, 0}, {-48, -93, 0, 0, 0, 0, 0}}, // eventCode: 18; normal: "у"; shift: "У";
- {{-48, -70, 0, 0, 0, 0, 0}, {-48, -102, 0, 0, 0, 0, 0}}, // eventCode: 19; normal: "к"; shift: "К";
- {{-48, -75, 0, 0, 0, 0, 0}, {-48, -107, 0, 0, 0, 0, 0}}, // eventCode: 20; normal: "е"; shift: "Е";
- {{-48, -67, 0, 0, 0, 0, 0}, {-48, -99, 0, 0, 0, 0, 0}}, // eventCode: 21; normal: "н"; shift: "Н";
- {{-48, -77, 0, 0, 0, 0, 0}, {-48, -109, 0, 0, 0, 0, 0}}, // eventCode: 22; normal: "г"; shift: "Г";
- {{-47, -120, 0, 0, 0, 0, 0}, {-48, -88, 0, 0, 0, 0, 0}}, // eventCode: 23; normal: "ш"; shift: "Ш";
- {{-47, -119, 0, 0, 0, 0, 0}, {-48, -87, 0, 0, 0, 0, 0}}, // eventCode: 24; normal: "щ"; shift: "Щ";
- {{-48, -73, 0, 0, 0, 0, 0}, {-48, -105, 0, 0, 0, 0, 0}}, // eventCode: 25; normal: "з"; shift: "З";
- {{-47, -123, 0, 0, 0, 0, 0}, {-48, -91, 0, 0, 0, 0, 0}}, // eventCode: 26; normal: "х"; shift: "Х";
- {{-47, -118, 0, 0, 0, 0, 0}, {-48, -86, 0, 0, 0, 0, 0}}, // eventCode: 27; normal: "ъ"; shift: "Ъ";
- {{13, 0, 0, 0, 0, 0, 0}, {13, 0, 0, 0, 0, 0, 0}}, // eventCode: 28;
- NOSYM, // eventCode: 29
- {{-47, -124, 0, 0, 0, 0, 0}, {-48, -92, 0, 0, 0, 0, 0}}, // eventCode: 30; normal: "ф"; shift: "Ф";
- {{-47, -117, 0, 0, 0, 0, 0}, {-48, -85, 0, 0, 0, 0, 0}}, // eventCode: 31; normal: "ы"; shift: "Ы";
- {{-48, -78, 0, 0, 0, 0, 0}, {-48, -110, 0, 0, 0, 0, 0}}, // eventCode: 32; normal: "в"; shift: "В";
- {{-48, -80, 0, 0, 0, 0, 0}, {-48, -112, 0, 0, 0, 0, 0}}, // eventCode: 33; normal: "а"; shift: "А";
- {{-48, -65, 0, 0, 0, 0, 0}, {-48, -97, 0, 0, 0, 0, 0}}, // eventCode: 34; normal: "п"; shift: "П";
- {{-47, -128, 0, 0, 0, 0, 0}, {-48, -96, 0, 0, 0, 0, 0}}, // eventCode: 35; normal: "р"; shift: "Р";
- {{-48, -66, 0, 0, 0, 0, 0}, {-48, -98, 0, 0, 0, 0, 0}}, // eventCode: 36; normal: "о"; shift: "О";
- {{-48, -69, 0, 0, 0, 0, 0}, {-48, -101, 0, 0, 0, 0, 0}}, // eventCode: 37; normal: "л"; shift: "Л";
- {{-48, -76, 0, 0, 0, 0, 0}, {-48, -108, 0, 0, 0, 0, 0}}, // eventCode: 38; normal: "д"; shift: "Д";
- {{-48, -74, 0, 0, 0, 0, 0}, {-48, -106, 0, 0, 0, 0, 0}}, // eventCode: 39; normal: "ж"; shift: "Ж";
- {{-47, -115, 0, 0, 0, 0, 0}, {-48, -83, 0, 0, 0, 0, 0}}, // eventCode: 40; normal: "э"; shift: "Э";
- {{-47, -111, 0, 0, 0, 0, 0}, {-48, -127, 0, 0, 0, 0, 0}}, // eventCode: 41; normal: "ё"; shift: "Ё";
- NOSYM, // eventCode: 42;
- {{92, 0, 0, 0, 0, 0, 0}, {47, 0, 0, 0, 0, 0, 0}}, // eventCode: 43; normal: "\"; shift: "/";
- {{-47, -113, 0, 0, 0, 0, 0}, {-48, -81, 0, 0, 0, 0, 0}}, // eventCode: 44; normal: "я"; shift: "Я";
- {{-47, -121, 0, 0, 0, 0, 0}, {-48, -89, 0, 0, 0, 0, 0}}, // eventCode: 45; normal: "ч"; shift: "Ч";
- {{-47, -127, 0, 0, 0, 0, 0}, {-48, -95, 0, 0, 0, 0, 0}}, // eventCode: 46; normal: "с"; shift: "С";
- {{-48, -68, 0, 0, 0, 0, 0}, {-48, -100, 0, 0, 0, 0, 0}}, // eventCode: 47; normal: "м"; shift: "М";
- {{-48, -72, 0, 0, 0, 0, 0}, {-48, -104, 0, 0, 0, 0, 0}}, // eventCode: 48; normal: "и"; shift: "И";
- {{-47, -126, 0, 0, 0, 0, 0}, {-48, -94, 0, 0, 0, 0, 0}}, // eventCode: 49; normal: "т"; shift: "Т";
- {{-47, -116, 0, 0, 0, 0, 0}, {-48, -84, 0, 0, 0, 0, 0}}, // eventCode: 50; normal: "ь"; shift: "Ь";
- {{-48, -79, 0, 0, 0, 0, 0}, {-48, -111, 0, 0, 0, 0, 0}}, // eventCode: 51; normal: "б"; shift: "Б";
- {{-47, -114, 0, 0, 0, 0, 0}, {-48, -82, 0, 0, 0, 0, 0}}, // eventCode: 52; normal: "ю"; shift: "Ю";
- {{46, 0, 0, 0, 0, 0, 0}, {44, 0, 0, 0, 0, 0, 0}}, // eventCode: 53; normal: "."; shift: ",";
- }
-};
-
-struct lorie_keymap *lorie_keymaps[] = {&lorie_keymap_ru, NULL};
-
-struct lorie_keymap_android {
- int eventCode;
- int shift;
-} lorie_keymap_android[] = {
- {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {1, 0}, // keycode 4
- {0, 0}, {0, 0},
- {11, 0}, // keycode 7
- {2, 0}, // keycode 8
- {3, 0}, // keycode 9
- {4, 0}, // keycode 10
- {5, 0}, // keycode 11
- {6, 0}, // keycode 12
- {7, 0}, // keycode 13
- {8, 0}, // keycode 14
- {9, 0}, // keycode 15
- {10, 0}, // keycode 16
- {9, 1}, // keycode 17
- {4, 1}, // keycode 18
- {103, 0}, // keycode 19
- {108, 0}, // keycode 20
- {105, 0}, // keycode 21
- {106, 0}, // keycode 22
- {0, 0},
- {115, 0}, // keycode 24
- {114, 0}, // keycode 25
- {116, 0}, // keycode 26
- {212, 0}, // keycode 27
- {0, 0},
- {30, 0}, // keycode 29
- {48, 0}, // keycode 30
- {46, 0}, // keycode 31
- {32, 0}, // keycode 32
- {18, 0}, // keycode 33
- {33, 0}, // keycode 34
- {34, 0}, // keycode 35
- {35, 0}, // keycode 36
- {23, 0}, // keycode 37
- {36, 0}, // keycode 38
- {37, 0}, // keycode 39
- {38, 0}, // keycode 40
- {50, 0}, // keycode 41
- {49, 0}, // keycode 42
- {24, 0}, // keycode 43
- {25, 0}, // keycode 44
- {16, 0}, // keycode 45
- {19, 0}, // keycode 46
- {31, 0}, // keycode 47
- {20, 0}, // keycode 48
- {22, 0}, // keycode 49
- {47, 0}, // keycode 50
- {17, 0}, // keycode 51
- {45, 0}, // keycode 52
- {21, 0}, // keycode 53
- {44, 0}, // keycode 54
- {51, 0}, // keycode 55
- {52, 0}, // keycode 56
- {56, 0}, // keycode 57
- {100, 0}, // keycode 58
- {42, 0}, // keycode 59
- {54, 0}, // keycode 60
- {15, 0}, // keycode 61
- {57, 0}, // keycode 62
- {0, 0},
- {150, 0}, // keycode 64
- {155, 0}, // keycode 65
- {28, 0}, // keycode 66
- {14, 0}, // keycode 67
- {41, 0}, // keycode 68
- {12, 0}, // keycode 69
- {13, 0}, // keycode 70
- {26, 0}, // keycode 71
- {27, 0}, // keycode 72
- {43, 0}, // keycode 73
- {39, 0}, // keycode 74
- {40, 0}, // keycode 75
- {53, 0}, // keycode 76
- {3, 1}, // keycode 77
- {0, 0}, {0, 0}, {0, 0},
- {13, 1}, // keycode 81
- {139, 0}, // keycode 82
- {0, 0},
- {217, 0}, // keycode 84
- {164, 0}, // keycode 85
- {625, 0}, // keycode 86
- {163, 0}, // keycode 87
- {165, 0}, // keycode 88
- {168, 0}, // keycode 89
- {208, 0}, // keycode 90
- {248, 0}, // keycode 91
- {104, 0}, // keycode 92
- {109, 0}, // keycode 93
- {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {1, 0}, // keycode 111
- {111, 0}, // keycode 112
- {29, 0}, // keycode 113
- {97, 0}, // keycode 114
- {58, 0}, // keycode 115
- {70, 0}, // keycode 116
- {125, 0}, // keycode 117
- {126, 0}, // keycode 118
- {0, 0},
- {99, 0}, // keycode 120
- {411, 0}, // keycode 121
- {102, 0}, // keycode 122
- {107, 0}, // keycode 123
- {110, 0}, // keycode 124
- {159, 0}, // keycode 125
- {207, 0}, // keycode 126
- {0, 0},
- {160, 0}, // keycode 128
- {161, 0}, // keycode 129
- {167, 0}, // keycode 130
- {59, 0}, // keycode 131
- {60, 0}, // keycode 132
- {61, 0}, // keycode 133
- {62, 0}, // keycode 134
- {63, 0}, // keycode 135
- {64, 0}, // keycode 136
- {65, 0}, // keycode 137
- {66, 0}, // keycode 138
- {67, 0}, // keycode 139
- {68, 0}, // keycode 140
- {87, 0}, // keycode 141
- {88, 0}, // keycode 142
- {69, 0}, // keycode 143
- {82, 0}, // keycode 144
- {79, 0}, // keycode 145
- {80, 0}, // keycode 146
- {81, 0}, // keycode 147
- {75, 0}, // keycode 148
- {76, 0}, // keycode 149
- {77, 0}, // keycode 150
- {71, 0}, // keycode 151
- {72, 0}, // keycode 152
- {73, 0}, // keycode 153
- {98, 0}, // keycode 154
- {55, 0}, // keycode 155
- {74, 0}, // keycode 156
- {78, 0}, // keycode 157
- {83, 0}, // keycode 158
- {121, 0}, // keycode 159
- {96, 0}, // keycode 160
- {117, 0}, // keycode 161
- {179, 0}, // keycode 162
- {180, 0}, // keycode 163
- {113, 0}, // keycode 164
- {358, 0}, // keycode 165
- {402, 0}, // keycode 166
- {403, 0}, // keycode 167
- {418, 0}, // keycode 168
- {419, 0}, // keycode 169
- {377, 0}, // keycode 170
- {0, 0}, {0, 0}, {0, 0},
- {156, 0}, // keycode 174
- {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {398, 0}, // keycode 183
- {399, 0}, // keycode 184
- {400, 0}, // keycode 185
- {401, 0}, // keycode 186
- {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {429, 0}, // keycode 207
- {397, 0}, // keycode 208
- {387, 0}, // keycode 209
- {140, 0}, // keycode 210
- {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},
- {224, 0}, // keycode 220
- {225, 0}, // keycode 221
- {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}
-};
diff --git a/app/src/main/jni/lorie/backend/android/locale/android-keycodes.h b/app/src/main/jni/lorie/backend/android/locale/android-keycodes.h
deleted file mode 100644
index a8528d0ab..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/android-keycodes.h
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __ANDROID_KEYCODES_H__
-#define __ANDROID_KEYCODES_H__
-
-/** Key code constant: Unknown key code. */
-#define ANDROID_KEYCODE_UNKNOWN 0
-/** Key code constant: Soft Left key.
- * Usually situated below the display on phones and used as a multi-function
- * feature key for selecting a software defined function shown on the bottom left
- * of the display. */
-#define ANDROID_KEYCODE_SOFT_LEFT 1
-/** Key code constant: Soft Right key.
- * Usually situated below the display on phones and used as a multi-function
- * feature key for selecting a software defined function shown on the bottom right
- * of the display. */
-#define ANDROID_KEYCODE_SOFT_RIGHT 2
-/** Key code constant: Home key.
- * This key is handled by the framework and is never delivered to applications. */
-#define ANDROID_KEYCODE_HOME 3
-/** Key code constant: Back key. */
-#define ANDROID_KEYCODE_BACK 4
-/** Key code constant: Call key. */
-#define ANDROID_KEYCODE_CALL 5
-/** Key code constant: End Call key. */
-#define ANDROID_KEYCODE_ENDCALL 6
-/** Key code constant: '0' key. */
-#define ANDROID_KEYCODE_0 7
-/** Key code constant: '1' key. */
-#define ANDROID_KEYCODE_1 8
-/** Key code constant: '2' key. */
-#define ANDROID_KEYCODE_2 9
-/** Key code constant: '3' key. */
-#define ANDROID_KEYCODE_3 10
-/** Key code constant: '4' key. */
-#define ANDROID_KEYCODE_4 11
-/** Key code constant: '5' key. */
-#define ANDROID_KEYCODE_5 12
-/** Key code constant: '6' key. */
-#define ANDROID_KEYCODE_6 13
-/** Key code constant: '7' key. */
-#define ANDROID_KEYCODE_7 14
-/** Key code constant: '8' key. */
-#define ANDROID_KEYCODE_8 15
-/** Key code constant: '9' key. */
-#define ANDROID_KEYCODE_9 16
-/** Key code constant: '*' key. */
-#define ANDROID_KEYCODE_STAR 17
-/** Key code constant: '#' key. */
-#define ANDROID_KEYCODE_POUND 18
-/** Key code constant: Directional Pad Up key.
- * May also be synthesized from trackball motions. */
-#define ANDROID_KEYCODE_DPAD_UP 19
-/** Key code constant: Directional Pad Down key.
- * May also be synthesized from trackball motions. */
-#define ANDROID_KEYCODE_DPAD_DOWN 20
-/** Key code constant: Directional Pad Left key.
- * May also be synthesized from trackball motions. */
-#define ANDROID_KEYCODE_DPAD_LEFT 21
-/** Key code constant: Directional Pad Right key.
- * May also be synthesized from trackball motions. */
-#define ANDROID_KEYCODE_DPAD_RIGHT 22
-/** Key code constant: Directional Pad Center key.
- * May also be synthesized from trackball motions. */
-#define ANDROID_KEYCODE_DPAD_CENTER 23
-/** Key code constant: Volume Up key.
- * Adjusts the speaker volume up. */
-#define ANDROID_KEYCODE_VOLUME_UP 24
-/** Key code constant: Volume Down key.
- * Adjusts the speaker volume down. */
-#define ANDROID_KEYCODE_VOLUME_DOWN 25
-/** Key code constant: Power key. */
-#define ANDROID_KEYCODE_POWER 26
-/** Key code constant: Camera key.
- * Used to launch a camera application or take pictures. */
-#define ANDROID_KEYCODE_CAMERA 27
-/** Key code constant: Clear key. */
-#define ANDROID_KEYCODE_CLEAR 28
-/** Key code constant: 'A' key. */
-#define ANDROID_KEYCODE_A 29
-/** Key code constant: 'B' key. */
-#define ANDROID_KEYCODE_B 30
-/** Key code constant: 'C' key. */
-#define ANDROID_KEYCODE_C 31
-/** Key code constant: 'D' key. */
-#define ANDROID_KEYCODE_D 32
-/** Key code constant: 'E' key. */
-#define ANDROID_KEYCODE_E 33
-/** Key code constant: 'F' key. */
-#define ANDROID_KEYCODE_F 34
-/** Key code constant: 'G' key. */
-#define ANDROID_KEYCODE_G 35
-/** Key code constant: 'H' key. */
-#define ANDROID_KEYCODE_H 36
-/** Key code constant: 'I' key. */
-#define ANDROID_KEYCODE_I 37
-/** Key code constant: 'J' key. */
-#define ANDROID_KEYCODE_J 38
-/** Key code constant: 'K' key. */
-#define ANDROID_KEYCODE_K 39
-/** Key code constant: 'L' key. */
-#define ANDROID_KEYCODE_L 40
-/** Key code constant: 'M' key. */
-#define ANDROID_KEYCODE_M 41
-/** Key code constant: 'N' key. */
-#define ANDROID_KEYCODE_N 42
-/** Key code constant: 'O' key. */
-#define ANDROID_KEYCODE_O 43
-/** Key code constant: 'P' key. */
-#define ANDROID_KEYCODE_P 44
-/** Key code constant: 'Q' key. */
-#define ANDROID_KEYCODE_Q 45
-/** Key code constant: 'R' key. */
-#define ANDROID_KEYCODE_R 46
-/** Key code constant: 'S' key. */
-#define ANDROID_KEYCODE_S 47
-/** Key code constant: 'T' key. */
-#define ANDROID_KEYCODE_T 48
-/** Key code constant: 'U' key. */
-#define ANDROID_KEYCODE_U 49
-/** Key code constant: 'V' key. */
-#define ANDROID_KEYCODE_V 50
-/** Key code constant: 'W' key. */
-#define ANDROID_KEYCODE_W 51
-/** Key code constant: 'X' key. */
-#define ANDROID_KEYCODE_X 52
-/** Key code constant: 'Y' key. */
-#define ANDROID_KEYCODE_Y 53
-/** Key code constant: 'Z' key. */
-#define ANDROID_KEYCODE_Z 54
-/** Key code constant: ',' key. */
-#define ANDROID_KEYCODE_COMMA 55
-/** Key code constant: '.' key. */
-#define ANDROID_KEYCODE_PERIOD 56
-/** Key code constant: Left Alt modifier key. */
-#define ANDROID_KEYCODE_ALT_LEFT 57
-/** Key code constant: Right Alt modifier key. */
-#define ANDROID_KEYCODE_ALT_RIGHT 58
-/** Key code constant: Left Shift modifier key. */
-#define ANDROID_KEYCODE_SHIFT_LEFT 59
-/** Key code constant: Right Shift modifier key. */
-#define ANDROID_KEYCODE_SHIFT_RIGHT 60
-/** Key code constant: Tab key. */
-#define ANDROID_KEYCODE_TAB 61
-/** Key code constant: Space key. */
-#define ANDROID_KEYCODE_SPACE 62
-/** Key code constant: Symbol modifier key.
- * Used to enter alternate symbols. */
-#define ANDROID_KEYCODE_SYM 63
-/** Key code constant: Explorer special function key.
- * Used to launch a browser application. */
-#define ANDROID_KEYCODE_EXPLORER 64
-/** Key code constant: Envelope special function key.
- * Used to launch a mail application. */
-#define ANDROID_KEYCODE_ENVELOPE 65
-/** Key code constant: Enter key. */
-#define ANDROID_KEYCODE_ENTER 66
-/** Key code constant: Backspace key.
- * Deletes characters before the insertion point, unlike {@link #KEYCODE_FORWARD_DEL}. */
-#define ANDROID_KEYCODE_DEL 67
-/** Key code constant: '`' (backtick) key. */
-#define ANDROID_KEYCODE_GRAVE 68
-/** Key code constant: '-'. */
-#define ANDROID_KEYCODE_MINUS 69
-/** Key code constant: '=' key. */
-#define ANDROID_KEYCODE_EQUALS 70
-/** Key code constant: '[' key. */
-#define ANDROID_KEYCODE_LEFT_BRACKET 71
-/** Key code constant: ']' key. */
-#define ANDROID_KEYCODE_RIGHT_BRACKET 72
-/** Key code constant: '\' key. */
-#define ANDROID_KEYCODE_BACKSLASH 73
-/** Key code constant: ';' key. */
-#define ANDROID_KEYCODE_SEMICOLON 74
-/** Key code constant: ''' (apostrophe) key. */
-#define ANDROID_KEYCODE_APOSTROPHE 75
-/** Key code constant: '/' key. */
-#define ANDROID_KEYCODE_SLASH 76
-/** Key code constant: '@' key. */
-#define ANDROID_KEYCODE_AT 77
-/** Key code constant: Number modifier key.
- * Used to enter numeric symbols.
- * This key is not Num Lock; it is more like {@link #KEYCODE_ALT_LEFT} and is
- * interpreted as an ALT key by {@link android.text.method.MetaKeyKeyListener}. */
-#define ANDROID_KEYCODE_NUM 78
-/** Key code constant: Headset Hook key.
- * Used to hang up calls and stop media. */
-#define ANDROID_KEYCODE_HEADSETHOOK 79
-/** Key code constant: Camera Focus key.
- * Used to focus the camera. */
-#define ANDROID_KEYCODE_FOCUS 80 // *Camera* focus
-/** Key code constant: '+' key. */
-#define ANDROID_KEYCODE_PLUS 81
-/** Key code constant: Menu key. */
-#define ANDROID_KEYCODE_MENU 82
-/** Key code constant: Notification key. */
-#define ANDROID_KEYCODE_NOTIFICATION 83
-/** Key code constant: Search key. */
-#define ANDROID_KEYCODE_SEARCH 84
-/** Key code constant: Play/Pause media key. */
-#define ANDROID_KEYCODE_MEDIA_PLAY_PAUSE 85
-/** Key code constant: Stop media key. */
-#define ANDROID_KEYCODE_MEDIA_STOP 86
-/** Key code constant: Play Next media key. */
-#define ANDROID_KEYCODE_MEDIA_NEXT 87
-/** Key code constant: Play Previous media key. */
-#define ANDROID_KEYCODE_MEDIA_PREVIOUS 88
-/** Key code constant: Rewind media key. */
-#define ANDROID_KEYCODE_MEDIA_REWIND 89
-/** Key code constant: Fast Forward media key. */
-#define ANDROID_KEYCODE_MEDIA_FAST_FORWARD 90
-/** Key code constant: Mute key.
- * Mutes the microphone, unlike {@link #KEYCODE_VOLUME_MUTE}. */
-#define ANDROID_KEYCODE_MUTE 91
-/** Key code constant: Page Up key. */
-#define ANDROID_KEYCODE_PAGE_UP 92
-/** Key code constant: Page Down key. */
-#define ANDROID_KEYCODE_PAGE_DOWN 93
-/** Key code constant: Picture Symbols modifier key.
- * Used to switch symbol sets (Emoji, Kao-moji). */
-#define ANDROID_KEYCODE_PICTSYMBOLS 94 // switch symbol-sets (Emoji,Kao-moji)
-/** Key code constant: Switch Charset modifier key.
- * Used to switch character sets (Kanji, Katakana). */
-#define ANDROID_KEYCODE_SWITCH_CHARSET 95 // switch char-sets (Kanji,Katakana)
-/** Key code constant: A Button key.
- * On a game controller, the A button should be either the button labeled A
- * or the first button on the bottom row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_A 96
-/** Key code constant: B Button key.
- * On a game controller, the B button should be either the button labeled B
- * or the second button on the bottom row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_B 97
-/** Key code constant: C Button key.
- * On a game controller, the C button should be either the button labeled C
- * or the third button on the bottom row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_C 98
-/** Key code constant: X Button key.
- * On a game controller, the X button should be either the button labeled X
- * or the first button on the upper row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_X 99
-/** Key code constant: Y Button key.
- * On a game controller, the Y button should be either the button labeled Y
- * or the second button on the upper row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_Y 100
-/** Key code constant: Z Button key.
- * On a game controller, the Z button should be either the button labeled Z
- * or the third button on the upper row of controller buttons. */
-#define ANDROID_KEYCODE_BUTTON_Z 101
-/** Key code constant: L1 Button key.
- * On a game controller, the L1 button should be either the button labeled L1 (or L)
- * or the top left trigger button. */
-#define ANDROID_KEYCODE_BUTTON_L1 102
-/** Key code constant: R1 Button key.
- * On a game controller, the R1 button should be either the button labeled R1 (or R)
- * or the top right trigger button. */
-#define ANDROID_KEYCODE_BUTTON_R1 103
-/** Key code constant: L2 Button key.
- * On a game controller, the L2 button should be either the button labeled L2
- * or the bottom left trigger button. */
-#define ANDROID_KEYCODE_BUTTON_L2 104
-/** Key code constant: R2 Button key.
- * On a game controller, the R2 button should be either the button labeled R2
- * or the bottom right trigger button. */
-#define ANDROID_KEYCODE_BUTTON_R2 105
-/** Key code constant: Left Thumb Button key.
- * On a game controller, the left thumb button indicates that the left (or only)
- * joystick is pressed. */
-#define ANDROID_KEYCODE_BUTTON_THUMBL 106
-/** Key code constant: Right Thumb Button key.
- * On a game controller, the right thumb button indicates that the right
- * joystick is pressed. */
-#define ANDROID_KEYCODE_BUTTON_THUMBR 107
-/** Key code constant: Start Button key.
- * On a game controller, the button labeled Start. */
-#define ANDROID_KEYCODE_BUTTON_START 108
-/** Key code constant: Select Button key.
- * On a game controller, the button labeled Select. */
-#define ANDROID_KEYCODE_BUTTON_SELECT 109
-/** Key code constant: Mode Button key.
- * On a game controller, the button labeled Mode. */
-#define ANDROID_KEYCODE_BUTTON_MODE 110
-/** Key code constant: Escape key. */
-#define ANDROID_KEYCODE_ESCAPE 111
-/** Key code constant: Forward Delete key.
- * Deletes characters ahead of the insertion point, unlike {@link #KEYCODE_DEL}. */
-#define ANDROID_KEYCODE_FORWARD_DEL 112
-/** Key code constant: Left Control modifier key. */
-#define ANDROID_KEYCODE_CTRL_LEFT 113
-/** Key code constant: Right Control modifier key. */
-#define ANDROID_KEYCODE_CTRL_RIGHT 114
-/** Key code constant: Caps Lock key. */
-#define ANDROID_KEYCODE_CAPS_LOCK 115
-/** Key code constant: Scroll Lock key. */
-#define ANDROID_KEYCODE_SCROLL_LOCK 116
-/** Key code constant: Left Meta modifier key. */
-#define ANDROID_KEYCODE_META_LEFT 117
-/** Key code constant: Right Meta modifier key. */
-#define ANDROID_KEYCODE_META_RIGHT 118
-/** Key code constant: Function modifier key. */
-#define ANDROID_KEYCODE_FUNCTION 119
-/** Key code constant: System Request / Print Screen key. */
-#define ANDROID_KEYCODE_SYSRQ 120
-/** Key code constant: Break / Pause key. */
-#define ANDROID_KEYCODE_BREAK 121
-/** Key code constant: Home Movement key.
- * Used for scrolling or moving the cursor around to the start of a line
- * or to the top of a list. */
-#define ANDROID_KEYCODE_MOVE_HOME 122
-/** Key code constant: End Movement key.
- * Used for scrolling or moving the cursor around to the end of a line
- * or to the bottom of a list. */
-#define ANDROID_KEYCODE_MOVE_END 123
-/** Key code constant: Insert key.
- * Toggles insert / overwrite edit mode. */
-#define ANDROID_KEYCODE_INSERT 124
-/** Key code constant: Forward key.
- * Navigates forward in the history stack. Complement of {@link #KEYCODE_BACK}. */
-#define ANDROID_KEYCODE_FORWARD 125
-/** Key code constant: Play media key. */
-#define ANDROID_KEYCODE_MEDIA_PLAY 126
-/** Key code constant: Pause media key. */
-#define ANDROID_KEYCODE_MEDIA_PAUSE 127
-/** Key code constant: Close media key.
- * May be used to close a CD tray, for example. */
-#define ANDROID_KEYCODE_MEDIA_CLOSE 128
-/** Key code constant: Eject media key.
- * May be used to eject a CD tray, for example. */
-#define ANDROID_KEYCODE_MEDIA_EJECT 129
-/** Key code constant: Record media key. */
-#define ANDROID_KEYCODE_MEDIA_RECORD 130
-/** Key code constant: F1 key. */
-#define ANDROID_KEYCODE_F1 131
-/** Key code constant: F2 key. */
-#define ANDROID_KEYCODE_F2 132
-/** Key code constant: F3 key. */
-#define ANDROID_KEYCODE_F3 133
-/** Key code constant: F4 key. */
-#define ANDROID_KEYCODE_F4 134
-/** Key code constant: F5 key. */
-#define ANDROID_KEYCODE_F5 135
-/** Key code constant: F6 key. */
-#define ANDROID_KEYCODE_F6 136
-/** Key code constant: F7 key. */
-#define ANDROID_KEYCODE_F7 137
-/** Key code constant: F8 key. */
-#define ANDROID_KEYCODE_F8 138
-/** Key code constant: F9 key. */
-#define ANDROID_KEYCODE_F9 139
-/** Key code constant: F10 key. */
-#define ANDROID_KEYCODE_F10 140
-/** Key code constant: F11 key. */
-#define ANDROID_KEYCODE_F11 141
-/** Key code constant: F12 key. */
-#define ANDROID_KEYCODE_F12 142
-/** Key code constant: Num Lock key.
- * This is the Num Lock key; it is different from {@link #KEYCODE_NUM}.
- * This key alters the behavior of other keys on the numeric keypad. */
-#define ANDROID_KEYCODE_NUM_LOCK 143
-/** Key code constant: Numeric keypad '0' key. */
-#define ANDROID_KEYCODE_NUMPAD_0 144
-/** Key code constant: Numeric keypad '1' key. */
-#define ANDROID_KEYCODE_NUMPAD_1 145
-/** Key code constant: Numeric keypad '2' key. */
-#define ANDROID_KEYCODE_NUMPAD_2 146
-/** Key code constant: Numeric keypad '3' key. */
-#define ANDROID_KEYCODE_NUMPAD_3 147
-/** Key code constant: Numeric keypad '4' key. */
-#define ANDROID_KEYCODE_NUMPAD_4 148
-/** Key code constant: Numeric keypad '5' key. */
-#define ANDROID_KEYCODE_NUMPAD_5 149
-/** Key code constant: Numeric keypad '6' key. */
-#define ANDROID_KEYCODE_NUMPAD_6 150
-/** Key code constant: Numeric keypad '7' key. */
-#define ANDROID_KEYCODE_NUMPAD_7 151
-/** Key code constant: Numeric keypad '8' key. */
-#define ANDROID_KEYCODE_NUMPAD_8 152
-/** Key code constant: Numeric keypad '9' key. */
-#define ANDROID_KEYCODE_NUMPAD_9 153
-/** Key code constant: Numeric keypad '/' key (for division). */
-#define ANDROID_KEYCODE_NUMPAD_DIVIDE 154
-/** Key code constant: Numeric keypad '*' key (for multiplication). */
-#define ANDROID_KEYCODE_NUMPAD_MULTIPLY 155
-/** Key code constant: Numeric keypad '-' key (for subtraction). */
-#define ANDROID_KEYCODE_NUMPAD_SUBTRACT 156
-/** Key code constant: Numeric keypad '+' key (for addition). */
-#define ANDROID_KEYCODE_NUMPAD_ADD 157
-/** Key code constant: Numeric keypad '.' key (for decimals or digit grouping). */
-#define ANDROID_KEYCODE_NUMPAD_DOT 158
-/** Key code constant: Numeric keypad ',' key (for decimals or digit grouping). */
-#define ANDROID_KEYCODE_NUMPAD_COMMA 159
-/** Key code constant: Numeric keypad Enter key. */
-#define ANDROID_KEYCODE_NUMPAD_ENTER 160
-/** Key code constant: Numeric keypad '=' key. */
-#define ANDROID_KEYCODE_NUMPAD_EQUALS 161
-/** Key code constant: Numeric keypad '(' key. */
-#define ANDROID_KEYCODE_NUMPAD_LEFT_PAREN 162
-/** Key code constant: Numeric keypad ')' key. */
-#define ANDROID_KEYCODE_NUMPAD_RIGHT_PAREN 163
-/** Key code constant: Volume Mute key.
- * Mutes the speaker, unlike {@link #KEYCODE_MUTE}.
- * This key should normally be implemented as a toggle such that the first press
- * mutes the speaker and the second press restores the original volume. */
-#define ANDROID_KEYCODE_VOLUME_MUTE 164
-/** Key code constant: Info key.
- * Common on TV remotes to show additional information related to what is
- * currently being viewed. */
-#define ANDROID_KEYCODE_INFO 165
-/** Key code constant: Channel up key.
- * On TV remotes, increments the television channel. */
-#define ANDROID_KEYCODE_CHANNEL_UP 166
-/** Key code constant: Channel down key.
- * On TV remotes, decrements the television channel. */
-#define ANDROID_KEYCODE_CHANNEL_DOWN 167
-/** Key code constant: Zoom in key. */
-#define ANDROID_KEYCODE_ZOOM_IN 168
-/** Key code constant: Zoom out key. */
-#define ANDROID_KEYCODE_ZOOM_OUT 169
-/** Key code constant: TV key.
- * On TV remotes, switches to viewing live TV. */
-#define ANDROID_KEYCODE_TV 170
-/** Key code constant: Window key.
- * On TV remotes, toggles picture-in-picture mode or other windowing functions.
- * On Android Wear devices, triggers a display offset. */
-#define ANDROID_KEYCODE_WINDOW 171
-/** Key code constant: Guide key.
- * On TV remotes, shows a programming guide. */
-#define ANDROID_KEYCODE_GUIDE 172
-/** Key code constant: DVR key.
- * On some TV remotes, switches to a DVR mode for recorded shows. */
-#define ANDROID_KEYCODE_DVR 173
-/** Key code constant: Bookmark key.
- * On some TV remotes, bookmarks content or web pages. */
-#define ANDROID_KEYCODE_BOOKMARK 174
-/** Key code constant: Toggle captions key.
- * Switches the mode for closed-captioning text, for example during television shows. */
-#define ANDROID_KEYCODE_CAPTIONS 175
-/** Key code constant: Settings key.
- * Starts the system settings activity. */
-#define ANDROID_KEYCODE_SETTINGS 176
-/** Key code constant: TV power key.
- * On TV remotes, toggles the power on a television screen. */
-#define ANDROID_KEYCODE_TV_POWER 177
-/** Key code constant: TV input key.
- * On TV remotes, switches the input on a television screen. */
-#define ANDROID_KEYCODE_TV_INPUT 178
-/** Key code constant: Set-top-box power key.
- * On TV remotes, toggles the power on an external Set-top-box. */
-#define ANDROID_KEYCODE_STB_POWER 179
-/** Key code constant: Set-top-box input key.
- * On TV remotes, switches the input mode on an external Set-top-box. */
-#define ANDROID_KEYCODE_STB_INPUT 180
-/** Key code constant: A/V Receiver power key.
- * On TV remotes, toggles the power on an external A/V Receiver. */
-#define ANDROID_KEYCODE_AVR_POWER 181
-/** Key code constant: A/V Receiver input key.
- * On TV remotes, switches the input mode on an external A/V Receiver. */
-#define ANDROID_KEYCODE_AVR_INPUT 182
-/** Key code constant: Red "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
-#define ANDROID_KEYCODE_PROG_RED 183
-/** Key code constant: Green "programmable" key.
- * On TV remotes, actsas a contextual/programmable key. */
-#define ANDROID_KEYCODE_PROG_GREEN 184
-/** Key code constant: Yellow "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
-#define ANDROID_KEYCODE_PROG_YELLOW 185
-/** Key code constant: Blue "programmable" key.
- * On TV remotes, acts as a contextual/programmable key. */
-#define ANDROID_KEYCODE_PROG_BLUE 186
-/** Key code constant: App switch key.
- * Should bring up the application switcher dialog. */
-#define ANDROID_KEYCODE_APP_SWITCH 187
-/** Key code constant: Generic Game Pad Button #1.*/
-#define ANDROID_KEYCODE_BUTTON_1 188
-/** Key code constant: Generic Game Pad Button #2.*/
-#define ANDROID_KEYCODE_BUTTON_2 189
-/** Key code constant: Generic Game Pad Button #3.*/
-#define ANDROID_KEYCODE_BUTTON_3 190
-/** Key code constant: Generic Game Pad Button #4.*/
-#define ANDROID_KEYCODE_BUTTON_4 191
-/** Key code constant: Generic Game Pad Button #5.*/
-#define ANDROID_KEYCODE_BUTTON_5 192
-/** Key code constant: Generic Game Pad Button #6.*/
-#define ANDROID_KEYCODE_BUTTON_6 193
-/** Key code constant: Generic Game Pad Button #7.*/
-#define ANDROID_KEYCODE_BUTTON_7 194
-/** Key code constant: Generic Game Pad Button #8.*/
-#define ANDROID_KEYCODE_BUTTON_8 195
-/** Key code constant: Generic Game Pad Button #9.*/
-#define ANDROID_KEYCODE_BUTTON_9 196
-/** Key code constant: Generic Game Pad Button #10.*/
-#define ANDROID_KEYCODE_BUTTON_10 197
-/** Key code constant: Generic Game Pad Button #11.*/
-#define ANDROID_KEYCODE_BUTTON_11 198
-/** Key code constant: Generic Game Pad Button #12.*/
-#define ANDROID_KEYCODE_BUTTON_12 199
-/** Key code constant: Generic Game Pad Button #13.*/
-#define ANDROID_KEYCODE_BUTTON_13 200
-/** Key code constant: Generic Game Pad Button #14.*/
-#define ANDROID_KEYCODE_BUTTON_14 201
-/** Key code constant: Generic Game Pad Button #15.*/
-#define ANDROID_KEYCODE_BUTTON_15 202
-/** Key code constant: Generic Game Pad Button #16.*/
-#define ANDROID_KEYCODE_BUTTON_16 203
-/** Key code constant: Language Switch key.
- * Toggles the current input language such as switching between English and Japanese on
- * a QWERTY keyboard. On some devices, the same function may be performed by
- * pressing Shift+Spacebar. */
-#define ANDROID_KEYCODE_LANGUAGE_SWITCH 204
-/** Key code constant: Manner Mode key.
- * Toggles silent or vibrate mode on and off to make the device behave more politely
- * in certain settings such as on a crowded train. On some devices, the key may only
- * operate when long-pressed. */
-#define ANDROID_KEYCODE_MANNER_MODE 205
-/** Key code constant: 3D Mode key.
- * Toggles the display between 2D and 3D mode. */
-#define ANDROID_KEYCODE_3D_MODE 206
-/** Key code constant: Contacts special function key.
- * Used to launch an address book application. */
-#define ANDROID_KEYCODE_CONTACTS 207
-/** Key code constant: Calendar special function key.
- * Used to launch a calendar application. */
-#define ANDROID_KEYCODE_CALENDAR 208
-/** Key code constant: Music special function key.
- * Used to launch a music player application. */
-#define ANDROID_KEYCODE_MUSIC 209
-/** Key code constant: Calculator special function key.
- * Used to launch a calculator application. */
-#define ANDROID_KEYCODE_CALCULATOR 210
-/** Key code constant: Japanese full-width / half-width key. */
-#define ANDROID_KEYCODE_ZENKAKU_HANKAKU 211
-/** Key code constant: Japanese alphanumeric key. */
-#define ANDROID_KEYCODE_EISU 212
-/** Key code constant: Japanese non-conversion key. */
-#define ANDROID_KEYCODE_MUHENKAN 213
-/** Key code constant: Japanese conversion key. */
-#define ANDROID_KEYCODE_HENKAN 214
-/** Key code constant: Japanese katakana / hiragana key. */
-#define ANDROID_KEYCODE_KATAKANA_HIRAGANA 215
-/** Key code constant: Japanese Yen key. */
-#define ANDROID_KEYCODE_YEN 216
-/** Key code constant: Japanese Ro key. */
-#define ANDROID_KEYCODE_RO 217
-/** Key code constant: Japanese kana key. */
-#define ANDROID_KEYCODE_KANA 218
-/** Key code constant: Assist key.
- * Launches the global assist activity. Not delivered to applications. */
-#define ANDROID_KEYCODE_ASSIST 219
-/** Key code constant: Brightness Down key.
- * Adjusts the screen brightness down. */
-#define ANDROID_KEYCODE_BRIGHTNESS_DOWN 220
-/** Key code constant: Brightness Up key.
- * Adjusts the screen brightness up. */
-#define ANDROID_KEYCODE_BRIGHTNESS_UP 221
-/** Key code constant: Audio Track key.
- * Switches the audio tracks. */
-#define ANDROID_KEYCODE_MEDIA_AUDIO_TRACK 222
-/** Key code constant: Sleep key.
- * Puts the device to sleep. Behaves somewhat like {@link #KEYCODE_POWER} but it
- * has no effect if the device is already asleep. */
-#define ANDROID_KEYCODE_SLEEP 223
-/** Key code constant: Wakeup key.
- * Wakes up the device. Behaves somewhat like {@link #KEYCODE_POWER} but it
- * has no effect if the device is already awake. */
-#define ANDROID_KEYCODE_WAKEUP 224
-/** Key code constant: Pairing key.
- * Initiates peripheral pairing mode. Useful for pairing remote control
- * devices or game controllers, especially if no other input mode is
- * available. */
-#define ANDROID_KEYCODE_PAIRING 225
-/** Key code constant: Media Top Menu key.
- * Goes to the top of media menu. */
-#define ANDROID_KEYCODE_MEDIA_TOP_MENU 226
-/** Key code constant: '11' key. */
-#define ANDROID_KEYCODE_11 227
-/** Key code constant: '12' key. */
-#define ANDROID_KEYCODE_12 228
-/** Key code constant: Last Channel key.
- * Goes to the last viewed channel. */
-#define ANDROID_KEYCODE_LAST_CHANNEL 229
-/** Key code constant: TV data service key.
- * Displays data services like weather, sports. */
-#define ANDROID_KEYCODE_TV_DATA_SERVICE 230
-/** Key code constant: Voice Assist key.
- * Launches the global voice assist activity. Not delivered to applications. */
-#define ANDROID_KEYCODE_VOICE_ASSIST 231
-/** Key code constant: Radio key.
- * Toggles TV service / Radio service. */
-#define ANDROID_KEYCODE_TV_RADIO_SERVICE 232
-/** Key code constant: Teletext key.
- * Displays Teletext service. */
-#define ANDROID_KEYCODE_TV_TELETEXT 233
-/** Key code constant: Number entry key.
- * Initiates to enter multi-digit channel nubmber when each digit key is assigned
- * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC
- * User Control Code. */
-#define ANDROID_KEYCODE_TV_NUMBER_ENTRY 234
-/** Key code constant: Analog Terrestrial key.
- * Switches to analog terrestrial broadcast service. */
-#define ANDROID_KEYCODE_TV_TERRESTRIAL_ANALOG 235
-/** Key code constant: Digital Terrestrial key.
- * Switches to digital terrestrial broadcast service. */
-#define ANDROID_KEYCODE_TV_TERRESTRIAL_DIGITAL 236
-/** Key code constant: Satellite key.
- * Switches to digital satellite broadcast service. */
-#define ANDROID_KEYCODE_TV_SATELLITE 237
-/** Key code constant: BS key.
- * Switches to BS digital satellite broadcasting service available in Japan. */
-#define ANDROID_KEYCODE_TV_SATELLITE_BS 238
-/** Key code constant: CS key.
- * Switches to CS digital satellite broadcasting service available in Japan. */
-#define ANDROID_KEYCODE_TV_SATELLITE_CS 239
-/** Key code constant: BS/CS key.
- * Toggles between BS and CS digital satellite services. */
-#define ANDROID_KEYCODE_TV_SATELLITE_SERVICE 240
-/** Key code constant: Toggle Network key.
- * Toggles selecting broacast services. */
-#define ANDROID_KEYCODE_TV_NETWORK 241
-/** Key code constant: Antenna/Cable key.
- * Toggles broadcast input source between antenna and cable. */
-#define ANDROID_KEYCODE_TV_ANTENNA_CABLE 242
-/** Key code constant: HDMI #1 key.
- * Switches to HDMI input #1. */
-#define ANDROID_KEYCODE_TV_INPUT_HDMI_1 243
-/** Key code constant: HDMI #2 key.
- * Switches to HDMI input #2. */
-#define ANDROID_KEYCODE_TV_INPUT_HDMI_2 244
-/** Key code constant: HDMI #3 key.
- * Switches to HDMI input #3. */
-#define ANDROID_KEYCODE_TV_INPUT_HDMI_3 245
-/** Key code constant: HDMI #4 key.
- * Switches to HDMI input #4. */
-#define ANDROID_KEYCODE_TV_INPUT_HDMI_4 246
-/** Key code constant: Composite #1 key.
- * Switches to composite video input #1. */
-#define ANDROID_KEYCODE_TV_INPUT_COMPOSITE_1 247
-/** Key code constant: Composite #2 key.
- * Switches to composite video input #2. */
-#define ANDROID_KEYCODE_TV_INPUT_COMPOSITE_2 248
-/** Key code constant: Component #1 key.
- * Switches to component video input #1. */
-#define ANDROID_KEYCODE_TV_INPUT_COMPONENT_1 249
-/** Key code constant: Component #2 key.
- * Switches to component video input #2. */
-#define ANDROID_KEYCODE_TV_INPUT_COMPONENT_2 250
-/** Key code constant: VGA #1 key.
- * Switches to VGA (analog RGB) input #1. */
-#define ANDROID_KEYCODE_TV_INPUT_VGA_1 251
-/** Key code constant: Audio description key.
- * Toggles audio description off / on. */
-#define ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION 252
-/** Key code constant: Audio description mixing volume up key.
- * Louden audio description volume as compared with normal audio volume. */
-#define ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP 253
-/** Key code constant: Audio description mixing volume down key.
- * Lessen audio description volume as compared with normal audio volume. */
-#define ANDROID_KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN 254
-/** Key code constant: Zoom mode key.
- * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */
-#define ANDROID_KEYCODE_TV_ZOOM_MODE 255
-/** Key code constant: Contents menu key.
- * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control
- * Code */
-#define ANDROID_KEYCODE_TV_CONTENTS_MENU 256
-/** Key code constant: Media context menu key.
- * Goes to the context menu of media contents. Corresponds to Media Context-sensitive
- * Menu (0x11) of CEC User Control Code. */
-#define ANDROID_KEYCODE_TV_MEDIA_CONTEXT_MENU 257
-/** Key code constant: Timer programming key.
- * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of
- * CEC User Control Code. */
-#define ANDROID_KEYCODE_TV_TIMER_PROGRAMMING 258
-/** Key code constant: Help key. */
-#define ANDROID_KEYCODE_HELP 259
-/** Key code constant: Navigate to previous key.
- * Goes backward by one item in an ordered collection of items. */
-#define ANDROID_KEYCODE_NAVIGATE_PREVIOUS 260
-/** Key code constant: Navigate to next key.
- * Advances to the next item in an ordered collection of items. */
-#define ANDROID_KEYCODE_NAVIGATE_NEXT 261
-/** Key code constant: Navigate in key.
- * Activates the item that currently has focus or expands to the next level of a navigation
- * hierarchy. */
-#define ANDROID_KEYCODE_NAVIGATE_IN 262
-/** Key code constant: Navigate out key.
- * Backs out one level of a navigation hierarchy or collapses the item that currently has
- * focus. */
-#define ANDROID_KEYCODE_NAVIGATE_OUT 263
-/** Key code constant: Primary stem key for Wear
- * Main power/reset button on watch. */
-#define ANDROID_KEYCODE_STEM_PRIMARY 264
-/** Key code constant: Generic stem key 1 for Wear */
-#define ANDROID_KEYCODE_STEM_1 265
-/** Key code constant: Generic stem key 2 for Wear */
-#define ANDROID_KEYCODE_STEM_2 266
-/** Key code constant: Generic stem key 3 for Wear */
-#define ANDROID_KEYCODE_STEM_3 267
-/** Key code constant: Directional Pad Up-Left */
-#define ANDROID_KEYCODE_DPAD_UP_LEFT 268
-/** Key code constant: Directional Pad Down-Left */
-#define ANDROID_KEYCODE_DPAD_DOWN_LEFT 269
-/** Key code constant: Directional Pad Up-Right */
-#define ANDROID_KEYCODE_DPAD_UP_RIGHT 270
-/** Key code constant: Directional Pad Down-Right */
-#define ANDROID_KEYCODE_DPAD_DOWN_RIGHT 271
-/** Key code constant: Skip forward media key. */
-#define ANDROID_KEYCODE_MEDIA_SKIP_FORWARD 272
-/** Key code constant: Skip backward media key. */
-#define ANDROID_KEYCODE_MEDIA_SKIP_BACKWARD 273
-/** Key code constant: Step forward media key.
- * Steps media forward, one frame at a time. */
-#define ANDROID_KEYCODE_MEDIA_STEP_FORWARD 274
-/** Key code constant: Step backward media key.
- * Steps media backward, one frame at a time. */
-#define ANDROID_KEYCODE_MEDIA_STEP_BACKWARD 275
-/** Key code constant: put device to sleep unless a wakelock is held. */
-#define ANDROID_KEYCODE_SOFT_SLEEP 276
-/** Key code constant: Cut key. */
-#define ANDROID_KEYCODE_CUT 277
-/** Key code constant: Copy key. */
-#define ANDROID_KEYCODE_COPY 278
-/** Key code constant: Paste key. */
-#define ANDROID_KEYCODE_PASTE 279
-/** Key code constant: Consumed by the system for navigation up */
-#define ANDROID_KEYCODE_SYSTEM_NAVIGATION_UP 280
-/** Key code constant: Consumed by the system for navigation down */
-#define ANDROID_KEYCODE_SYSTEM_NAVIGATION_DOWN 281
-/** Key code constant: Consumed by the system for navigation left*/
-#define ANDROID_KEYCODE_SYSTEM_NAVIGATION_LEFT 282
-/** Key code constant: Consumed by the system for navigation right */
-#define ANDROID_KEYCODE_SYSTEM_NAVIGATION_RIGHT 283
-/** Key code constant: Show all apps */
-#define ANDROID_KEYCODE_ALL_APPS 284
-/** Key code constant: Refresh key. */
-#define ANDROID_KEYCODE_REFRESH 285
-
-#define ANDROID_KEYCODE_LAST ANDROID_KEYCODE_REFRESH
-
-#endif // __ANDROID_KEYCODES_H__
diff --git a/app/src/main/jni/lorie/backend/android/locale/android-utils.c b/app/src/main/jni/lorie/backend/android/locale/android-utils.c
deleted file mode 100644
index a249519fa..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/android-utils.c
+++ /dev/null
@@ -1,175 +0,0 @@
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "readability-non-const-parameter"
-#pragma ide diagnostic ignored "OCDFAInspection"
-#include
-#include
-#include "input-event-codes.h"
-#include "android-keycodes.h"
-#include "evdev-keycodes.h"
-
-#define KEYCODE1(c) case ANDROID_KEYCODE_##c : *eventCode = KEY_##c; return 1
-#define KEYCODE2(kc, ec) case ANDROID_KEYCODE_##kc : *eventCode = KEY_##ec; return 1
-#define KEYCODE2shift(kc, ec) case ANDROID_KEYCODE_##kc : *eventCode = KEY_##ec; *shift = 1; return 1
-int android_keycode_to_linux_event_code(int keyCode, int *eventCode, int *shift) {
- //if (!eventCode || !shift) return;
- switch (keyCode) {
- KEYCODE1(1);
- KEYCODE1(2);
- KEYCODE1(3);
- KEYCODE1(4);
- KEYCODE1(5);
- KEYCODE1(6);
- KEYCODE1(7);
- KEYCODE1(8);
- KEYCODE1(9);
- KEYCODE1(0);
- KEYCODE1(A);
- KEYCODE1(B);
- KEYCODE1(C);
- KEYCODE1(D);
- KEYCODE1(E);
- KEYCODE1(F);
- KEYCODE1(G);
- KEYCODE1(H);
- KEYCODE1(I);
- KEYCODE1(J);
- KEYCODE1(K);
- KEYCODE1(L);
- KEYCODE1(M);
- KEYCODE1(N);
- KEYCODE1(O);
- KEYCODE1(P);
- KEYCODE1(Q);
- KEYCODE1(R);
- KEYCODE1(S);
- KEYCODE1(T);
- KEYCODE1(U);
- KEYCODE1(V);
- KEYCODE1(W);
- KEYCODE1(X);
- KEYCODE1(Y);
- KEYCODE1(Z);
- KEYCODE1(COMMA);
- KEYCODE2(PERIOD, DOT);
- KEYCODE2(DPAD_UP, UP);
- KEYCODE2(DPAD_LEFT, LEFT);
- KEYCODE2(DPAD_DOWN, DOWN);
- KEYCODE2(DPAD_RIGHT, RIGHT);
- KEYCODE2(DPAD_CENTER, ENTER);
- KEYCODE2(ALT_LEFT, LEFTALT);
- KEYCODE2(ALT_RIGHT, RIGHTALT);
- KEYCODE2(SHIFT_LEFT, LEFTSHIFT);
- KEYCODE2(SHIFT_RIGHT, RIGHTSHIFT);
- KEYCODE1(TAB);
- KEYCODE1(SPACE);
- KEYCODE2(EXPLORER, WWW);
- KEYCODE2(ENVELOPE, MAIL);
- KEYCODE1(ENTER);
- KEYCODE2(DEL, BACKSPACE);
- KEYCODE1(GRAVE);
- KEYCODE1(MINUS);
- KEYCODE2(EQUALS, EQUAL);
- KEYCODE2(LEFT_BRACKET, LEFTBRACE);
- KEYCODE2(RIGHT_BRACKET, RIGHTBRACE);
- KEYCODE1(BACKSLASH);
- KEYCODE1(SEMICOLON);
- KEYCODE1(APOSTROPHE);
- KEYCODE1(SLASH);
- KEYCODE2shift(AT, 2);
- KEYCODE2shift(POUND, 3);
- KEYCODE2shift(STAR, 8);
- KEYCODE2shift(PLUS, EQUAL);
- KEYCODE1(MENU);
- KEYCODE1(SEARCH);
- KEYCODE2(MEDIA_PLAY_PAUSE, PLAYPAUSE);
- KEYCODE2(MEDIA_PLAY, PLAY);
- KEYCODE2(MEDIA_STOP, STOP_RECORD);
- KEYCODE2(MEDIA_NEXT, NEXTSONG);
- KEYCODE2(MEDIA_PREVIOUS, PREVIOUSSONG);
- KEYCODE2(MEDIA_REWIND, REWIND);
- KEYCODE2(MEDIA_FAST_FORWARD, FASTFORWARD);
- KEYCODE2(MEDIA_CLOSE, CLOSECD);
- KEYCODE2(MEDIA_EJECT, EJECTCD);
- KEYCODE2(MEDIA_RECORD, RECORD);
- KEYCODE2(MUTE, MICMUTE);
- KEYCODE2(PAGE_UP, PAGEUP);
- KEYCODE2(PAGE_DOWN, PAGEDOWN);
- KEYCODE2(ESCAPE, ESC);
- KEYCODE2(FORWARD_DEL, DELETE);
- KEYCODE2(CTRL_LEFT, LEFTCTRL);
- KEYCODE2(CTRL_RIGHT, RIGHTCTRL);
- KEYCODE2(CAPS_LOCK, CAPSLOCK);
- KEYCODE2(SCROLL_LOCK, SCROLLLOCK);
- KEYCODE2(NUM_LOCK, NUMLOCK);
- KEYCODE2(META_LEFT, LEFTMETA);
- KEYCODE2(META_RIGHT, RIGHTMETA);
- KEYCODE1(SYSRQ); // Print screen key
- KEYCODE1(BREAK); // Pause key
- KEYCODE2(MOVE_HOME, HOME);
- KEYCODE2(MOVE_END, END);
- KEYCODE1(INSERT);
- KEYCODE1(FORWARD);
- KEYCODE2(BACK, ESC);
- KEYCODE1(F1);
- KEYCODE1(F2);
- KEYCODE1(F3);
- KEYCODE1(F4);
- KEYCODE1(F5);
- KEYCODE1(F6);
- KEYCODE1(F7);
- KEYCODE1(F8);
- KEYCODE1(F9);
- KEYCODE1(F10);
- KEYCODE1(F11);
- KEYCODE1(F12);
- KEYCODE2(NUMPAD_0, KP0);
- KEYCODE2(NUMPAD_1, KP1);
- KEYCODE2(NUMPAD_2, KP2);
- KEYCODE2(NUMPAD_3, KP3);
- KEYCODE2(NUMPAD_4, KP4);
- KEYCODE2(NUMPAD_5, KP5);
- KEYCODE2(NUMPAD_6, KP6);
- KEYCODE2(NUMPAD_7, KP7);
- KEYCODE2(NUMPAD_8, KP8);
- KEYCODE2(NUMPAD_9, KP9);
- KEYCODE2(NUMPAD_DIVIDE, KPSLASH);
- KEYCODE2(NUMPAD_MULTIPLY, KPASTERISK);
- KEYCODE2(NUMPAD_SUBTRACT, KPMINUS);
- KEYCODE2(NUMPAD_ADD, KPPLUS);
- KEYCODE2(NUMPAD_DOT, KPDOT);
- KEYCODE2(NUMPAD_COMMA, KPCOMMA);
- KEYCODE2(NUMPAD_ENTER, KPENTER);
- KEYCODE2(NUMPAD_EQUALS, KPEQUAL);
- KEYCODE2(NUMPAD_LEFT_PAREN, KPLEFTPAREN);
- KEYCODE2(NUMPAD_RIGHT_PAREN, KPRIGHTPAREN);
- KEYCODE1(POWER);
- KEYCODE1(CAMERA);
- KEYCODE2(VOLUME_MUTE, MUTE);
- KEYCODE2(VOLUME_UP, VOLUMEUP);
- KEYCODE2(VOLUME_DOWN, VOLUMEDOWN);
- KEYCODE1(INFO);
- KEYCODE2(CHANNEL_UP, CHANNELUP);
- KEYCODE2(CHANNEL_DOWN, CHANNELDOWN);
- KEYCODE2(ZOOM_IN, ZOOMIN);
- KEYCODE2(ZOOM_OUT, ZOOMOUT);
- KEYCODE1(TV);
- KEYCODE2(BOOKMARK, BOOKMARKS);
- KEYCODE2(PROG_RED, RED);
- KEYCODE2(PROG_GREEN, GREEN);
- KEYCODE2(PROG_YELLOW, YELLOW);
- KEYCODE2(PROG_BLUE, BLUE);
- KEYCODE2(CONTACTS, ADDRESSBOOK);
- KEYCODE1(CALENDAR);
- KEYCODE2(MUSIC, PLAYER);
- KEYCODE2(CALCULATOR, CALC);
- KEYCODE2(BRIGHTNESS_DOWN, BRIGHTNESSDOWN);
- KEYCODE2(BRIGHTNESS_UP, BRIGHTNESSUP);
- default: *eventCode = KEY_RESERVED; return 0;
- }
- *eventCode = KEY_RESERVED;
- return 0;
-}
-#undef KEYCODE1
-#undef KEYCODE2
-
-#pragma clang diagnostic pop
diff --git a/app/src/main/jni/lorie/backend/android/locale/evdev-keycodes.h b/app/src/main/jni/lorie/backend/android/locale/evdev-keycodes.h
deleted file mode 100644
index 951a87942..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/evdev-keycodes.h
+++ /dev/null
@@ -1,296 +0,0 @@
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "OCUnusedMacroInspection"
-#ifndef __EVDEV_KEYCODES_H__
-#define EVDEV___EVDEV_KEYCODES_H__
-
-// Added for pc105 compatibility
-#define EVDEV_LSGT 94
-
-#define EVDEV_TLDE 49
-#define EVDEV_AE01 10
-#define EVDEV_AE02 11
-#define EVDEV_AE03 12
-#define EVDEV_AE04 13
-#define EVDEV_AE05 14
-#define EVDEV_AE06 15
-#define EVDEV_AE07 16
-#define EVDEV_AE08 17
-#define EVDEV_AE09 18
-#define EVDEV_AE10 19
-#define EVDEV_AE11 20
-#define EVDEV_AE12 21
-#define EVDEV_BKSP 22
-
-#define EVDEV_TAB 23
-#define EVDEV_AD01 24
-#define EVDEV_AD02 25
-#define EVDEV_AD03 26
-#define EVDEV_AD04 27
-#define EVDEV_AD05 28
-#define EVDEV_AD06 29
-#define EVDEV_AD07 30
-#define EVDEV_AD08 31
-#define EVDEV_AD09 32
-#define EVDEV_AD10 33
-#define EVDEV_AD11 34
-#define EVDEV_AD12 35
-#define EVDEV_BKSL 51
-#define EVDEV_AC12 EVDEV_BKSL
-#define EVDEV_RTRN 36
-
-#define EVDEV_CAPS 66
-#define EVDEV_AC01 38
-#define EVDEV_AC02 39
-#define EVDEV_AC03 40
-#define EVDEV_AC04 41
-#define EVDEV_AC05 42
-#define EVDEV_AC06 43
-#define EVDEV_AC07 44
-#define EVDEV_AC08 45
-#define EVDEV_AC09 46
-#define EVDEV_AC10 47
-#define EVDEV_AC11 48
-
-#define EVDEV_LFSH 50
-#define EVDEV_AB01 52
-#define EVDEV_AB02 53
-#define EVDEV_AB03 54
-#define EVDEV_AB04 55
-#define EVDEV_AB05 56
-#define EVDEV_AB06 57
-#define EVDEV_AB07 58
-#define EVDEV_AB08 59
-#define EVDEV_AB09 60
-#define EVDEV_AB10 61
-#define EVDEV_RTSH 62
-
-#define EVDEV_LALT 64
-#define EVDEV_LCTL 37
-#define EVDEV_SPCE 65
-#define EVDEV_RCTL 105
-#define EVDEV_RALT 108
-// Microsoft keyboard extra keys
-#define EVDEV_LWIN 133
-#define EVDEV_RWIN 134
-#define EVDEV_COMP 135
-#define EVDEV_MENU EVDEV_COMP
-
-#define EVDEV_ESC 9
-#define EVDEV_FK01 67
-#define EVDEV_FK02 68
-#define EVDEV_FK03 69
-#define EVDEV_FK04 70
-#define EVDEV_FK05 71
-#define EVDEV_FK06 72
-#define EVDEV_FK07 73
-#define EVDEV_FK08 74
-#define EVDEV_FK09 75
-#define EVDEV_FK10 76
-#define EVDEV_FK11 95
-#define EVDEV_FK12 96
-
-#define EVDEV_PRSC 107
-//#define EVDEV_SYRQ 107
-#define EVDEV_SCLK 78
-#define EVDEV_PAUS 127
-//#define EVDEV_BRK 419
-
-#define EVDEV_INS 118
-#define EVDEV_HOME 110
-#define EVDEV_PGUP 112
-#define EVDEV_DELE 119
-#define EVDEV_END 115
-#define EVDEV_PGDN 117
-
-#define EVDEV_UP 111
-#define EVDEV_LEFT 113
-#define EVDEV_DOWN 116
-#define EVDEV_RGHT 114
-
-#define EVDEV_NMLK 77
-#define EVDEV_KPDV 106
-#define EVDEV_KPMU 63
-#define EVDEV_KPSU 82
-
-#define EVDEV_KP7 79
-#define EVDEV_KP8 80
-#define EVDEV_KP9 81
-#define EVDEV_KPAD 86
-
-#define EVDEV_KP4 83
-#define EVDEV_KP5 84
-#define EVDEV_KP6 85
-
-#define EVDEV_KP1 87
-#define EVDEV_KP2 88
-#define EVDEV_KP3 89
-#define EVDEV_KPEN 104
-
-#define EVDEV_KP0 90
-#define EVDEV_KPDL 91
-#define EVDEV_KPEQ 125
-
-#define EVDEV_FK13 191
-#define EVDEV_FK14 192
-#define EVDEV_FK15 193
-#define EVDEV_FK16 194
-#define EVDEV_FK17 195
-#define EVDEV_FK18 196
-#define EVDEV_FK19 197
-#define EVDEV_FK20 198
-#define EVDEV_FK21 199
-#define EVDEV_FK22 200
-#define EVDEV_FK23 201
-#define EVDEV_FK24 202
-
-// Keys that are generated on Japanese keyboards
-
-//#define EVDEV_HZTG 93 // Hankaku/Zenkakau toggle - not actually used
-#define EVDEV_HZTG TLDE
-#define EVDEV_HKTG 101 // Hiragana/Katakana toggle
-#define EVDEV_AB11 97 // backslash/underscore
-#define EVDEV_HENK 100 // Henkan
-#define EVDEV_MUHE 102 // Muhenkan
-#define EVDEV_AE13 132 // Yen
-#define EVDEV_KATA 98 // Katakana
-#define EVDEV_HIRA 99 // Hiragana
-#define EVDEV_JPCM 103 // KPJPComma
-// #define EVDEV_RO 97 // Romaji
-
-// Keys that are generated on Korean keyboards
-
-#define EVDEV_HNGL 130 // Hangul Latin toggle
-#define EVDEV_HJCV 131 // Hangul to Hanja conversion
-
- // Solaris compatibility
-
-#define EVDEV_LMTA EVDEV_LWIN
-#define EVDEV_RMTA EVDEV_RWIN
-#define EVDEV_MUTE 121
-#define EVDEV_VOL_MINUS 122
-#define EVDEV_VOL_PLUS 123
-#define EVDEV_POWR 124
-#define EVDEV_STOP 136
-#define EVDEV_AGAI 137
-#define EVDEV_PROP 138
-#define EVDEV_UNDO 139
-#define EVDEV_FRNT 140
-#define EVDEV_COPY 141
-#define EVDEV_OPEN 142
-#define EVDEV_PAST 143
-#define EVDEV_FIND 144
-#define EVDEV_CUT 145
-#define EVDEV_HELP 146
-
-// Extended keys that may be generated on "Internet" keyboards.
-// evdev has standardize names for these.
-
-#define EVDEV_LNFD 109 // #define EVDEV_KEY_LINEFEED 101
-#define EVDEV_I120 120 // #define EVDEV_KEY_MACRO 112
-#define EVDEV_I126 126 // #define EVDEV_KEY_KPPLUSMINUS 118
-#define EVDEV_I128 128 // #define EVDEV_KEY_SCALE 120
-#define EVDEV_I129 129 // #define EVDEV_KEY_KPCOMMA 121
-#define EVDEV_I147 147 // #define EVDEV_KEY_MENU 139
-#define EVDEV_I148 148 // #define EVDEV_KEY_CALC 140
-#define EVDEV_I149 149 // #define EVDEV_KEY_SETUP 141
-#define EVDEV_I150 150 // #define EVDEV_KEY_SLEEP 142
-#define EVDEV_I151 151 // #define EVDEV_KEY_WAKEUP 143
-#define EVDEV_I152 152 // #define EVDEV_KEY_FILE 144
-#define EVDEV_I153 153 // #define EVDEV_KEY_SENDFILE 145
-#define EVDEV_I154 154 // #define EVDEV_KEY_DELETEFILE 146
-#define EVDEV_I155 155 // #define EVDEV_KEY_XFER 147
-#define EVDEV_I156 156 // #define EVDEV_KEY_PROG1 148
-#define EVDEV_I157 157 // #define EVDEV_KEY_PROG2 149
-#define EVDEV_I158 158 // #define EVDEV_KEY_WWW 150
-#define EVDEV_I159 159 // #define EVDEV_KEY_MSDOS 151
-#define EVDEV_I160 160 // #define EVDEV_KEY_COFFEE 152
-#define EVDEV_I161 161 // #define EVDEV_KEY_DIRECTION 153
-#define EVDEV_I162 162 // #define EVDEV_KEY_CYCLEWINDOWS 154
-#define EVDEV_I163 163 // #define EVDEV_KEY_MAIL 155
-#define EVDEV_I164 164 // #define EVDEV_KEY_BOOKMARKS 156
-#define EVDEV_I165 165 // #define EVDEV_KEY_COMPUTER 157
-#define EVDEV_I166 166 // #define EVDEV_KEY_BACK 158
-#define EVDEV_I167 167 // #define EVDEV_KEY_FORWARD 159
-#define EVDEV_I168 168 // #define EVDEV_KEY_CLOSECD 160
-#define EVDEV_I169 169 // #define EVDEV_KEY_EJECTCD 161
-#define EVDEV_I170 170 // #define EVDEV_KEY_EJECTCLOSECD 162
-#define EVDEV_I171 171 // #define EVDEV_KEY_NEXTSONG 163
-#define EVDEV_I172 172 // #define EVDEV_KEY_PLAYPAUSE 164
-#define EVDEV_I173 173 // #define EVDEV_KEY_PREVIOUSSONG 165
-#define EVDEV_I174 174 // #define EVDEV_KEY_STOPCD 166
-#define EVDEV_I175 175 // #define EVDEV_KEY_RECORD 167
-#define EVDEV_I176 176 // #define EVDEV_KEY_REWIND 168
-#define EVDEV_I177 177 // #define EVDEV_KEY_PHONE 169
-#define EVDEV_I178 178 // #define EVDEV_KEY_ISO 170
-#define EVDEV_I179 179 // #define EVDEV_KEY_CONFIG 171
-#define EVDEV_I180 180 // #define EVDEV_KEY_HOMEPAGE 172
-#define EVDEV_I181 181 // #define EVDEV_KEY_REFRESH 173
-#define EVDEV_I182 182 // #define EVDEV_KEY_EXIT 174
-#define EVDEV_I183 183 // #define EVDEV_KEY_MOVE 175
-#define EVDEV_I184 184 // #define EVDEV_KEY_EDIT 176
-#define EVDEV_I185 185 // #define EVDEV_KEY_SCROLLUP 177
-#define EVDEV_I186 186 // #define EVDEV_KEY_SCROLLDOWN 178
-#define EVDEV_I187 187 // #define EVDEV_KEY_KPLEFTPAREN 179
-#define EVDEV_I188 188 // #define EVDEV_KEY_KPRIGHTPAREN 180
-#define EVDEV_I189 189 // #define EVDEV_KEY_NEW 181
-#define EVDEV_I190 190 // #define EVDEV_KEY_REDO 182
-#define EVDEV_I208 208 // #define EVDEV_KEY_PLAYCD 200
-#define EVDEV_I209 209 // #define EVDEV_KEY_PAUSECD 201
-#define EVDEV_I210 210 // #define EVDEV_KEY_PROG3 202
-#define EVDEV_I211 211 // #define EVDEV_KEY_PROG4 203 conflicts with AB11
-#define EVDEV_I212 212 // #define EVDEV_KEY_DASHBOARD 204
-#define EVDEV_I213 213 // #define EVDEV_KEY_SUSPEND 205
-#define EVDEV_I214 214 // #define EVDEV_KEY_CLOSE 206
-#define EVDEV_I215 215 // #define EVDEV_KEY_PLAY 207
-#define EVDEV_I216 216 // #define EVDEV_KEY_FASTFORWARD 208
-#define EVDEV_I217 217 // #define EVDEV_KEY_BASSBOOST 209
-#define EVDEV_I218 218 // #define EVDEV_KEY_PRINT 210
-#define EVDEV_I219 219 // #define EVDEV_KEY_HP 211
-#define EVDEV_I220 220 // #define EVDEV_KEY_CAMERA 212
-#define EVDEV_I221 221 // #define EVDEV_KEY_SOUND 213
-#define EVDEV_I222 222 // #define EVDEV_KEY_QUESTION 214
-#define EVDEV_I223 223 // #define EVDEV_KEY_EMAIL 215
-#define EVDEV_I224 224 // #define EVDEV_KEY_CHAT 216
-#define EVDEV_I225 225 // #define EVDEV_KEY_SEARCH 217
-#define EVDEV_I226 226 // #define EVDEV_KEY_CONNECT 218
-#define EVDEV_I227 227 // #define EVDEV_KEY_FINANCE 219
-#define EVDEV_I228 228 // #define EVDEV_KEY_SPORT 220
-#define EVDEV_I229 229 // #define EVDEV_KEY_SHOP 221
-#define EVDEV_I230 230 // #define EVDEV_KEY_ALTERASE 222
-#define EVDEV_I231 231 // #define EVDEV_KEY_CANCEL 223
-#define EVDEV_I232 232 // #define EVDEV_KEY_BRIGHTNESSDOWN 224
-#define EVDEV_I233 233 // #define EVDEV_KEY_BRIGHTNESSUP 225
-#define EVDEV_I234 234 // #define EVDEV_KEY_MEDIA 226
-#define EVDEV_I235 235 // #define EVDEV_KEY_SWITCHVIDEOMODE 227
-#define EVDEV_I236 236 // #define EVDEV_KEY_KBDILLUMTOGGLE 228
-#define EVDEV_I237 237 // #define EVDEV_KEY_KBDILLUMDOWN 229
-#define EVDEV_I238 238 // #define EVDEV_KEY_KBDILLUMUP 230
-#define EVDEV_I239 239 // #define EVDEV_KEY_SEND 231
-#define EVDEV_I240 240 // #define EVDEV_KEY_REPLY 232
-#define EVDEV_I241 241 // #define EVDEV_KEY_FORWARDMAIL 233
-#define EVDEV_I242 242 // #define EVDEV_KEY_SAVE 234
-#define EVDEV_I243 243 // #define EVDEV_KEY_DOCUMENTS 235
-#define EVDEV_I244 244 // #define EVDEV_KEY_BATTERY 236
-#define EVDEV_I245 245 // #define EVDEV_KEY_BLUETOOTH 237
-#define EVDEV_I246 246 // #define EVDEV_KEY_WLAN 238
-#define EVDEV_I247 247 // #define EVDEV_KEY_UWB 239
-#define EVDEV_I248 248 // #define EVDEV_KEY_UNKNOWN 240
-#define EVDEV_I249 249 // #define EVDEV_KEY_VIDEO_NEXT 241
-#define EVDEV_I250 250 // #define EVDEV_KEY_VIDEO_PREV 242
-#define EVDEV_I251 251 // #define EVDEV_KEY_BRIGHTNESS_CYCLE 243
-#define EVDEV_I252 252 // #define EVDEV_KEY_BRIGHTNESS_ZERO 244
-#define EVDEV_I253 253 // #define EVDEV_KEY_DISPLAY_OFF 245
-#define EVDEV_I254 254 // #define EVDEV_KEY_WWAN 246
-#define EVDEV_I255 255 // #define EVDEV_KEY_RFKILL 247
-
-// Fake keycodes for virtual keys
-#define EVDEV_LVL3 92
-#define EVDEV_MDSW 203
-#define EVDEV_ALT 204
-#define EVDEV_META 205
-#define EVDEV_SUPR 206
-#define EVDEV_HYPR 207
-
-#endif // __EVDEV_KEYCODES_H__
-
-#pragma clang diagnostic pop
diff --git a/app/src/main/jni/lorie/backend/android/locale/generator b/app/src/main/jni/lorie/backend/android/locale/generator
deleted file mode 100755
index d0274f799..000000000
Binary files a/app/src/main/jni/lorie/backend/android/locale/generator and /dev/null differ
diff --git a/app/src/main/jni/lorie/backend/android/locale/generator.c b/app/src/main/jni/lorie/backend/android/locale/generator.c
deleted file mode 100644
index c1a24886d..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/generator.c
+++ /dev/null
@@ -1,360 +0,0 @@
-// gcc -o generator generator.c -lxkbcommon
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "evdev-keycodes.h"
-#include "log.h"
-
-#include "android-keycodes.h"
-
-#define KEYCODE_MIN 8
-#define KEYCODE_MAX 255
-#define EVDEV_OFFSET 8
-#define SYM_LENGTH 7
-
-int android_keycode_to_linux_event_code(int keyCode, int *eventCode, int *shift);
-
-struct keysym {
- int eventCode;
- char normal[SYM_LENGTH];
- char shift[SYM_LENGTH];
-};
-
-#define KEYMAPS_LENGTH 1
-struct keymap {
- char *name;
- struct keysym keysyms[KEYCODE_MAX - KEYCODE_MIN];
-} keymaps[KEYMAPS_LENGTH] = {0};
-
-void handler(int sig) {
- void *array[10];
- size_t size;
-
- // get void*'s for all entries on the stack
- size = backtrace(array, 10);
-
- // print out all the frames to stderr
- fprintf(stderr, "Error: signal %d:\n", sig);
- backtrace_symbols_fd(array, size, STDERR_FILENO);
- exit(1);
-}
-
-#define K(c1, c2) case EVDEV_##c1: return KEY_##c2
-int keyCode2eventCode(int kc) {
- int keyCode = kc - KEYCODE_MIN;
- switch(keyCode) {
- K(TLDE, GRAVE);
-
- K(AE01, 1);
- K(AE02, 2);
- K(AE03, 3);
- K(AE04, 4);
- K(AE05, 5);
- K(AE06, 6);
- K(AE07, 7);
- K(AE08, 8);
- K(AE09, 9);
- K(AE10, 0);
- K(AE11, MINUS);
- K(AE12, EQUAL);
- K(BKSP, BACKSPACE);
-
- K(TAB, TAB);
- K(AD01, Q);
- K(AD02, W);
- K(AD03, E);
- K(AD04, R);
- K(AD05, T);
- K(AD06, Y);
- K(AD07, U);
- K(AD08, I);
- K(AD09, O);
- K(AD10, P);
- K(AD11, LEFTBRACE);
- K(AD12, RIGHTBRACE);
- //K(BKSL, BACKSLASH); // DUPLICATE
- K(RTRN, ENTER);
-
- K(CAPS, CAPSLOCK);
- K(AC01, A);
- K(AC02, S);
- K(AC03, D);
- K(AC04, F);
- K(AC05, G);
- K(AC06, H);
- K(AC07, J);
- K(AC08, K);
- K(AC09, L);
- K(AC10, SEMICOLON);
- K(AC11, APOSTROPHE);
- K(AC12, BACKSLASH);
-
- K(LFSH, LEFTSHIFT);
- K(AB01, Z);
- K(AB02, X);
- K(AB03, C);
- K(AB04, V);
- K(AB05, B);
- K(AB06, N);
- K(AB07, M);
- K(AB08, COMMA);
- K(AB09, DOT);
- K(AB10, SLASH);
- K(RTSH, RIGHTSHIFT);
- default: return KEY_UNKNOWN;
- }
- return KEY_UNKNOWN;
-}
-
-struct iterator_args {
- struct keymap *keymap;
- uint8_t symcase;
-};
-void iterate_normal(struct xkb_keymap *xkb_keymap, xkb_keycode_t key, void *data) {
- struct iterator_args *ita = data;
- if (!ita || !ita->keymap) return;
-
- struct keymap *keymap = ita->keymap;
- struct xkb_state *xkb_state = NULL;
- char *buf = NULL;
- xkb_keysym_t ks = 0;
-
- xkb_state = xkb_state_new(xkb_keymap);
- if (xkb_state == NULL) {
- LOGE("failed to create xkb_state");
- };
-
- if (ita->symcase) {
- xkb_state_update_key(xkb_state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
- buf = keymap->keysyms[key].shift;
- } else {
- buf = keymap->keysyms[key].normal;
- }
-
- ks = xkb_state_key_get_one_sym(xkb_state, key);
- xkb_keysym_to_utf8(ks, buf, SYM_LENGTH);
-
- xkb_state_unref(xkb_state);
-}
-
-struct keymap* parse_keymap(struct xkb_context *ctx, char *name) {
- if (!ctx || !name) return NULL;
-
- struct xkb_rule_names xkb_names = {0};
- struct xkb_keymap *xkb_keymap = NULL;
- struct iterator_args ita = {0};
- struct keymap *result = NULL;
-
- xkb_names.rules = strdup("evdev");
- xkb_names.model = strdup("pc105");
- xkb_names.layout = strdup(name);
-
- xkb_keymap = xkb_keymap_new_from_names(ctx, &xkb_names, 0);
- if (xkb_keymap == NULL) {
- LOGE("failed to compile global XKB keymap\n");
- LOGE(" tried rules %s, model %s, layout %s, variant %s, "
- "options %s\n",
- xkb_names.rules, xkb_names.model,
- xkb_names.layout, xkb_names.variant,
- xkb_names.options);
- goto end;
- }
-
- result = calloc(1, sizeof(struct keymap));
- if (!result) {
- LOGE("failed to allocate struct keymap");
- goto end;
- }
-
- result->name = strdup(name);
-
- ita.keymap = result;
- ita.symcase = 0;
- xkb_keymap_key_for_each(xkb_keymap, iterate_normal, &ita);
-
- ita.symcase = 1;
- xkb_keymap_key_for_each(xkb_keymap, iterate_normal, &ita);
-
- for (int i=0; i<(KEYCODE_MAX-KEYCODE_MIN);i++)
- result->keysyms[i].eventCode = keyCode2eventCode(i+KEYCODE_MIN);
-
-end:
- if (xkb_keymap) xkb_keymap_unref(xkb_keymap);
- if (xkb_names.rules) free((void*)xkb_names.rules);
- if (xkb_names.model) free((void*)xkb_names.model);
- if (xkb_names.layout) free((void*)xkb_names.layout);
- return result;
-}
-
-void print_header(void) {
- printf( "#include \n"
- "#define SYM_LENGTH %d\n"
- "#define KEYCODE_MIN 8\n"
- "#define KEYCODE_MAX 255\n"
- "#define NOSYM {{0}, {0}}\n"
- "struct lorie_keymap {\n"
- "\tchar *name;\n"
- "\tstruct keysym {\n"
- "\t\tchar normal[SYM_LENGTH];\n"
- "\t\tchar shift[SYM_LENGTH];\n"
- "\t} keysyms[KEYCODE_MAX - KEYCODE_MIN];\n"
- "};\n\n",
- SYM_LENGTH
- );
-}
-
-void print_sym(char *sym) {
- int i;
- if (strlen(sym)) {
- printf("{");
- for(i=0; i 0 && i < SYM_LENGTH) printf(", ");
- printf("%d", (inormal) && strlen(keysym->shift)) {
- printf("\t\t{");
- print_sym(keysym->normal);
- printf(", ");
- print_sym(keysym->shift);
- printf("}");
- } else printf("\t\tNOSYM");
-}
-
-int ks_displayable(char *sym) {
- if (strlen(sym) == 0) return 0;
- if (strlen(sym) == 1) {
- switch(sym[0]) {
- case 8:
- case 10:
- case 13:
- case 27:
- case 30:
- case 127:
- return 0;
- }
- }
- return 1;
-}
-
-int find_keysym_by_eventcode(struct keymap* keymap, int eventCode) {
- for (int i=0; i<(KEYCODE_MAX-KEYCODE_MIN); i++) {
- if (keymap->keysyms[i].eventCode == eventCode)
- return i;
- }
- return -1;
-}
-
-void keymap_print(struct keymap* keymap) {
- if (!keymap) return;
- int i, j, latestEventCode;
-
- printf( "struct lorie_keymap lorie_keymap_%s = {\n"
- "\t.name = (char*) \"%s\",\n"
- "\t.keysyms = {\n",
- keymap->name, keymap->name
- );
- #if 0
- for (i=0; i<(KEYCODE_MAX-KEYCODE_MIN); i++) {
- print_keysym(&keymap->keysyms[i]);
- if (i!=(KEYCODE_MAX-KEYCODE_MIN-1)) printf(",");
-
- printf(" // keyCode: %d; eventCode: %d;", i + KEYCODE_MIN, keymap->keysyms[i].eventCode);
- if (ks_displayable(i, keymap->keysyms[i].normal)) printf(" normal: \"%s\";", keymap->keysyms[i].normal);
- if (ks_displayable(i, keymap->keysyms[i].shift)) printf(" shift: \"%s\";", keymap->keysyms[i].shift);
- printf("\n");
- }
- #else
- latestEventCode = 0;
- for (i=0; i<(KEYCODE_MAX-KEYCODE_MIN); i++) {
- if (keymap->keysyms[i].eventCode > latestEventCode &&
- keymap->keysyms[i].eventCode != KEY_UNKNOWN &&
- strlen(keymap->keysyms[i].normal) &&
- strlen(keymap->keysyms[i].shift)) // check if it is displayable and known
- latestEventCode = keymap->keysyms[i].eventCode;
- }
- //printf("\n\n\nLatest eventCode = %d\n\n\n\n", latestEventCode);
- for (i=0; i<=latestEventCode; i++) {
- j = find_keysym_by_eventcode(keymap, i);
- struct keysym* k = &keymap->keysyms[j];
- if (j >= 0) {
- print_keysym(k);
- if (j!=(KEYCODE_MAX-KEYCODE_MIN-1)) printf(",");
-
- printf(" // eventCode: %d;", i);
- if (ks_displayable(k->normal)) printf(" normal: \"%s\";", k->normal);
- if (ks_displayable(k->shift)) printf(" shift: \"%s\";", k->shift);
- printf("\n");
- } else printf("\t\tNOSYM, // eventCode: %d\n", i);
- }
- #endif
- printf("\t}\n};\n");
-}
-
-int main(void) {
- signal(SIGSEGV, handler);
- int i;
- struct xkb_context *xkb_context = NULL;
- struct xkb_rule_names xkb_names = {0};
- struct xkb_keymap *xkb_keymap = NULL;
- struct keymap* map = NULL;
- //char *keymaps[] = { "us", NULL };
- //char *keymaps[] = { "ru", "il", NULL };
- char *keymaps[] = { "ru", NULL };
-
- if (xkb_context == NULL) {
- xkb_context = xkb_context_new(0);
- if (xkb_context == NULL) {
- LOGE("failed to create XKB context\n");
- return 1;
- }
- }
- print_header();
- for (i=0; keymaps[i]; i++) {
- map = parse_keymap(xkb_context, keymaps[i]);
- if (!map) {
- LOGE("failed to parse keymap \"us\"");
- return 1;
- }
- keymap_print(map);
- }
-
- printf("\nstruct lorie_keymap *lorie_keymaps[] = {");
- for (i=0; keymaps[i]; i++) {
- printf("&lorie_keymap_%s, ", keymaps[i]);
- }
- printf("NULL};\n\n");
- printf("struct lorie_keymap_android {\n");
- printf("\tint eventCode;\n");
- printf("\tint shift;\n");
- printf("} lorie_keymap_android[] = {\n");
-
- int lastWasNull = 0;
- for (i=0; i<=ANDROID_KEYCODE_LAST; i++) {
- int evCode = 0;
- int shift = 0;
- if (android_keycode_to_linux_event_code(i, &evCode, &shift)) {
- if (lastWasNull) printf("\n");
- printf("\t{%d, %d}%s // keycode %d\n", evCode, shift, (i!=ANDROID_KEYCODE_LAST)?",":"", i);
- lastWasNull = 0;
- } else {
- if (!lastWasNull) printf("\t");
- printf("{0, 0}%s", (i!=ANDROID_KEYCODE_LAST)?", ":"\n");
- lastWasNull = 1;
- }
- };
- printf("};\n");
-}
diff --git a/app/src/main/jni/lorie/backend/android/locale/input-event-codes.h b/app/src/main/jni/lorie/backend/android/locale/input-event-codes.h
deleted file mode 100644
index a9902a7c2..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/input-event-codes.h
+++ /dev/null
@@ -1,861 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * Input event codes
- *
- * *** IMPORTANT ***
- * This file is not only included from C-code but also from devicetree source
- * files. As such this file MUST only contain comments and defines.
- *
- * Copyright (c) 1999-2002 Vojtech Pavlik
- * Copyright (c) 2015 Hans de Goede
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef _INPUT_EVENT_CODES_H
-#define _INPUT_EVENT_CODES_H
-
-/*
- * Device properties and quirks
- */
-
-#define INPUT_PROP_POINTER 0x00 /* needs a pointer */
-#define INPUT_PROP_DIRECT 0x01 /* direct input devices */
-#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
-#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
-#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
-#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
-#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
-
-#define INPUT_PROP_MAX 0x1f
-#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
-
-/*
- * Event types
- */
-
-#define EV_SYN 0x00
-#define EV_KEY 0x01
-#define EV_REL 0x02
-#define EV_ABS 0x03
-#define EV_MSC 0x04
-#define EV_SW 0x05
-#define EV_LED 0x11
-#define EV_SND 0x12
-#define EV_REP 0x14
-#define EV_FF 0x15
-#define EV_PWR 0x16
-#define EV_FF_STATUS 0x17
-#define EV_MAX 0x1f
-#define EV_CNT (EV_MAX+1)
-
-/*
- * Synchronization events.
- */
-
-#define SYN_REPORT 0
-#define SYN_CONFIG 1
-#define SYN_MT_REPORT 2
-#define SYN_DROPPED 3
-#define SYN_MAX 0xf
-#define SYN_CNT (SYN_MAX+1)
-
-/*
- * Keys and buttons
- *
- * Most of the keys/buttons are modeled after USB HUT 1.12
- * (see http://www.usb.org/developers/hidpage).
- * Abbreviations in the comments:
- * AC - Application Control
- * AL - Application Launch Button
- * SC - System Control
- */
-
-#define KEY_RESERVED 0
-#define KEY_ESC 1
-#define KEY_1 2
-#define KEY_2 3
-#define KEY_3 4
-#define KEY_4 5
-#define KEY_5 6
-#define KEY_6 7
-#define KEY_7 8
-#define KEY_8 9
-#define KEY_9 10
-#define KEY_0 11
-#define KEY_MINUS 12
-#define KEY_EQUAL 13
-#define KEY_BACKSPACE 14
-#define KEY_TAB 15
-#define KEY_Q 16
-#define KEY_W 17
-#define KEY_E 18
-#define KEY_R 19
-#define KEY_T 20
-#define KEY_Y 21
-#define KEY_U 22
-#define KEY_I 23
-#define KEY_O 24
-#define KEY_P 25
-#define KEY_LEFTBRACE 26
-#define KEY_RIGHTBRACE 27
-#define KEY_ENTER 28
-#define KEY_LEFTCTRL 29
-#define KEY_A 30
-#define KEY_S 31
-#define KEY_D 32
-#define KEY_F 33
-#define KEY_G 34
-#define KEY_H 35
-#define KEY_J 36
-#define KEY_K 37
-#define KEY_L 38
-#define KEY_SEMICOLON 39
-#define KEY_APOSTROPHE 40
-#define KEY_GRAVE 41
-#define KEY_LEFTSHIFT 42
-#define KEY_BACKSLASH 43
-#define KEY_Z 44
-#define KEY_X 45
-#define KEY_C 46
-#define KEY_V 47
-#define KEY_B 48
-#define KEY_N 49
-#define KEY_M 50
-#define KEY_COMMA 51
-#define KEY_DOT 52
-#define KEY_SLASH 53
-#define KEY_RIGHTSHIFT 54
-#define KEY_KPASTERISK 55
-#define KEY_LEFTALT 56
-#define KEY_SPACE 57
-#define KEY_CAPSLOCK 58
-#define KEY_F1 59
-#define KEY_F2 60
-#define KEY_F3 61
-#define KEY_F4 62
-#define KEY_F5 63
-#define KEY_F6 64
-#define KEY_F7 65
-#define KEY_F8 66
-#define KEY_F9 67
-#define KEY_F10 68
-#define KEY_NUMLOCK 69
-#define KEY_SCROLLLOCK 70
-#define KEY_KP7 71
-#define KEY_KP8 72
-#define KEY_KP9 73
-#define KEY_KPMINUS 74
-#define KEY_KP4 75
-#define KEY_KP5 76
-#define KEY_KP6 77
-#define KEY_KPPLUS 78
-#define KEY_KP1 79
-#define KEY_KP2 80
-#define KEY_KP3 81
-#define KEY_KP0 82
-#define KEY_KPDOT 83
-
-#define KEY_ZENKAKUHANKAKU 85
-#define KEY_102ND 86
-#define KEY_F11 87
-#define KEY_F12 88
-#define KEY_RO 89
-#define KEY_KATAKANA 90
-#define KEY_HIRAGANA 91
-#define KEY_HENKAN 92
-#define KEY_KATAKANAHIRAGANA 93
-#define KEY_MUHENKAN 94
-#define KEY_KPJPCOMMA 95
-#define KEY_KPENTER 96
-#define KEY_RIGHTCTRL 97
-#define KEY_KPSLASH 98
-#define KEY_SYSRQ 99
-#define KEY_RIGHTALT 100
-#define KEY_LINEFEED 101
-#define KEY_HOME 102
-#define KEY_UP 103
-#define KEY_PAGEUP 104
-#define KEY_LEFT 105
-#define KEY_RIGHT 106
-#define KEY_END 107
-#define KEY_DOWN 108
-#define KEY_PAGEDOWN 109
-#define KEY_INSERT 110
-#define KEY_DELETE 111
-#define KEY_MACRO 112
-#define KEY_MUTE 113
-#define KEY_VOLUMEDOWN 114
-#define KEY_VOLUMEUP 115
-#define KEY_POWER 116 /* SC System Power Down */
-#define KEY_KPEQUAL 117
-#define KEY_KPPLUSMINUS 118
-#define KEY_PAUSE 119
-#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */
-
-#define KEY_KPCOMMA 121
-#define KEY_HANGEUL 122
-#define KEY_HANGUEL KEY_HANGEUL
-#define KEY_HANJA 123
-#define KEY_YEN 124
-#define KEY_LEFTMETA 125
-#define KEY_RIGHTMETA 126
-#define KEY_COMPOSE 127
-
-#define KEY_STOP 128 /* AC Stop */
-#define KEY_AGAIN 129
-#define KEY_PROPS 130 /* AC Properties */
-#define KEY_UNDO 131 /* AC Undo */
-#define KEY_FRONT 132
-#define KEY_COPY 133 /* AC Copy */
-#define KEY_OPEN 134 /* AC Open */
-#define KEY_PASTE 135 /* AC Paste */
-#define KEY_FIND 136 /* AC Search */
-#define KEY_CUT 137 /* AC Cut */
-#define KEY_HELP 138 /* AL Integrated Help Center */
-#define KEY_MENU 139 /* Menu (show menu) */
-#define KEY_CALC 140 /* AL Calculator */
-#define KEY_SETUP 141
-#define KEY_SLEEP 142 /* SC System Sleep */
-#define KEY_WAKEUP 143 /* System Wake Up */
-#define KEY_FILE 144 /* AL Local Machine Browser */
-#define KEY_SENDFILE 145
-#define KEY_DELETEFILE 146
-#define KEY_XFER 147
-#define KEY_PROG1 148
-#define KEY_PROG2 149
-#define KEY_WWW 150 /* AL Internet Browser */
-#define KEY_MSDOS 151
-#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
-#define KEY_SCREENLOCK KEY_COFFEE
-#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */
-#define KEY_DIRECTION KEY_ROTATE_DISPLAY
-#define KEY_CYCLEWINDOWS 154
-#define KEY_MAIL 155
-#define KEY_BOOKMARKS 156 /* AC Bookmarks */
-#define KEY_COMPUTER 157
-#define KEY_BACK 158 /* AC Back */
-#define KEY_FORWARD 159 /* AC Forward */
-#define KEY_CLOSECD 160
-#define KEY_EJECTCD 161
-#define KEY_EJECTCLOSECD 162
-#define KEY_NEXTSONG 163
-#define KEY_PLAYPAUSE 164
-#define KEY_PREVIOUSSONG 165
-#define KEY_STOPCD 166
-#define KEY_RECORD 167
-#define KEY_REWIND 168
-#define KEY_PHONE 169 /* Media Select Telephone */
-#define KEY_ISO 170
-#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
-#define KEY_HOMEPAGE 172 /* AC Home */
-#define KEY_REFRESH 173 /* AC Refresh */
-#define KEY_EXIT 174 /* AC Exit */
-#define KEY_MOVE 175
-#define KEY_EDIT 176
-#define KEY_SCROLLUP 177
-#define KEY_SCROLLDOWN 178
-#define KEY_KPLEFTPAREN 179
-#define KEY_KPRIGHTPAREN 180
-#define KEY_NEW 181 /* AC New */
-#define KEY_REDO 182 /* AC Redo/Repeat */
-
-#define KEY_F13 183
-#define KEY_F14 184
-#define KEY_F15 185
-#define KEY_F16 186
-#define KEY_F17 187
-#define KEY_F18 188
-#define KEY_F19 189
-#define KEY_F20 190
-#define KEY_F21 191
-#define KEY_F22 192
-#define KEY_F23 193
-#define KEY_F24 194
-
-#define KEY_PLAYCD 200
-#define KEY_PAUSECD 201
-#define KEY_PROG3 202
-#define KEY_PROG4 203
-#define KEY_DASHBOARD 204 /* AL Dashboard */
-#define KEY_SUSPEND 205
-#define KEY_CLOSE 206 /* AC Close */
-#define KEY_PLAY 207
-#define KEY_FASTFORWARD 208
-#define KEY_BASSBOOST 209
-#define KEY_PRINT 210 /* AC Print */
-#define KEY_HP 211
-#define KEY_CAMERA 212
-#define KEY_SOUND 213
-#define KEY_QUESTION 214
-#define KEY_EMAIL 215
-#define KEY_CHAT 216
-#define KEY_SEARCH 217
-#define KEY_CONNECT 218
-#define KEY_FINANCE 219 /* AL Checkbook/Finance */
-#define KEY_SPORT 220
-#define KEY_SHOP 221
-#define KEY_ALTERASE 222
-#define KEY_CANCEL 223 /* AC Cancel */
-#define KEY_BRIGHTNESSDOWN 224
-#define KEY_BRIGHTNESSUP 225
-#define KEY_MEDIA 226
-
-#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video
- outputs (Monitor/LCD/TV-out/etc) */
-#define KEY_KBDILLUMTOGGLE 228
-#define KEY_KBDILLUMDOWN 229
-#define KEY_KBDILLUMUP 230
-
-#define KEY_SEND 231 /* AC Send */
-#define KEY_REPLY 232 /* AC Reply */
-#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
-#define KEY_SAVE 234 /* AC Save */
-#define KEY_DOCUMENTS 235
-
-#define KEY_BATTERY 236
-
-#define KEY_BLUETOOTH 237
-#define KEY_WLAN 238
-#define KEY_UWB 239
-
-#define KEY_UNKNOWN 240
-
-#define KEY_VIDEO_NEXT 241 /* drive next video source */
-#define KEY_VIDEO_PREV 242 /* drive previous video source */
-#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
-#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
- brightness control is off,
- rely on ambient */
-#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
-#define KEY_DISPLAY_OFF 245 /* display device to off state */
-
-#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
-#define KEY_WIMAX KEY_WWAN
-#define KEY_RFKILL 247 /* Key that controls all radios */
-
-#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
-
-/* Code 255 is reserved for special needs of AT keyboard driver */
-
-#define BTN_MISC 0x100
-#define BTN_0 0x100
-#define BTN_1 0x101
-#define BTN_2 0x102
-#define BTN_3 0x103
-#define BTN_4 0x104
-#define BTN_5 0x105
-#define BTN_6 0x106
-#define BTN_7 0x107
-#define BTN_8 0x108
-#define BTN_9 0x109
-
-#define BTN_MOUSE 0x110
-#define BTN_LEFT 0x110
-#define BTN_RIGHT 0x111
-#define BTN_MIDDLE 0x112
-#define BTN_SIDE 0x113
-#define BTN_EXTRA 0x114
-#define BTN_FORWARD 0x115
-#define BTN_BACK 0x116
-#define BTN_TASK 0x117
-
-#define BTN_JOYSTICK 0x120
-#define BTN_TRIGGER 0x120
-#define BTN_THUMB 0x121
-#define BTN_THUMB2 0x122
-#define BTN_TOP 0x123
-#define BTN_TOP2 0x124
-#define BTN_PINKIE 0x125
-#define BTN_BASE 0x126
-#define BTN_BASE2 0x127
-#define BTN_BASE3 0x128
-#define BTN_BASE4 0x129
-#define BTN_BASE5 0x12a
-#define BTN_BASE6 0x12b
-#define BTN_DEAD 0x12f
-
-#define BTN_GAMEPAD 0x130
-#define BTN_SOUTH 0x130
-#define BTN_A BTN_SOUTH
-#define BTN_EAST 0x131
-#define BTN_B BTN_EAST
-#define BTN_C 0x132
-#define BTN_NORTH 0x133
-#define BTN_X BTN_NORTH
-#define BTN_WEST 0x134
-#define BTN_Y BTN_WEST
-#define BTN_Z 0x135
-#define BTN_TL 0x136
-#define BTN_TR 0x137
-#define BTN_TL2 0x138
-#define BTN_TR2 0x139
-#define BTN_SELECT 0x13a
-#define BTN_START 0x13b
-#define BTN_MODE 0x13c
-#define BTN_THUMBL 0x13d
-#define BTN_THUMBR 0x13e
-
-#define BTN_DIGI 0x140
-#define BTN_TOOL_PEN 0x140
-#define BTN_TOOL_RUBBER 0x141
-#define BTN_TOOL_BRUSH 0x142
-#define BTN_TOOL_PENCIL 0x143
-#define BTN_TOOL_AIRBRUSH 0x144
-#define BTN_TOOL_FINGER 0x145
-#define BTN_TOOL_MOUSE 0x146
-#define BTN_TOOL_LENS 0x147
-#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
-#define BTN_STYLUS3 0x149
-#define BTN_TOUCH 0x14a
-#define BTN_STYLUS 0x14b
-#define BTN_STYLUS2 0x14c
-#define BTN_TOOL_DOUBLETAP 0x14d
-#define BTN_TOOL_TRIPLETAP 0x14e
-#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */
-
-#define BTN_WHEEL 0x150
-#define BTN_GEAR_DOWN 0x150
-#define BTN_GEAR_UP 0x151
-
-#define KEY_OK 0x160
-#define KEY_SELECT 0x161
-#define KEY_GOTO 0x162
-#define KEY_CLEAR 0x163
-#define KEY_POWER2 0x164
-#define KEY_OPTION 0x165
-#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */
-#define KEY_TIME 0x167
-#define KEY_VENDOR 0x168
-#define KEY_ARCHIVE 0x169
-#define KEY_PROGRAM 0x16a /* Media Select Program Guide */
-#define KEY_CHANNEL 0x16b
-#define KEY_FAVORITES 0x16c
-#define KEY_EPG 0x16d
-#define KEY_PVR 0x16e /* Media Select Home */
-#define KEY_MHP 0x16f
-#define KEY_LANGUAGE 0x170
-#define KEY_TITLE 0x171
-#define KEY_SUBTITLE 0x172
-#define KEY_ANGLE 0x173
-#define KEY_ZOOM 0x174
-#define KEY_MODE 0x175
-#define KEY_KEYBOARD 0x176
-#define KEY_SCREEN 0x177
-#define KEY_PC 0x178 /* Media Select Computer */
-#define KEY_TV 0x179 /* Media Select TV */
-#define KEY_TV2 0x17a /* Media Select Cable */
-#define KEY_VCR 0x17b /* Media Select VCR */
-#define KEY_VCR2 0x17c /* VCR Plus */
-#define KEY_SAT 0x17d /* Media Select Satellite */
-#define KEY_SAT2 0x17e
-#define KEY_CD 0x17f /* Media Select CD */
-#define KEY_TAPE 0x180 /* Media Select Tape */
-#define KEY_RADIO 0x181
-#define KEY_TUNER 0x182 /* Media Select Tuner */
-#define KEY_PLAYER 0x183
-#define KEY_TEXT 0x184
-#define KEY_DVD 0x185 /* Media Select DVD */
-#define KEY_AUX 0x186
-#define KEY_MP3 0x187
-#define KEY_AUDIO 0x188 /* AL Audio Browser */
-#define KEY_VIDEO 0x189 /* AL Movie Browser */
-#define KEY_DIRECTORY 0x18a
-#define KEY_LIST 0x18b
-#define KEY_MEMO 0x18c /* Media Select Messages */
-#define KEY_CALENDAR 0x18d
-#define KEY_RED 0x18e
-#define KEY_GREEN 0x18f
-#define KEY_YELLOW 0x190
-#define KEY_BLUE 0x191
-#define KEY_CHANNELUP 0x192 /* Channel Increment */
-#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */
-#define KEY_FIRST 0x194
-#define KEY_LAST 0x195 /* Recall Last */
-#define KEY_AB 0x196
-#define KEY_NEXT 0x197
-#define KEY_RESTART 0x198
-#define KEY_SLOW 0x199
-#define KEY_SHUFFLE 0x19a
-#define KEY_BREAK 0x19b
-#define KEY_PREVIOUS 0x19c
-#define KEY_DIGITS 0x19d
-#define KEY_TEEN 0x19e
-#define KEY_TWEN 0x19f
-#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */
-#define KEY_GAMES 0x1a1 /* Media Select Games */
-#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */
-#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */
-#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */
-#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */
-#define KEY_EDITOR 0x1a6 /* AL Text Editor */
-#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */
-#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */
-#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */
-#define KEY_DATABASE 0x1aa /* AL Database App */
-#define KEY_NEWS 0x1ab /* AL Newsreader */
-#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */
-#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
-#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
-#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
-#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
-#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
-#define KEY_LOGOFF 0x1b1 /* AL Logoff */
-
-#define KEY_DOLLAR 0x1b2
-#define KEY_EURO 0x1b3
-
-#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */
-#define KEY_FRAMEFORWARD 0x1b5
-#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */
-#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */
-#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */
-#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */
-#define KEY_IMAGES 0x1ba /* AL Image Browser */
-
-#define KEY_DEL_EOL 0x1c0
-#define KEY_DEL_EOS 0x1c1
-#define KEY_INS_LINE 0x1c2
-#define KEY_DEL_LINE 0x1c3
-
-#define KEY_FN 0x1d0
-#define KEY_FN_ESC 0x1d1
-#define KEY_FN_F1 0x1d2
-#define KEY_FN_F2 0x1d3
-#define KEY_FN_F3 0x1d4
-#define KEY_FN_F4 0x1d5
-#define KEY_FN_F5 0x1d6
-#define KEY_FN_F6 0x1d7
-#define KEY_FN_F7 0x1d8
-#define KEY_FN_F8 0x1d9
-#define KEY_FN_F9 0x1da
-#define KEY_FN_F10 0x1db
-#define KEY_FN_F11 0x1dc
-#define KEY_FN_F12 0x1dd
-#define KEY_FN_1 0x1de
-#define KEY_FN_2 0x1df
-#define KEY_FN_D 0x1e0
-#define KEY_FN_E 0x1e1
-#define KEY_FN_F 0x1e2
-#define KEY_FN_S 0x1e3
-#define KEY_FN_B 0x1e4
-
-#define KEY_BRL_DOT1 0x1f1
-#define KEY_BRL_DOT2 0x1f2
-#define KEY_BRL_DOT3 0x1f3
-#define KEY_BRL_DOT4 0x1f4
-#define KEY_BRL_DOT5 0x1f5
-#define KEY_BRL_DOT6 0x1f6
-#define KEY_BRL_DOT7 0x1f7
-#define KEY_BRL_DOT8 0x1f8
-#define KEY_BRL_DOT9 0x1f9
-#define KEY_BRL_DOT10 0x1fa
-
-#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */
-#define KEY_NUMERIC_1 0x201 /* and other keypads */
-#define KEY_NUMERIC_2 0x202
-#define KEY_NUMERIC_3 0x203
-#define KEY_NUMERIC_4 0x204
-#define KEY_NUMERIC_5 0x205
-#define KEY_NUMERIC_6 0x206
-#define KEY_NUMERIC_7 0x207
-#define KEY_NUMERIC_8 0x208
-#define KEY_NUMERIC_9 0x209
-#define KEY_NUMERIC_STAR 0x20a
-#define KEY_NUMERIC_POUND 0x20b
-#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */
-#define KEY_NUMERIC_B 0x20d
-#define KEY_NUMERIC_C 0x20e
-#define KEY_NUMERIC_D 0x20f
-
-#define KEY_CAMERA_FOCUS 0x210
-#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */
-
-#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */
-#define KEY_TOUCHPAD_ON 0x213
-#define KEY_TOUCHPAD_OFF 0x214
-
-#define KEY_CAMERA_ZOOMIN 0x215
-#define KEY_CAMERA_ZOOMOUT 0x216
-#define KEY_CAMERA_UP 0x217
-#define KEY_CAMERA_DOWN 0x218
-#define KEY_CAMERA_LEFT 0x219
-#define KEY_CAMERA_RIGHT 0x21a
-
-#define KEY_ATTENDANT_ON 0x21b
-#define KEY_ATTENDANT_OFF 0x21c
-#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */
-#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */
-
-#define BTN_DPAD_UP 0x220
-#define BTN_DPAD_DOWN 0x221
-#define BTN_DPAD_LEFT 0x222
-#define BTN_DPAD_RIGHT 0x223
-
-#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
-#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
-
-#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
-#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
-#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
-#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
-#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
-#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
-#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
-#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
-
-#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
-#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
-
-#define KEY_KBDINPUTASSIST_PREV 0x260
-#define KEY_KBDINPUTASSIST_NEXT 0x261
-#define KEY_KBDINPUTASSIST_PREVGROUP 0x262
-#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263
-#define KEY_KBDINPUTASSIST_ACCEPT 0x264
-#define KEY_KBDINPUTASSIST_CANCEL 0x265
-
-/* Diagonal movement keys */
-#define KEY_RIGHT_UP 0x266
-#define KEY_RIGHT_DOWN 0x267
-#define KEY_LEFT_UP 0x268
-#define KEY_LEFT_DOWN 0x269
-
-#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */
-/* Show Top Menu of the Media (e.g. DVD) */
-#define KEY_MEDIA_TOP_MENU 0x26b
-#define KEY_NUMERIC_11 0x26c
-#define KEY_NUMERIC_12 0x26d
-/*
- * Toggle Audio Description: refers to an audio service that helps blind and
- * visually impaired consumers understand the action in a program. Note: in
- * some countries this is referred to as "Video Description".
- */
-#define KEY_AUDIO_DESC 0x26e
-#define KEY_3D_MODE 0x26f
-#define KEY_NEXT_FAVORITE 0x270
-#define KEY_STOP_RECORD 0x271
-#define KEY_PAUSE_RECORD 0x272
-#define KEY_VOD 0x273 /* Video on Demand */
-#define KEY_UNMUTE 0x274
-#define KEY_FASTREVERSE 0x275
-#define KEY_SLOWREVERSE 0x276
-/*
- * Control a data application associated with the currently viewed channel,
- * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
- */
-#define KEY_DATA 0x277
-#define KEY_ONSCREEN_KEYBOARD 0x278
-
-#define BTN_TRIGGER_HAPPY 0x2c0
-#define BTN_TRIGGER_HAPPY1 0x2c0
-#define BTN_TRIGGER_HAPPY2 0x2c1
-#define BTN_TRIGGER_HAPPY3 0x2c2
-#define BTN_TRIGGER_HAPPY4 0x2c3
-#define BTN_TRIGGER_HAPPY5 0x2c4
-#define BTN_TRIGGER_HAPPY6 0x2c5
-#define BTN_TRIGGER_HAPPY7 0x2c6
-#define BTN_TRIGGER_HAPPY8 0x2c7
-#define BTN_TRIGGER_HAPPY9 0x2c8
-#define BTN_TRIGGER_HAPPY10 0x2c9
-#define BTN_TRIGGER_HAPPY11 0x2ca
-#define BTN_TRIGGER_HAPPY12 0x2cb
-#define BTN_TRIGGER_HAPPY13 0x2cc
-#define BTN_TRIGGER_HAPPY14 0x2cd
-#define BTN_TRIGGER_HAPPY15 0x2ce
-#define BTN_TRIGGER_HAPPY16 0x2cf
-#define BTN_TRIGGER_HAPPY17 0x2d0
-#define BTN_TRIGGER_HAPPY18 0x2d1
-#define BTN_TRIGGER_HAPPY19 0x2d2
-#define BTN_TRIGGER_HAPPY20 0x2d3
-#define BTN_TRIGGER_HAPPY21 0x2d4
-#define BTN_TRIGGER_HAPPY22 0x2d5
-#define BTN_TRIGGER_HAPPY23 0x2d6
-#define BTN_TRIGGER_HAPPY24 0x2d7
-#define BTN_TRIGGER_HAPPY25 0x2d8
-#define BTN_TRIGGER_HAPPY26 0x2d9
-#define BTN_TRIGGER_HAPPY27 0x2da
-#define BTN_TRIGGER_HAPPY28 0x2db
-#define BTN_TRIGGER_HAPPY29 0x2dc
-#define BTN_TRIGGER_HAPPY30 0x2dd
-#define BTN_TRIGGER_HAPPY31 0x2de
-#define BTN_TRIGGER_HAPPY32 0x2df
-#define BTN_TRIGGER_HAPPY33 0x2e0
-#define BTN_TRIGGER_HAPPY34 0x2e1
-#define BTN_TRIGGER_HAPPY35 0x2e2
-#define BTN_TRIGGER_HAPPY36 0x2e3
-#define BTN_TRIGGER_HAPPY37 0x2e4
-#define BTN_TRIGGER_HAPPY38 0x2e5
-#define BTN_TRIGGER_HAPPY39 0x2e6
-#define BTN_TRIGGER_HAPPY40 0x2e7
-
-/* We avoid low common keys in module aliases so they don't get huge. */
-#define KEY_MIN_INTERESTING KEY_MUTE
-#define KEY_MAX 0x2ff
-#define KEY_CNT (KEY_MAX+1)
-
-/*
- * Relative axes
- */
-
-#define REL_X 0x00
-#define REL_Y 0x01
-#define REL_Z 0x02
-#define REL_RX 0x03
-#define REL_RY 0x04
-#define REL_RZ 0x05
-#define REL_HWHEEL 0x06
-#define REL_DIAL 0x07
-#define REL_WHEEL 0x08
-#define REL_MISC 0x09
-/*
- * 0x0a is reserved and should not be used in input drivers.
- * It was used by HID as REL_MISC+1 and userspace needs to detect if
- * the next REL_* event is correct or is just REL_MISC + n.
- * We define here REL_RESERVED so userspace can rely on it and detect
- * the situation described above.
- */
-#define REL_RESERVED 0x0a
-#define REL_WHEEL_HI_RES 0x0b
-#define REL_HWHEEL_HI_RES 0x0c
-#define REL_MAX 0x0f
-#define REL_CNT (REL_MAX+1)
-
-/*
- * Absolute axes
- */
-
-#define ABS_X 0x00
-#define ABS_Y 0x01
-#define ABS_Z 0x02
-#define ABS_RX 0x03
-#define ABS_RY 0x04
-#define ABS_RZ 0x05
-#define ABS_THROTTLE 0x06
-#define ABS_RUDDER 0x07
-#define ABS_WHEEL 0x08
-#define ABS_GAS 0x09
-#define ABS_BRAKE 0x0a
-#define ABS_HAT0X 0x10
-#define ABS_HAT0Y 0x11
-#define ABS_HAT1X 0x12
-#define ABS_HAT1Y 0x13
-#define ABS_HAT2X 0x14
-#define ABS_HAT2Y 0x15
-#define ABS_HAT3X 0x16
-#define ABS_HAT3Y 0x17
-#define ABS_PRESSURE 0x18
-#define ABS_DISTANCE 0x19
-#define ABS_TILT_X 0x1a
-#define ABS_TILT_Y 0x1b
-#define ABS_TOOL_WIDTH 0x1c
-
-#define ABS_VOLUME 0x20
-
-#define ABS_MISC 0x28
-
-/*
- * 0x2e is reserved and should not be used in input drivers.
- * It was used by HID as ABS_MISC+6 and userspace needs to detect if
- * the next ABS_* event is correct or is just ABS_MISC + n.
- * We define here ABS_RESERVED so userspace can rely on it and detect
- * the situation described above.
- */
-#define ABS_RESERVED 0x2e
-
-#define ABS_MT_SLOT 0x2f /* MT slot being modified */
-#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
-#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
-#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
-#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
-#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
-#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
-#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
-#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
-#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
-#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
-#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
-#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
-#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
-#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
-
-
-#define ABS_MAX 0x3f
-#define ABS_CNT (ABS_MAX+1)
-
-/*
- * Switch events
- */
-
-#define SW_LID 0x00 /* set = lid shut */
-#define SW_TABLET_MODE 0x01 /* set = tablet mode */
-#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */
-#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any"
- set = radio enabled */
-#define SW_RADIO SW_RFKILL_ALL /* deprecated */
-#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */
-#define SW_DOCK 0x05 /* set = plugged into dock */
-#define SW_LINEOUT_INSERT 0x06 /* set = inserted */
-#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */
-#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */
-#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */
-#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */
-#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */
-#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
-#define SW_LINEIN_INSERT 0x0d /* set = inserted */
-#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
-#define SW_PEN_INSERTED 0x0f /* set = pen inserted */
-#define SW_MAX 0x0f
-#define SW_CNT (SW_MAX+1)
-
-/*
- * Misc events
- */
-
-#define MSC_SERIAL 0x00
-#define MSC_PULSELED 0x01
-#define MSC_GESTURE 0x02
-#define MSC_RAW 0x03
-#define MSC_SCAN 0x04
-#define MSC_TIMESTAMP 0x05
-#define MSC_MAX 0x07
-#define MSC_CNT (MSC_MAX+1)
-
-/*
- * LEDs
- */
-
-#define LED_NUML 0x00
-#define LED_CAPSL 0x01
-#define LED_SCROLLL 0x02
-#define LED_COMPOSE 0x03
-#define LED_KANA 0x04
-#define LED_SLEEP 0x05
-#define LED_SUSPEND 0x06
-#define LED_MUTE 0x07
-#define LED_MISC 0x08
-#define LED_MAIL 0x09
-#define LED_CHARGING 0x0a
-#define LED_MAX 0x0f
-#define LED_CNT (LED_MAX+1)
-
-/*
- * Autorepeat values
- */
-
-#define REP_DELAY 0x00
-#define REP_PERIOD 0x01
-#define REP_MAX 0x01
-#define REP_CNT (REP_MAX+1)
-
-/*
- * Sounds
- */
-
-#define SND_CLICK 0x00
-#define SND_BELL 0x01
-#define SND_TONE 0x02
-#define SND_MAX 0x07
-#define SND_CNT (SND_MAX+1)
-
-#endif
diff --git a/app/src/main/jni/lorie/backend/android/locale/log.h b/app/src/main/jni/lorie/backend/android/locale/log.h
deleted file mode 100644
index b3da08ee5..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/log.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifdef __ANDROID__
-#include
-
-#ifndef LOG_TAG
-#define LOG_TAG "LorieNative"
-#endif
-
-#define LOG(prio, ...) __android_log_print(prio, LOG_TAG, __VA_ARGS__)
-
-#define LOGI(...) LOG(ANDROID_LOG_INFO, __VA_ARGS__)
-#define LOGW(...) LOG(ANDROID_LOG_WARN, __VA_ARGS__)
-#define LOGD(...) LOG(ANDROID_LOG_DEBUG, __VA_ARGS__)
-#define LOGV(...) LOG(ANDROID_LOG_VERBOSE, __VA_ARGS__)
-#define LOGE(...) LOG(ANDROID_LOG_ERROR, __VA_ARGS__)
-#define LOGF(...) LOG(ANDROID_LOG_FATAL, __VA_ARGS__)
-
-#else
-#include
-
-#define LOG(prio, ...) { printf(prio __VA_ARGS__); printf("\n"); }
-
-#define LOGI(...) LOG("I: " , __VA_ARGS__)
-#define LOGW(...) LOG("W: " , __VA_ARGS__)
-#define LOGD(...) LOG("D: " , __VA_ARGS__)
-#define LOGV(...) LOG("V: " , __VA_ARGS__)
-#define LOGE(...) LOG("E: " , __VA_ARGS__)
-#define LOGF(...) LOG("F: " , __VA_ARGS__)
-
-#endif
-#ifdef DBG
-#undef DBG
-#endif
-
-#define DBG LOGD("Here! %s %d", __FILE__, __LINE__)
-
-extern int trace_funcs;
-#if defined(TRACE_FUNCS) && !defined(__ANDROID__)
-#include
-#include
-void __attribute__((no_instrument_function))
-__cyg_profile_func_enter (void *func, void *caller) {
- if (!trace_funcs) return;
- Dl_info info;
- if (dladdr(func, &info))
- LOGD ("enter %p [%s] %s\n", func, (info.dli_fname) ? info.dli_fname : "?", info.dli_sname ? info.dli_sname : "?");
-}
-void __attribute__((no_instrument_function))
-__cyg_profile_func_exit (void *func, void *caller) {
- if (!trace_funcs) return;
- Dl_info info;
- if (dladdr(func, &info))
- LOGD ("leave %p [%s] %s\n", func, (info.dli_fname) ? info.dli_fname : "?", info.dli_sname ? info.dli_sname : "?");
-}
-
-#define static // backtrace do not report static function names
-#endif
diff --git a/app/src/main/jni/lorie/backend/android/locale/make.sh b/app/src/main/jni/lorie/backend/android/locale/make.sh
deleted file mode 100755
index db06240e6..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/make.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -e -x
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-cd ${DIR}
-rm -f test generator
-gcc -o generator generator.c android-utils.c -lxkbcommon -g -rdynamic
-#./generator
-./generator > ../keymaps.h
-#gcc -o test test.c -lX11 -g -rdynamic
-#./test
diff --git a/app/src/main/jni/lorie/backend/android/locale/test.c b/app/src/main/jni/lorie/backend/android/locale/test.c
deleted file mode 100644
index 77315370e..000000000
--- a/app/src/main/jni/lorie/backend/android/locale/test.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "keymaps.h"
-void handler(int sig) {
- void *array[10];
- size_t size;
-
- // get void*'s for all entries on the stack
- size = backtrace(array, 10);
-
- // print out all the frames to stderr
- fprintf(stderr, "Error: signal %d:\n", sig);
- backtrace_symbols_fd(array, size, STDERR_FILENO);
- exit(1);
-}
-
-void getSymLayout1(int keyCode, char* sym) {
- int i;
- for (i=0; lorie_keymaps[i]; i++) {
- if (lorie_keymaps[i]->keysyms[keyCode - KEYCODE_MIN].normal[0] == sym[0]) {
- printf("aasdasd\n");
- return;
- }
- }
- printf("lorie_keymaps[i]->keysyms[%d].normal[0] = %c; sym[0] = %c\n",
- keyCode + KEYCODE_MIN,
- lorie_keymaps[0]->keysyms[keyCode - KEYCODE_MIN].normal[0],
- sym[0]);
- printf("aqweqweqwe\n");
-}
-
-char* getSymLayout(int keyCode, char* sym) {
- int i, j;
- for (i=0; lorie_keymaps[i]; i++) {
- for (j=0; j<(KEYCODE_MAX-KEYCODE_MIN); j++) {
- if (!strcmp(sym, lorie_keymaps[i]->keysyms[j].normal)) return lorie_keymaps[i]->name;
- }
- }
- for (i=0; lorie_keymaps[i]; i++) {
- for (j=0; j<(KEYCODE_MAX-KEYCODE_MIN); j++) {
- if (!strcmp(sym, lorie_keymaps[i]->keysyms[j].shift)) return lorie_keymaps[i]->name;
- }
- }
- return "unknown";
-}
-
-int main(void){
- signal(SIGSEGV, handler);
-
- char *teststrings[] = {"q", "w", "e", "1", "2", "3", "ф", "ы", "в", "ф", "א", "ת", "ה", NULL};
- for (int i=0; teststrings[i]; i++) {
- printf("sym: %s, layout: %s\n", teststrings[i], getSymLayout(0, teststrings[i]));
- }
-}
diff --git a/app/src/main/jni/lorie/backend/android/utils.c b/app/src/main/jni/lorie/backend/android/utils.c
deleted file mode 100644
index 6a9594074..000000000
--- a/app/src/main/jni/lorie/backend/android/utils.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include
-#include "keymaps.h"
-void get_character_data(char** layout, int *shift, int *ec, char *ch) {
- int i;
- for (i=0; lorie_keymaps[i]; i++) {
- for ((*ec)=0; (*ec)<(KEYCODE_MAX-KEYCODE_MIN); (*ec)++) {
- if (!strcmp(ch, lorie_keymaps[i]->keysyms[*ec].normal)) {
- *layout = lorie_keymaps[i]->name;
- *shift = 0;
- return;
- }
- if (!strcmp(ch, lorie_keymaps[i]->keysyms[*ec].shift)) {
- *layout = lorie_keymaps[i]->name;
- *shift = 1;
- return;
- }
- }
- }
- *ec = 0;
- *shift = 0;
-}
-
-void android_keycode_get_eventcode(int kc, int *ec, int *shift) {
- if (lorie_keymap_android[kc].eventCode != 0) {
- *ec = lorie_keymap_android[kc].eventCode;
- *shift = lorie_keymap_android[kc].shift;
- } else {
- *ec = *shift = 0;
- }
-};
diff --git a/app/src/main/jni/lorie/compositor.cpp b/app/src/main/jni/lorie/compositor.cpp
deleted file mode 100644
index 2a4aab4a4..000000000
--- a/app/src/main/jni/lorie/compositor.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-#include
-#include
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
-
-using namespace wayland;
-
-lorie_compositor::lorie_compositor() {
- on_client = [=](client_t* client) {
- client->user_data() = new client_data;
- client->on_destroy = [=] {
- bool request_redraw{};
-
- if (screen.sfc && screen.sfc->client() == client) {
- screen.sfc = nullptr;
- request_redraw = true;
- }
-
- if (cursor.sfc && cursor.sfc->client() == client) {
- screen.sfc = nullptr;
- request_redraw = true;
- }
-
- if (request_redraw)
- redraw(true);
-
- if(!screen.sfc)
- set_renderer_visibility(false);
- LOGI("Client destroyed");
- };
- };
- global_compositor.on_bind = [=] (client_t*, compositor_t* compositor) {
- compositor->on_create_region = [](region_t* region) {
- region->on__destroy = [=] {
- region->destroy();
- };
- };
- compositor->on_create_surface = [=](surface_t* surface) {
- auto data = new surface_data;
- data->id = surface->id(); // For debugging purposes
- surface->user_data() = data;
- surface->on_attach = [=](buffer_t* b, int32_t, int32_t) {
- data->buffer = b;
- };
- surface->on_damage = [=](int32_t, int32_t, int32_t, int32_t) {
- data->damaged = true;
- };
- surface->on_damage_buffer = [=](int32_t, int32_t, int32_t, int32_t) {
- data->damaged = true;
- };
- surface->on_frame = [=] (callback_t* cb) {
- data->frame_callback = cb;
- };
- surface->on_commit = [=] {
- redraw();
- if (data->buffer)
- data->buffer->release();
- if (data->frame_callback) {
- data->frame_callback->done(resource_t::timestamp());
- data->frame_callback = nullptr;
- }
- };
- surface->on__destroy = [=] {
- surface->destroy();
- };
- };
- };
- global_seat.on_bind = [=, this](client_t* client, seat_t* seat) {
- seat->capabilities (seat_capability::touch | seat_capability::keyboard | seat_capability::pointer);
- seat->name("default");
-
- auto data = any_cast(client->user_data());
-
- seat->on_get_pointer = [=, this](pointer_t* pointer) {
- LOGV("Client requested seat pointer");
- data->pointer = pointer;
- if (screen.sfc)
- pointer->enter(next_serial(), screen.sfc, 0, 0);
-
- pointer->on_set_cursor = [=](uint32_t, wayland::surface_t* sfc, int32_t x, int32_t y) {
- cursor.sfc = sfc;
- cursor.hotspot_x = x;
- cursor.hotspot_y = y;
-
- if (sfc)
- any_cast(sfc->user_data())->damaged = true;
- };
- pointer->on_release = [=] {
- pointer->destroy();
- };
- };
- seat->on_get_keyboard = [=](keyboard_t* kbd) {
- LOGV("Client requested seat keyboard");
- data->kbd = kbd;
-
- int fd = -1, size = -1;
- get_keymap(&fd, &size);
- if (fd == -1 || size == -1) {
- LOGE("Error while getting keymap from backend");
- return;
- }
-
- kbd->keymap(wayland::keyboard_keymap_format::xkb_v1, fd, size);
- close (fd);
-
- wl_array keys{};
- wl_array_init(&keys);
-
- if (screen.sfc)
- kbd->enter(next_serial(), screen.sfc, &keys);
-
- kbd->on_release = [=] {
- kbd->destroy();
- };
- };
- seat->on_get_touch = [=](touch_t* touch) {
- data->touch = touch;
- touch->on_release = [=] {
- touch->destroy();
- };
- };
- };
- global_output.on_bind = [=, this](client_t* client, output_t* output) {
- auto data = any_cast(client->user_data());
- data->output = output;
- report_mode(output);
-
- output->on_release = [=]{
- output->destroy();
- };
- };
- global_shell.on_bind = [=](client_t* client, shell_t* shell) {
- auto data = any_cast(client->user_data());
-
- shell->on_get_shell_surface = [=] (shell_surface_t* shell, surface_t* sfc) {
- shell->on_set_toplevel = [=] () {
- wl_array keys{};
- wl_array_init(&keys);
- screen.sfc = sfc;
- redraw();
- set_renderer_visibility(sfc != nullptr);
-
- if (data->pointer)
- data->pointer->enter(next_serial(),sfc, 0, 0);
-
- if(data->kbd)
- data->kbd->enter(next_serial(), sfc, &keys);
-
- auto buffer = sfc ? any_cast(sfc->user_data())->buffer : nullptr;
- if (buffer)
- shell->configure(shell_surface_resize::none, buffer->shm_width(), buffer->shm_height());
- };
- };
- };
- global_xdg_wm_base.on_bind = [=, this](client_t* client, xdg_wm_base_t* wm_base) {
- auto data = any_cast(client->user_data());
- wm_base->on_get_xdg_surface = [=, this](xdg_surface_t* xdg_surface, surface_t* sfc) {
- xdg_surface->on_get_toplevel = [=, this](xdg_toplevel_t*) {
- wl_array keys{};
- wl_array_init(&keys);
- screen.sfc = sfc;
- redraw();
- set_renderer_visibility(sfc != nullptr);
-
- if (data->pointer)
- data->pointer->enter(next_serial(),sfc, 0, 0);
-
- if(data->kbd)
- data->kbd->enter(next_serial(), sfc, &keys);
- };
- };
- wm_base->on__destroy = [=]() { wm_base->destroy(); };
- };
-
- LOGV("Starting compositor");
- wl_display_init_shm (*this);
- add_fd_listener(queue.get_fd(), WL_EVENT_READABLE, [&](int, uint){ queue.run(); return 0; });
-}
-
-void lorie_compositor::redraw(bool force) {
- if (screen.win) {
- auto data = screen.sfc ? any_cast(screen.sfc->user_data()) : nullptr;
- bool damaged = (data && data->damaged) || force;
- if (damaged)
- blit(screen.win, screen.sfc);
- if (data)
- data->damaged = false;
- }
-
- if (cursor.win) {
- auto data = cursor.sfc ? any_cast(cursor.sfc->user_data()) : nullptr;
- bool damaged = (data && data->damaged) || force;
- if (damaged)
- blit(cursor.win, cursor.sfc);
- if (data)
- data->damaged = false;
- }
-}
-
-void lorie_compositor::post(std::function f) {
- queue.write(std::move(f));
-}
-
-void lorie_compositor::output_resize(EGLNativeWindowType win, int real_width, int real_height, int physical_width, int physical_height) {
- // Xwayland segfaults without that line
- LOGV("JNI: window is changed: %p %dx%d (%dmm x %dmm)", win, real_width, real_height, physical_width, physical_height);
- if (real_width == 0 || real_height == 0 || physical_width == 0 || physical_height == 0) return;
- screen.real_width = real_width;
- screen.real_height = real_height;
- screen.physical_width = physical_width;
- screen.physical_height = physical_height;
- screen.win = win;
-
- if (screen.sfc) {
- auto data = any_cast(screen.sfc->client()->user_data());
- report_mode(data->output);
- }
-}
-
-void lorie_compositor::report_mode(wayland::output_t* output) const {
- output->geometry(0, 0, screen.physical_width, screen.physical_height, output_subpixel::unknown, "Lorie", "none", output_transform::normal);
- output->scale(1.0);
- output->mode(output_mode::current | output_mode::preferred, screen.real_width, screen.real_height, 60000);
- output->done();
-}
-
-void lorie_compositor::pointer_motion(int x, int y) {
- LOGV("JNI: pointer motion %dx%d", x, y);
- if (!screen.sfc)
- return;
-
- auto data = any_cast(screen.sfc->client()->user_data());
-
- data->pointer->motion(resource_t::timestamp(), double(x), double(y));
- data->pointer->frame();
-}
-
-void lorie_compositor::pointer_scroll(int axis, float value) {
- LOGV("JNI: pointer scroll %d %f", axis, value);
- if (!screen.sfc)
- return;
-
- auto data = any_cast(screen.sfc->client()->user_data());
-
- data->pointer->axis_discrete(pointer_axis(axis), (value >= 0) ? 1 : -1);
- data->pointer->axis(resource_t::timestamp(), pointer_axis(axis), value);
- data->pointer->frame();
-}
-
-void lorie_compositor::pointer_button(int button, int state) {
- LOGV("JNI: pointer button %d type %d", button, state);
- if (!screen.sfc)
- return;
-
- auto data = any_cast(screen.sfc->client()->user_data());
-
- LOGI("pointer button: %d %d", button, state);
- data->pointer->button(next_serial(), resource_t::timestamp(), button, pointer_button_state(state));
- data->pointer->frame();
-}
-
-void lorie_compositor::keyboard_key(uint32_t key, keyboard_key_state state) {
- if (!screen.sfc)
- return;
-
- auto data = any_cast(screen.sfc->client()->user_data());
- data->kbd->key (next_serial(), resource_t::timestamp(), key, keyboard_key_state(state));
-}
-
-#pragma clang diagnostic pop
diff --git a/app/src/main/jni/lorie/include/ashmem.h b/app/src/main/jni/lorie/include/ashmem.h
deleted file mode 100644
index 1f5397927..000000000
--- a/app/src/main/jni/lorie/include/ashmem.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/****************************************************************************
- ****************************************************************************
- ***
- *** This header was automatically generated from a Linux kernel header
- *** of the same name, to make information necessary for userspace to
- *** call into the kernel available to libc. It contains only constants,
- *** structures, and macros generated from the original header, and thus,
- *** contains no copyrightable information.
- ***
- ****************************************************************************
- ****************************************************************************/
-#ifndef _LINUX_ASHMEM_H
-#define _LINUX_ASHMEM_H
-
-#include
-#include
-#include
-
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-#define ASHMEM_NOT_PURGED 0
-#define ASHMEM_WAS_PURGED 1
-
-#define ASHMEM_IS_UNPINNED 0
-#define ASHMEM_IS_PINNED 1
-
-struct ashmem_pin {
- uint32_t offset;
- uint32_t len;
-};
-
-#define __ASHMEMIOC 0x77
-
-#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
-#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
-#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
-#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
-#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
-#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
-#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
-#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
-
-#endif
diff --git a/app/src/main/jni/lorie/include/log.h b/app/src/main/jni/lorie/include/log.h
deleted file mode 100644
index c97558d12..000000000
--- a/app/src/main/jni/lorie/include/log.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "OCUnusedMacroInspection"
-#ifdef ANDROID
-#include
-
-#ifndef LOG_TAG
-#define LOG_TAG "LorieNative"
-#endif
-
-#ifndef LOG
-#define LOG(prio, ...) __android_log_print(prio, LOG_TAG, __VA_ARGS__)
-#endif
-
-#define LOGI(...) LOG(ANDROID_LOG_INFO, __VA_ARGS__)
-#define LOGW(...) LOG(ANDROID_LOG_WARN, __VA_ARGS__)
-#define LOGD(...) LOG(ANDROID_LOG_DEBUG, __VA_ARGS__)
-#define LOGV(...) LOG(ANDROID_LOG_VERBOSE, __VA_ARGS__)
-#define LOGE(...) LOG(ANDROID_LOG_ERROR, __VA_ARGS__)
-#define LOGF(...) LOG(ANDROID_LOG_FATAL, __VA_ARGS__)
-
-#endif
-#pragma clang diagnostic pop
\ No newline at end of file
diff --git a/app/src/main/jni/lorie/include/lorie_compositor.hpp b/app/src/main/jni/lorie/include/lorie_compositor.hpp
deleted file mode 100644
index d9ef2bd62..000000000
--- a/app/src/main/jni/lorie/include/lorie_compositor.hpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#pragma once
-#include
-#include
-#include
-#include
-#include "log.h"
-
-#ifdef ANDROID
-#include
-#include
-#include
-
-typedef ANativeWindow* EGLNativeWindowType;
-#else
-typedef void* EGLNativeWindowType;
-#endif
-
-class lorie_compositor: public wayland::display_t {
-public:
- lorie_compositor();
-// compositor features
- void start();
- void post(std::function f);
- void redraw(bool force = false);
-
- void output_resize(EGLNativeWindowType win, int real_width, int real_height, int physical_width, int physical_height);
- void report_mode(wayland::output_t* output) const;
-
- void pointer_motion(int x, int y); // absolute values
- void pointer_scroll(int axis, float value);
- void pointer_button(int button, int state);
- void keyboard_key(uint32_t key, wayland::keyboard_key_state state);
-
- struct client_data {
- wayland::output_t* output{};
- wayland::pointer_t* pointer{};
- wayland::keyboard_t* kbd{};
- wayland::touch_t* touch{};
- };
-
- struct surface_data {
- uint32_t x{}, y{}, id{};
- bool damaged{};
- wayland::buffer_t *buffer{};
- wayland::callback_t *frame_callback{};
- };
-
- struct {
- int real_width, real_height;
- int physical_width, physical_height;
- wayland::surface_t* sfc;
- EGLNativeWindowType win;
- } screen{};
- struct {
- int width, height;
- int hotspot_x, hotspot_y;
- int x, y;
- wayland::surface_t* sfc;
- EGLNativeWindowType win;
- } cursor{};
- static void blit(EGLNativeWindowType win, wayland::surface_t* sfc);
- std::function set_renderer_visibility = [](bool){};
- std::function set_cursor_visibility = [](JNIEnv*, bool){};
- std::function set_cursor_position = [](JNIEnv*, int, int){};
-
-// backend features
- void get_keymap(int *fd, int *size);
-
-//private:
- wayland::global_compositor_t global_compositor{this};
- wayland::global_seat_t global_seat{this};
- wayland::global_output_t global_output{this};
- wayland::global_shell_t global_shell{this};
- wayland::global_xdg_wm_base_t global_xdg_wm_base{this};
-
- lorie_message_queue queue;
-
-#ifdef ANDROID
- JNIEnv *env{};
- jobject thiz{};
- static jfieldID compositor_field_id;
- jmethodID set_renderer_visibility_id{};
- jmethodID set_cursor_visibility_id{};
- jmethodID set_cursor_rect_id{};
- lorie_compositor(jobject thiz);
- std::thread self;
-#endif
-};
diff --git a/app/src/main/jni/lorie/include/lorie_message_queue.hpp b/app/src/main/jni/lorie/include/lorie_message_queue.hpp
deleted file mode 100644
index 5cfbee2d6..000000000
--- a/app/src/main/jni/lorie/include/lorie_message_queue.hpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#include
-#include
-#include
-
-class lorie_message_queue {
-public:
- lorie_message_queue();
- void write(std::function func);
-
- void run();
- int get_fd();
-private:
- int fd;
- std::mutex mutex;
- std::queue> queue;
-};
diff --git a/app/src/main/jni/lorie/include/shm.h b/app/src/main/jni/lorie/include/shm.h
deleted file mode 100644
index f2ff3b7dc..000000000
--- a/app/src/main/jni/lorie/include/shm.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "ashmem.h"
-
-static inline int
-os_create_anonymous_file(size_t size) {
- int fd, ret;
- long flags;
- fd = open("/dev/ashmem", O_RDWR | O_CLOEXEC);
- if (fd < 0)
- return fd;
- ret = ioctl(fd, ASHMEM_SET_SIZE, size);
- if (ret < 0)
- goto err;
- flags = fcntl(fd, F_GETFD);
- if (flags == -1)
- goto err;
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
- goto err;
- return fd;
- err:
- close(fd);
- return ret;
-}
\ No newline at end of file
diff --git a/app/src/main/jni/lorie/lorie_message_queue.cpp b/app/src/main/jni/lorie/lorie_message_queue.cpp
deleted file mode 100644
index 868c7ab57..000000000
--- a/app/src/main/jni/lorie/lorie_message_queue.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-lorie_message_queue::lorie_message_queue() {
- std::unique_lock lock(mutex);
-
- fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
- if (fd == -1) {
- LOGE("Failed to create socketpair for message queue: %s", strerror(errno));
- return;
- }
-}
-
-void lorie_message_queue::write(std::function func) {
- static uint64_t i = 1;
- std::unique_lock lock(mutex);
- queue.push(func);
- ::write(fd, &i, sizeof(uint64_t));
-}
-
-void lorie_message_queue::run() {
- static uint64_t i = 0;
- std::unique_lock lock(mutex);
- std::function fn;
- ::read(fd, &i, sizeof(uint64_t));
- while(!queue.empty()){
- fn = queue.front();
- queue.pop();
-
- lock.unlock();
- fn();
- lock.lock();
- }
-}
-
-int lorie_message_queue::get_fd() {
- return fd;
-}
diff --git a/app/src/main/jni/lorie/lorie_wayland_server.cpp b/app/src/main/jni/lorie/lorie_wayland_server.cpp
deleted file mode 100644
index c73cbac06..000000000
--- a/app/src/main/jni/lorie/lorie_wayland_server.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma ide diagnostic ignored "cppcoreguidelines-pro-type-static-cast-downcast"
-
-using namespace wayland;
-
-
-/* display_t methods */
-static void display_destroyed(wl_listener* l, void* data) {
- auto d = static_cast(l);
- if (d->on_destroy)
- d->on_destroy();
-}
-
-static void client_created(wl_listener* l, void* data) {
- if (!data) return;
- auto c = static_cast(data);
- auto d = reinterpret_cast(wl_display_get_destroy_listener(wl_client_get_display(c), &display_destroyed));
- auto new_client = new client_t(c);
- if (d->on_client)
- d->on_client(new_client);
-}
-
-display_t::display_t():
-display(wl_display_create()),
-wl_listener{{}, &display_destroyed},
-client_created_listener{{}, &client_created}{
- wl_display_add_destroy_listener(display, this);
- wl_display_add_client_created_listener(display, &client_created_listener);
-}
-
-class fd_listener: public wl_listener {
-protected:
- std::function dispatch;
- static void destroy(wl_listener* that, void *) {
- auto listener = static_cast(that);
- wl_list_remove(&listener->link);
- wl_event_source_remove(listener->source);
- delete listener;
- }
-public:
- wl_event_source* source = nullptr;
- explicit fd_listener(wl_event_loop* loop, std::function dispatch_func):
- wl_listener{{}, &destroy}, dispatch(std::move(dispatch_func)) {
- wl_event_loop_add_destroy_listener(loop, this);
- }
- static int fire(int fd, uint32_t mask, void *data) {
- auto listener = static_cast(data);
- if (listener)
- return listener->dispatch(fd, mask);
- return 0;
- }
-};
-
-void display_t::add_fd_listener(int fd, uint32_t mask, std::function