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 listener) { - wl_event_loop* loop = wl_display_get_event_loop(display); - auto l = new fd_listener(loop, std::move(listener)); - l->source = wl_event_loop_add_fd(loop, fd, mask, fd_listener::fire, l); -} - -// It is wl_display_socket_add_fd version which drops server fd if it is faulty. -void display_t::add_socket_fd(int fd) { - { -#if 0 - wl_display_add_socket_fd(display, fd); -#else - class [[maybe_unused]] server_socket_listener: public wl_listener { - public: - wl_display* dpy; - wl_event_source* src; - explicit server_socket_listener(wl_display* dpy): - wl_listener{{}, &destroy}, dpy(dpy) {} - static void destroy(wl_listener* l, void* d) { - auto thiz = reinterpret_cast(l); - wl_event_source_remove(thiz->src); - delete thiz; - } - static int event(int fd, uint32_t mask, void *data) - { - auto l = reinterpret_cast(data); - if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) { - l->destroy(l, nullptr); - return 0; - } - - struct sockaddr_un name{}; - socklen_t length; - int client_fd; - - length = sizeof name; - client_fd = accept4(fd, (struct sockaddr *) &name, &length, SOCK_CLOEXEC); - if (client_fd < 0) { - LOGE("failed to accept: %s\n", strerror(errno)); - if (errno == EBADF || errno == ENOTSOCK || errno == EPERM) { - l->destroy(l, nullptr); - return 0; - } - } else - if (!wl_client_create(l->dpy, client_fd)) - close(client_fd); - - return 1; - } - static int set_cloexec_or_close(int fd) { - long flags; - - if (fd == -1) return -1; - 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 -1; - }; - }; - - uint32_t mask = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; - - listen(fd, 128); - wl_event_loop* loop = wl_display_get_event_loop(display); - auto listener = new server_socket_listener(display); - listener->src = wl_event_loop_add_fd(loop, fd, mask, server_socket_listener::event, listener); - wl_event_loop_add_destroy_listener(loop, listener); -#endif - } -} - -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::post_implementation_error(const std::string& string) { - wl_client_post_implementation_error(client, "%s", string.c_str()); -} - -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); -} - -uint32_t resource_t::timestamp() { - timespec t = {0}; - clock_gettime (CLOCK_MONOTONIC, &t); - return t.tv_sec * 1000 + t.tv_nsec / 1000000; -} diff --git a/app/src/main/jni/lorie/utils/log.cpp b/app/src/main/jni/lorie/utils/log.cpp deleted file mode 100755 index 30924520c..000000000 --- a/app/src/main/jni/lorie/utils/log.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma ide diagnostic ignored "readability-inconsistent-declaration-parameter-name" -#pragma ide diagnostic ignored "bugprone-reserved-identifier" -#include // for dladdr -#include // for __cxa_demangle -#include - -#include -#include - -#define LOG(prio, ...) { \ - __android_log_print(prio, "LorieProfile", __VA_ARGS__); \ - char p = ((prio == ANDROID_LOG_VERBOSE)?'V': \ - ((prio == ANDROID_LOG_DEBUG) ?'D': \ - ((prio == ANDROID_LOG_INFO) ?'I': \ - ((prio == ANDROID_LOG_WARN) ?'W': \ - ((prio == ANDROID_LOG_ERROR) ?'E': \ - ((prio == ANDROID_LOG_FATAL) ?'F':'U')))))); \ - printf("%s/%c: ", "LorieProfile", p); \ - printf(__VA_ARGS__); \ - printf("\n"); \ -} - -#include "../include/log.h" -#include -#include - -bool enabled = true; -#define no_instrument void __attribute__((no_instrument_function)) __attribute__ ((visibility ("default"))) - -using namespace std; -extern "C" { - -extern void *blacklist[]; -#define skip_blacklisted(f) for (int z=0; blacklist[z]!=NULL; z++) if (blacklist[z]==(f)) return - -static thread_local int level = -1; - -no_instrument __attribute__((__constructor__(5))) i() { - if (getenv("LORIE_DEBUG")) - enabled = true; - if (getenv("LORIE_NDEBUG")) - enabled = false; -} - -no_instrument print_func(void *func, int enter) { - Dl_info info; - if (dladdr(func, &info) && info.dli_sname != nullptr) { - int status; - char *demangled = abi::__cxa_demangle(info.dli_sname,nullptr, nullptr, &status); - LOGD("%d%*c%s %s", gettid(), level, ' ', enter ? ">" : "<", status == 0 ? demangled : info.dli_sname); - free(demangled); - } -} - -no_instrument __cyg_profile_func_enter (void *func, [[maybe_unused]] void *caller) { - if (!enabled) return; - skip_blacklisted(func); - level++; - print_func(func, 1); -} - -no_instrument __cyg_profile_func_exit (void *func, [[maybe_unused]] void *caller) { - if (!enabled) return; - skip_blacklisted(func); - print_func(func, 0); - level--; -} - -void *blacklist[] = { - (void*) __cyg_profile_func_enter, - (void*) __cyg_profile_func_exit, - (void*) print_func -}; -} // extern "C" diff --git a/app/src/main/jni/starter/Android.mk b/app/src/main/jni/starter/Android.mk deleted file mode 100755 index 75d901c41..000000000 --- a/app/src/main/jni/starter/Android.mk +++ /dev/null @@ -1,7 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := x11-starter -LOCAL_SRC_FILES := starter.c -LOCAL_LDLIBS := -llog -ldl -include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/starter/starter.c b/app/src/main/jni/starter/starter.c deleted file mode 100755 index 93b8fd31d..000000000 --- a/app/src/main/jni/starter/starter.c +++ /dev/null @@ -1,182 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define unused __attribute__((__unused__)) - -#define DEFAULT_PREFIX "/data/data/com.termux/files/usr" -#define DEFAULT_XDG_RUNTIME_DIR DEFAULT_PREFIX "/tmp" -#define DEFAULT_SOCKET_NAME "termux-x11" - -static int socket_action(int* fd, char* path, - int (*action)(int, const struct sockaddr *, socklen_t)) { - if (!fd || !action) { - errno = -EINVAL; - return -1; - } - - struct sockaddr_un local; - size_t len; - - if((*fd = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) - { - perror("socket"); - return *fd; - } - - local.sun_family = AF_UNIX; - strcpy(local.sun_path, path); - len = strlen(local.sun_path) + sizeof(local.sun_family); - return action(*fd, (struct sockaddr *)&local, len); -} - -JNIEXPORT void JNICALL -Java_com_termux_x11_CmdEntryPoint_checkXdgRuntimeDir(unused JNIEnv *env, unused jobject thiz) { - char* XDG_RUNTIME_DIR = getenv("XDG_RUNTIME_DIR"); - if (!XDG_RUNTIME_DIR || strlen(XDG_RUNTIME_DIR) == 0) { - printf("$XDG_RUNTIME_DIR is unset.\n"); - printf("Exporting default value (%s).\n", DEFAULT_XDG_RUNTIME_DIR); - setenv("XDG_RUNTIME_DIR", DEFAULT_XDG_RUNTIME_DIR, true); - } -} - -static const char *getWaylandSocketPath() { - static char* path = NULL; - if (path != NULL) - return path; - - path = malloc(256 * sizeof(char)); - memset(path, 0, 256 * sizeof(char)); - - char* XDG_RUNTIME_DIR = getenv("XDG_RUNTIME_DIR"); - if (!XDG_RUNTIME_DIR || strlen(XDG_RUNTIME_DIR) == 0) { - printf("$XDG_RUNTIME_DIR is unset"); - exit(1); - } - - sprintf(path, "%s/%s", XDG_RUNTIME_DIR, DEFAULT_SOCKET_NAME); - return path; -} - -JNIEXPORT jboolean JNICALL -Java_com_termux_x11_CmdEntryPoint_checkWaylandSocket(unused JNIEnv *env, unused jobject thiz) { - int fd; - errno = 0; - - if (socket_action(&fd, (char *) getWaylandSocketPath(), connect) != -1) { - close(fd); - return 1; - } - - return 0; -} - -JNIEXPORT jint JNICALL -Java_com_termux_x11_CmdEntryPoint_createWaylandSocket(unused JNIEnv *env, unused jobject thiz) { - int fd; - errno = 0; - - unlink(getWaylandSocketPath()); - if (socket_action(&fd, (char *) getWaylandSocketPath(), bind) < 0) { - perror("socket"); - return -1; - } - - return fd; -} - -#pragma clang diagnostic push -#pragma ide diagnostic ignored "hicpp-signed-bitwise" -JNIEXPORT jint JNICALL -Java_com_termux_x11_CmdEntryPoint_openLogFD(unused JNIEnv *env, unused jobject thiz) { - const char* TERMUX_X11_LOG_FILE = getenv("TERMUX_X11_LOG_FILE"); - int sv[2]; /* the pair of socket descriptors */ - if (TERMUX_X11_LOG_FILE == NULL || strlen(TERMUX_X11_LOG_FILE) == 0) - return -1; - - int logfd = open(TERMUX_X11_LOG_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (logfd < 0) { - perror("open logfile"); - return -1; - } - - if (pipe(sv) == -1) { - perror("pipe"); - return -1; - } - - fchmod (sv[0], 0777); - fchmod (sv[1], 0777); - - switch(fork()) { - /* - * Android do not allow another process to write to tty or pipe fd of our process. - * We can not force allowing even using chmod. - * That is a reason we are using pipe and cat here. - */ - case 0: { - int new_stderr = dup(2); - close(sv[1]); - dup2(sv[0], 0); - dup2(logfd, 1); - dup2(logfd, 2); - close(sv[0]); - close(logfd); - - printf("cat started (%d)\n", getpid()); - - struct pollfd pfd = {0}; - pfd.fd = 0; - pfd.events = POLLIN | POLLHUP; - - poll(&pfd, 1, 10000); - - execl("/data/data/com.termux/files/usr/bin/cat", "cat", NULL); - dprintf(new_stderr, "execl cat: %s\n", strerror(errno)); - return -1; - } - case -1: - return -1; - default: - close(sv[0]); - close(logfd); - return sv[1]; - } -} - -JNIEXPORT void JNICALL -Java_com_termux_x11_CmdEntryPoint_exec(JNIEnv *env, jclass clazz, jstring jpath, jobjectArray jargv) { - // execv's argv array is a bit incompatible with Java's String[], so we do some converting here... - int argc = (*env)->GetArrayLength(env, jargv) + 2; // Leading executable path and terminating NULL - char *argv[argc]; - memset(argv, 0, sizeof(char*) * argc); - - for(int i=0; iGetObjectArrayElement(env, jargv, i - 1) : jpath; - const char *pjc = (*env)->GetStringUTFChars(env, js, false); - argv[i] = calloc(strlen(pjc)+1, sizeof(char)); //Extra char for the terminating NULL - strcpy((char *) argv[i], pjc); - (*env)->ReleaseStringUTFChars(env, js, pjc); - } - argv[argc] = NULL; // Terminating NULL - setenv("WAYLAND_DISPLAY", DEFAULT_SOCKET_NAME, 1); - - execv(argv[0], argv); - perror("execv"); - exit(1); -} - -#pragma clang diagnostic pop diff --git a/app/src/main/jni/wayland b/app/src/main/jni/wayland deleted file mode 160000 index 8135e856e..000000000 --- a/app/src/main/jni/wayland +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8135e856ebd79872f886466e9cee39affb7d9ee8 diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index 8800a0c5d..a61fe5813 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -87,18 +87,18 @@ - + android:layout_height="37.5dp" + android:background="@color/black" + android:layout_gravity="bottom|center"/> - - + diff --git a/app/src/main/res/layout/view_terminal_toolbar_extra_keys.xml b/app/src/main/res/layout/view_terminal_toolbar_extra_keys.xml new file mode 100644 index 000000000..a921343cf --- /dev/null +++ b/app/src/main/res/layout/view_terminal_toolbar_extra_keys.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_terminal_toolbar_text_input.xml b/app/src/main/res/layout/view_terminal_toolbar_text_input.xml new file mode 100644 index 000000000..ed0b23ded --- /dev/null +++ b/app/src/main/res/layout/view_terminal_toolbar_text_input.xml @@ -0,0 +1,16 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ddfc11c20..9a2e7e3c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,7 +33,7 @@ Already Granted Already Disabled - Not conected + Not connected Getting started Preferences diff --git a/app/stub/build.gradle b/app/stub/build.gradle deleted file mode 100644 index 93e9e403a..000000000 --- a/app/stub/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -plugins { - id('com.android.library') -} - -android { - compileSdkVersion 30 - defaultConfig { - minSdkVersion 24 - //noinspection ExpiredTargetSdkVersion - targetSdkVersion 28 - } - buildFeatures { - buildConfig false - } - buildTypes { - release { - minifyEnabled false - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - implementation 'androidx.annotation:annotation:1.5.0' -} diff --git a/app/stub/src/main/AndroidManifest.xml b/app/stub/src/main/AndroidManifest.xml deleted file mode 100644 index f682fe267..000000000 --- a/app/stub/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/stub/src/main/aidl/android/content/IIntentReceiver.aidl b/app/stub/src/main/aidl/android/content/IIntentReceiver.aidl deleted file mode 100644 index cf00a2342..000000000 --- a/app/stub/src/main/aidl/android/content/IIntentReceiver.aidl +++ /dev/null @@ -1,33 +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. - */ - -package android.content; - -import android.content.Intent; -import android.os.Bundle; - -/** - * System private API for dispatching intent broadcasts. This is given to the - * activity manager as part of registering for an intent broadcasts, and is - * called when it receives intents. - * - * {@hide} - */ -oneway interface IIntentReceiver { - // Android 6+, unchanged. - void performReceive(in Intent intent, int resultCode, String data, - in Bundle extras, boolean ordered, boolean sticky, int sendingUser); -} \ No newline at end of file diff --git a/app/stub/src/main/java/android/app/ActivityManagerNative.java b/app/stub/src/main/java/android/app/ActivityManagerNative.java deleted file mode 100644 index cc8bf93e4..000000000 --- a/app/stub/src/main/java/android/app/ActivityManagerNative.java +++ /dev/null @@ -1,9 +0,0 @@ -package android.app; - -import android.os.IBinder; - -public class ActivityManagerNative { - public static IActivityManager asInterface(IBinder obj) { - throw new RuntimeException("STUB"); - } -} \ No newline at end of file diff --git a/app/stub/src/main/java/android/app/ActivityTaskManager.java b/app/stub/src/main/java/android/app/ActivityTaskManager.java deleted file mode 100644 index 367f48500..000000000 --- a/app/stub/src/main/java/android/app/ActivityTaskManager.java +++ /dev/null @@ -1,7 +0,0 @@ -package android.app; - -public class ActivityTaskManager { - public static IActivityTaskManager getService() { - throw new RuntimeException("STUB"); - } -} diff --git a/app/stub/src/main/java/android/app/IActivityManager.java b/app/stub/src/main/java/android/app/IActivityManager.java deleted file mode 100644 index 62c00b025..000000000 --- a/app/stub/src/main/java/android/app/IActivityManager.java +++ /dev/null @@ -1,31 +0,0 @@ -package android.app; - -import android.content.Intent; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.IInterface; -import android.os.RemoteException; - -import androidx.annotation.RequiresApi; - -import java.util.List; - -public interface IActivityManager extends IInterface { - int checkPermission(String permission, int pid, int uid) - throws RemoteException; - - int startActivityAsUser(IApplicationThread caller, String callingPackage, - Intent intent, String resolvedType, IBinder resultTo, String resultWho, - int requestCode, int flags, ProfilerInfo profilerInfo, - Bundle options, int userId) - throws RemoteException; - - @RequiresApi(26) - abstract class Stub extends Binder implements IActivityManager { - - public static IActivityManager asInterface(IBinder obj) { - throw new RuntimeException("STUB"); - } - } -} diff --git a/app/stub/src/main/java/android/app/IActivityTaskManager.java b/app/stub/src/main/java/android/app/IActivityTaskManager.java deleted file mode 100644 index 01f2b6940..000000000 --- a/app/stub/src/main/java/android/app/IActivityTaskManager.java +++ /dev/null @@ -1,23 +0,0 @@ -package android.app; - -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; -import android.os.IInterface; -import android.os.RemoteException; -import android.content.IIntentSender; - -public interface IActivityTaskManager extends IInterface { - int startActivity(IApplicationThread caller, String callingPackage, String callingFeatureId, - Intent intent, String resolvedType, IBinder resultTo, String resultWho, - int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) - throws RemoteException; - int startActivity(IApplicationThread caller, String callingPackage, Intent intent, - String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int flags, ProfilerInfo profilerInfo, Bundle options) - throws RemoteException; - IIntentSender getIntentSender(int type, String packageName, IBinder token, - String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, - int flags, Bundle options, int userId) - throws RemoteException; -} diff --git a/app/stub/src/main/java/android/app/IApplicationThread.java b/app/stub/src/main/java/android/app/IApplicationThread.java deleted file mode 100644 index 340553149..000000000 --- a/app/stub/src/main/java/android/app/IApplicationThread.java +++ /dev/null @@ -1,4 +0,0 @@ -package android.app; - -public interface IApplicationThread { -} \ No newline at end of file diff --git a/app/stub/src/main/java/android/app/ProfilerInfo.java b/app/stub/src/main/java/android/app/ProfilerInfo.java deleted file mode 100644 index dce3921c7..000000000 --- a/app/stub/src/main/java/android/app/ProfilerInfo.java +++ /dev/null @@ -1,4 +0,0 @@ -package android.app; - -public class ProfilerInfo { -} \ No newline at end of file diff --git a/app/stub/src/main/java/android/content/IIntentSender.java b/app/stub/src/main/java/android/content/IIntentSender.java deleted file mode 100644 index 597cf2251..000000000 --- a/app/stub/src/main/java/android/content/IIntentSender.java +++ /dev/null @@ -1,32 +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. - */ - -package android.content; - -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; - -public interface IIntentSender { - // Android 8+ - void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, - IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) - throws RemoteException; - // Android 6+ - int send(int code, Intent intent, String resolvedType, - IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) - throws RemoteException; -} \ No newline at end of file diff --git a/app/stub/src/main/java/android/os/ServiceManager.java b/app/stub/src/main/java/android/os/ServiceManager.java deleted file mode 100644 index 67496631b..000000000 --- a/app/stub/src/main/java/android/os/ServiceManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package android.os; - -public class ServiceManager { - /** - * Returns a reference to a service with the given name. - * - * @param name the name of the service to get - * @return a reference to the service, or null if the service doesn't exist - */ - public static IBinder getService(String name) { - throw new RuntimeException("STUB"); - } -} diff --git a/app/stub/src/main/java/com/android/internal/app/IAppOpsService.java b/app/stub/src/main/java/com/android/internal/app/IAppOpsService.java deleted file mode 100644 index 1e2d8bcad..000000000 --- a/app/stub/src/main/java/com/android/internal/app/IAppOpsService.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.internal.app; - -import android.os.IBinder; - -public interface IAppOpsService extends android.os.IInterface { - public static abstract class Stub extends android.os.Binder implements IAppOpsService { - public static IAppOpsService asInterface(IBinder obj) { - throw new RuntimeException("STUB"); - } - } -} diff --git a/settings.gradle b/settings.gradle index 26d47a38f..7996fd291 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,3 @@ include ':shell-loader:stub' include ':shell-loader' -include ':app:stub' include ':app' -include ':x11-client-experimental' diff --git a/x11-client-experimental/.gitignore b/x11-client-experimental/.gitignore deleted file mode 100755 index 42afabfd2..000000000 --- a/x11-client-experimental/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/x11-client-experimental/build.gradle b/x11-client-experimental/build.gradle deleted file mode 100755 index 4d17aa465..000000000 --- a/x11-client-experimental/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 32 - defaultConfig { - // It will not interfere with main app because they are not considered to be installed at the same time. - applicationId "com.termux.x11" - minSdkVersion 24 - // Note: targetSdkVersion affects only tests, - // normally, even though this is packaged as apk, - // it's not loaded as apk so targetSdkVersion is ignored. - // targetSdkVersion this must be < 28 because this application accesses hidden apis - //noinspection ExpiredTargetSdkVersion,OldTargetApi - targetSdkVersion 28 - versionCode 1 - versionName "0.1" - } - - signingConfigs { - debug { - storeFile file('../app/testkey_untrusted.jks') - keyAlias 'alias' - storePassword 'xrj45yWGLbsO7W0v' - keyPassword 'xrj45yWGLbsO7W0v' - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - externalNativeBuild { - cmake { - path "src/main/cpp/CMakeLists.txt" - } - } - - packagingOptions { - jniLibs { - // This will allow us to use shared libraries inside *.apk, without unpacking - // @agnostic-apollo is the best - // https://github.com/termux/termux-x11/commit/6cdfb75c4451eef63f114a93baef5ba73b7cfd8c#commitcomment-77856313 - useLegacyPackaging false - } - } -} - -dependencies { - implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' - implementation 'com.termux.termux-app:termux-shared:-SNAPSHOT' - implementation 'com.google.android.material:material:1.8.0' - implementation fileTree(dir: 'libs', include: ['*.jar']) - //noinspection GradleDependency - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.5.2' - 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') -} \ No newline at end of file diff --git a/x11-client-experimental/src/main/AndroidManifest.xml b/x11-client-experimental/src/main/AndroidManifest.xml deleted file mode 100644 index 501da0e49..000000000 --- a/x11-client-experimental/src/main/AndroidManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/x11-client-experimental/src/main/aidl/com/termux/x11/ICmdEntryPointInterface.aidl b/x11-client-experimental/src/main/aidl/com/termux/x11/ICmdEntryPointInterface.aidl deleted file mode 100644 index 95b59a0c4..000000000 --- a/x11-client-experimental/src/main/aidl/com/termux/x11/ICmdEntryPointInterface.aidl +++ /dev/null @@ -1,8 +0,0 @@ -// ICmdEntryPointInterface.aidl -package com.termux.x11; - -// Declare any non-default types here with import statements - -interface ICmdEntryPointInterface { - ParcelFileDescriptor getConnectionFd(); -} \ No newline at end of file diff --git a/x11-client-experimental/src/main/cpp/libXau b/x11-client-experimental/src/main/cpp/libXau deleted file mode 160000 index 14fdf25db..000000000 --- a/x11-client-experimental/src/main/cpp/libXau +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 14fdf25db9f21c8f3ad37f0d32a5b8e726efdc0d diff --git a/x11-client-experimental/src/main/cpp/loading_sign.c b/x11-client-experimental/src/main/cpp/loading_sign.c deleted file mode 100644 index b7a0acf74..000000000 --- a/x11-client-experimental/src/main/cpp/loading_sign.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -static void __attribute__((__constructor__)) load() { - puts("libxcb is loaded from apk...\n"); -} diff --git a/x11-client-experimental/src/main/cpp/lorie/lorie.cpp b/x11-client-experimental/src/main/cpp/lorie/lorie.cpp deleted file mode 100644 index 2f2dce90f..000000000 --- a/x11-client-experimental/src/main/cpp/lorie/lorie.cpp +++ /dev/null @@ -1,670 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lorie_message_queue.hpp" - -// 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" - -#if 1 -#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "LorieX11Client", fmt, ## __VA_ARGS__) -#else -#define ALOGE(fmt, ...) printf(fmt, ## __VA_ARGS__); printf("\n") -#endif -#define unused __attribute__((unused)) - -typedef uint8_t u8 unused; -typedef uint16_t u16 unused; -typedef uint32_t u32 unused; -typedef uint64_t u64 unused; -typedef int8_t i8 unused; -typedef int16_t i16 unused; -typedef int32_t i32 unused; -typedef int64_t i64 unused; - -#define always_inline inline __attribute__((__always_inline__)) - -#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__)) - -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, seg, fd, ro); - self.handle_error("Error attaching file descriptor through MIT-SHM extension"); - }; - - void unused 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"); - } - - 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* unused 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; - xcb_randr_get_screen_resources_reply_t* res{}; - const char* temporary_name = "temporary"; - void init() { - { - auto reply = xcb(randr_query_version, 1, 1); - self.handle_error(reply, "Error querying RANDR extension"); - free(reply); - } - - refresh(); - } - - void refresh() { - auto screen = xcb_setup_roots_iterator(xcb_get_setup (self.conn)).data; - free(res); - res = xcb(randr_get_screen_resources, screen->root); - self.handle_error(res, "Error during refreshing RANDR modes."); - } - - xcb_randr_mode_t get_id_for_mode(const char *name) { - refresh(); - char *mode_names = reinterpret_cast(xcb_randr_get_screen_resources_names(res)); - auto modes = xcb_randr_get_screen_resources_modes(res); - for (int i = 0; i < xcb_randr_get_screen_resources_modes_length(res); i++) { - auto& mode = modes[i]; - char mode_name[64]{}; - snprintf(mode_name, mode.name_len+1, "%s", mode_names); - mode_names += mode.name_len; - - if (!strcmp(mode_name, name)) { - return mode.id; - } - } - return 0; - } - - void create_mode(const char* name, libxcvt_mode_info *mode_info) { - bool is_temporary = strcmp(name, temporary_name) == 0; - if (!is_temporary && get_id_for_mode(name)) - delete_mode(name); - - if (is_temporary && get_id_for_mode(name)) - return; - - auto screen = xcb_setup_roots_iterator(xcb_get_setup (self.conn)).data; - xcb_randr_mode_info_t mode{}; - mode.width = mode_info->hdisplay; - mode.height = mode_info->vdisplay; - mode.dot_clock = mode_info->dot_clock * 1000; - mode.hsync_start = mode_info->hsync_start; - mode.hsync_end = mode_info->hsync_end; - mode.htotal = mode_info->htotal; - mode.vsync_start = mode_info->vsync_start; - mode.vsync_end = mode_info->vsync_end; - mode.vtotal = mode_info->vtotal; - mode.mode_flags = mode_info->mode_flags; - mode.name_len = strlen(name); - { - auto reply = xcb(randr_create_mode, screen->root, mode, mode.name_len, name); - self.handle_error(reply, "Failed to create RANDR mode"); - } - - refresh(); - xcb_randr_mode_t mode_id = get_id_for_mode(name); - if (!mode_id) { - throw std::runtime_error("Failed to find RANDR mode we just created"); - } - xcb_check(randr_add_output_mode_checked, xcb_randr_get_screen_resources_outputs(res)[0], mode_id); - self.handle_error("Failed to add RANDR mode we just created to screen"); - } - - void delete_mode(const char* name) { - xcb_randr_mode_t mode_id = get_id_for_mode(name); - if (mode_id) { - xcb_check(randr_delete_output_mode_checked, xcb_randr_get_screen_resources_outputs(res)[0], mode_id); - self.handle_error("Failed to detach RANDR mode from output"); - - xcb_check(randr_destroy_mode_checked, mode_id); - self.handle_error("Failed to destroy RANDR mode we just detached from output"); - - refresh(); - } - } - - void switch_to_mode(const char *name) { - xcb_randr_mode_t mode_id = XCB_NONE; - xcb_randr_output_t* outputs{}; - int noutput = 0; - if (name) { - mode_id = get_id_for_mode(name); - if (mode_id == 0) return; - outputs = xcb_randr_get_screen_resources_outputs(res); - noutput = xcb_randr_get_screen_resources_outputs_length(res); - } - - ALOGE("crts len %d", xcb_randr_get_screen_resources_crtcs_length(res)); - - auto reply = xcb(randr_set_crtc_config, xcb_randr_get_screen_resources_crtcs(res)[0], XCB_CURRENT_TIME, - res->config_timestamp, 0, 0, mode_id, XCB_RANDR_ROTATION_ROTATE_0, - noutput, outputs); - self.handle_error(reply,"Failed to switch RANDR mode"); - }; - - void set_screen_size(u16 width, u16 height, u32 mm_width, u32 mm_height) { - auto screen = xcb_setup_roots_iterator(xcb_get_setup (self.conn)).data; - xcb_check(randr_set_screen_size_checked, screen->root, width, height, mm_width, mm_height); - self.handle_error("Failed to set RANDR screen size"); - } - - } randr {*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(); - //randr.init(); - damage.init(); - input.init(); - fixes.init(); - } -}; - -#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; -} - -// 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 (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_message_queue queue; - std::thread runner_thread; - bool terminate = false; - - xcb_connection c; - - struct { - ANativeWindow* win{}; - u32 width{}; - u32 height{}; - - i32 shmfd{}; - xcb_shm_seg_t shmseg{}; - u32 *shmaddr{}; - } screen; - ANativeWindow* cursor{}; - - - lorie_client() { - runner_thread = std::thread([=, this] { runner(); }); - } - - void post(std::function task) { - queue.write(std::move(task)); - } - - void runner() { - ALooper_prepare(0); - ALooper_addFd(ALooper_forThread(), queue.get_fd(), ALOOPER_EVENT_INPUT, ALOOPER_POLL_CALLBACK, [](int, int, void *d) { - auto thiz = reinterpret_cast (d); - thiz->queue.run(); - return 1; - }, this); - - while(!terminate) ALooper_pollAll(500, nullptr, nullptr, nullptr); - - ALooper_release(ALooper_forThread()); - } - - void surface_changed(ANativeWindow* win, u32 width, u32 height) { - if (screen.win) - ANativeWindow_release(screen.win); - - screen.win = win; - screen.width = width; - screen.height = height; - - if (c.conn) - change_resolution(width, height); - } - - void change_resolution(u16 width, u16 height) { - char mode_name[128]{}; - - auto mi = libxcvt_gen_mode_info(width, height, 60, false, false); - ALOGE("Changing resolution to %dx%d", mi->hdisplay, mi->vdisplay); - sprintf(mode_name, "TERMUX:X11 %dx%d", mi->hdisplay, mi->vdisplay); - - int mm_width = int(25.4*width/120); - int mm_height = int(25.4*height/120); - - xcb_grab_server(c.conn); - try { - ALOGE("line %d", __LINE__); - c.randr.create_mode(c.randr.temporary_name, mi); - c.randr.switch_to_mode(nullptr); - ALOGE("line %d", __LINE__); - c.randr.set_screen_size(mi->hdisplay, mi->vdisplay, mm_width, mm_height); - c.randr.switch_to_mode(c.randr.temporary_name); - ALOGE("line %d", __LINE__); - c.randr.delete_mode(mode_name); - c.randr.create_mode(mode_name, mi); // NOLINT(cppcoreguidelines-narrowing-conversions) - ALOGE("line %d", __LINE__); - c.randr.switch_to_mode(mode_name); - c.randr.delete_mode(c.randr.temporary_name); - ALOGE("line %d", __LINE__); - } catch (std::runtime_error& e) { - xcb_ungrab_server(c.conn); - throw e; - } - xcb_ungrab_server(c.conn); - } - - void adopt_connection_fd(int 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); - - if (screen.shmaddr) - munmap(screen.shmaddr, DEFAULT_SHMSEG_LENGTH); - if (screen.shmfd) - close(screen.shmfd); - - ALOGE("Creating file..."); - screen.shmfd = os_create_anonymous_file(DEFAULT_SHMSEG_LENGTH); - if (screen.shmfd < 1) { - ALOGE("Error opening file: %s", strerror(errno)); - } - fchmod(screen.shmfd, 0777); - ALOGE("Attaching file..."); - screen.shmaddr = static_cast(mmap(nullptr, 8096*8096*4, - PROT_READ | PROT_WRITE, - MAP_SHARED, screen.shmfd, 0)); - if (screen.shmaddr == MAP_FAILED) { - ALOGE("Map failed: %s", strerror(errno)); - } - c.shm.attach_fd(screen.shmseg, screen.shmfd, 0); - - if (screen.win) { - change_resolution(screen.width, screen.height); - } - - int event_mask = ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT | ALOOPER_EVENT_INVALID | ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_ERROR; - ALooper_addFd(ALooper_forThread(), fd, ALOOPER_EVENT_INPUT, event_mask, [](int, int mask, void *d) { - auto self = reinterpret_cast(d); - if (mask & (ALOOPER_EVENT_INVALID | ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_ERROR)) { - xcb_disconnect(self->c.conn); - self->c.conn = nullptr; - ALOGE("Disconnected"); - return 0; - } - - self->connection_poll_func(); - return 1; - }, this); - } - - void connection_poll_func() { - 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_CONFIGURE_NOTIFY) { - ALOGE("Configure notification. "); - auto e = reinterpret_cast(event); - ALOGE("old w: %d h: %d", s->width_in_pixels, s->height_in_pixels); - ALOGE("new w: %d h: %d", e->width, e->height); - s->width_in_pixels = e->width; - s->height_in_pixels = e->height; - } else if (c.damage.is_damage_notify_event(event)) { - try { - 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) { - continue; - } - } //else - // ALOGE("some other event %s of %s", xcb_errors_get_name_for_core_event(c.err_ctx, event->response_type, &ext), (ext ?: "core")); - } - } - - ~lorie_client() { - queue.write([=, this] { terminate = true; }); - if (runner_thread.joinable()) - runner_thread.join(); - close(queue.get_fd()); - } -} lorie_client; // NOLINT(cert-err58-cpp) - -extern "C" -JNIEXPORT void JNICALL -Java_com_termux_x11_MainActivity_start(unused JNIEnv *env, unused jobject thiz, jint fd) { - lorie_client.post([fd] { lorie_client.adopt_connection_fd(fd); }); -} - -extern "C" -JNIEXPORT void JNICALL -Java_com_termux_x11_MainActivity_surface(JNIEnv *env, jobject thiz, jobject sfc, jint width, jint height) { - ANativeWindow *win = sfc ? ANativeWindow_fromSurface(env, sfc) : nullptr; - if (win) - ANativeWindow_acquire(win); - - ALOGE("Got new surface %p", win); - lorie_client.post([=] { lorie_client.surface_changed(win, width, height); }); -} - -extern "C" -JNIEXPORT jint JNICALL -Java_com_termux_x11_CmdEntryPoint_connect(JNIEnv *env, jclass clazz) { - struct sockaddr_un remote{ .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; - } - - std::cerr << "Connecting..." << std::endl; - connect(sockfd, reinterpret_cast(&remote), sizeof(remote)); // NOLINT(bugprone-unused-return-value) - return sockfd; -} \ No newline at end of file diff --git a/x11-client-experimental/src/main/cpp/lorie/lorie_message_queue.cpp b/x11-client-experimental/src/main/cpp/lorie/lorie_message_queue.cpp deleted file mode 100644 index dceb8cdac..000000000 --- a/x11-client-experimental/src/main/cpp/lorie/lorie_message_queue.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "lorie_message_queue.hpp" -#if 1 -#define ALOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "LorieX11Client", fmt, ## __VA_ARGS__) -#else -#define ALOGE(fmt, ...) printf(fmt, ## __VA_ARGS__); printf("\n") -#endif - -lorie_message_queue::lorie_message_queue() { - std::unique_lock lock(mutex); - - fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); - if (fd == -1) { - ALOGE("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(std::move(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/x11-client-experimental/src/main/cpp/lorie/lorie_message_queue.hpp b/x11-client-experimental/src/main/cpp/lorie/lorie_message_queue.hpp deleted file mode 100644 index 5cfbee2d6..000000000 --- a/x11-client-experimental/src/main/cpp/lorie/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/x11-client-experimental/src/main/cpp/xcbproto b/x11-client-experimental/src/main/cpp/xcbproto deleted file mode 160000 index ed461f379..000000000 --- a/x11-client-experimental/src/main/cpp/xcbproto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ed461f379b6cde5bea7bc99d253c270b37298401 diff --git a/x11-client-experimental/src/main/cpp/xorgproto b/x11-client-experimental/src/main/cpp/xorgproto deleted file mode 160000 index 824001c94..000000000 --- a/x11-client-experimental/src/main/cpp/xorgproto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 824001c947cb1962209c6a8f2c63c2637877220d diff --git a/x11-client-experimental/src/main/ic_launcher-web.png b/x11-client-experimental/src/main/ic_launcher-web.png deleted file mode 100644 index d7497dee5..000000000 Binary files a/x11-client-experimental/src/main/ic_launcher-web.png and /dev/null differ diff --git a/x11-client-experimental/src/main/java/com/termux/x11/CmdEntryPoint.java b/x11-client-experimental/src/main/java/com/termux/x11/CmdEntryPoint.java deleted file mode 100644 index 70efe5e8e..000000000 --- a/x11-client-experimental/src/main/java/com/termux/x11/CmdEntryPoint.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.termux.x11; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Looper; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.util.Log; - -import java.util.Arrays; - -import dalvik.system.PathClassLoader; - -public class CmdEntryPoint { - public static void main(String[] args) throws Exception { -// if (Arrays.stream(args).noneMatch(s->s.equals("asd"))) { -// Context ctx = android.app.ActivityThread.systemMain().getSystemContext(); -// PackageManager pm = ctx.getPackageManager(); -// ApplicationInfo target = pm.getApplicationInfo("com.termux.x11", 0); -// @SuppressLint("SdCardPath") -// String librarySearchPath = "/data/data/com.termux/files/usr/lib/:" + target.sourceDir + "!/lib/" + Build.SUPPORTED_ABIS[0] + "/"; -// PathClassLoader classLoader = new PathClassLoader(target.sourceDir, librarySearchPath, -// ClassLoader.getSystemClassLoader()); -// Class targetClass = Class.forName("com.termux.x11.CmdEntryPoint", true, classLoader); -// targetClass.getMethod("main", String[].class).invoke(null, (Object) new String[]{"asd"}); -// return; -// } -// -// System.loadLibrary("lorie"); - - System.err.println("CmdEntryPoint started"); - Context ctx = android.app.ActivityThread.systemMain().getSystemContext(); - - Intent intent = new Intent(); - Bundle bundle = new Bundle(); - intent.setPackage("com.termux.x11"); - intent.setAction("a"); - intent.putExtra("", bundle); - bundle.putBinder("", new ICmdEntryPointInterface.Stub() { - @Override - public ParcelFileDescriptor getConnectionFd() throws RemoteException { - int fd = connect(); - System.err.println("Sending fd " + fd); - return (fd == -1) ? null : ParcelFileDescriptor.adoptFd(fd); - } - }); - - ctx.sendBroadcast(intent); - - Looper.loop(); - } - - static native int connect(); - - static { - System.loadLibrary("lorie"); - } -} diff --git a/x11-client-experimental/src/main/java/com/termux/x11/MainActivity.java b/x11-client-experimental/src/main/java/com/termux/x11/MainActivity.java deleted file mode 100644 index e4f3e5a65..000000000 --- a/x11-client-experimental/src/main/java/com/termux/x11/MainActivity.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.termux.x11; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; - -public class MainActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main_activity); - BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - try { - Log.i("App", "Got intent"); - ICmdEntryPointInterface iface = ICmdEntryPointInterface.Stub.asInterface(intent.getBundleExtra("").getBinder("")); - int fd = iface.getConnectionFd().detachFd(); - Log.i("App", "Starting with fd "+ fd); - start(fd); - } catch (Exception e) { - e.printStackTrace(); - } - } - }; - registerReceiver(receiver, new IntentFilter("a")); - - SurfaceView v = findViewById(R.id.lorieView); - v.getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(@NonNull SurfaceHolder holder) { - Log.e("asd", "surfaceCreated"); - surface(holder.getSurface(), 0, 0); - } - - @Override - public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { - Log.e("asd", "surfaceChanged"); - surface(holder.getSurface(), width, height); - } - - @Override - public void surfaceDestroyed(@NonNull SurfaceHolder holder) { - Log.e("asd", "surfaceDestroyed"); - surface(null, 0, 0); - } - }); - } - - @Override - public void setTheme(int resId) { - super.setTheme(R.style.NoActionBar); - } - - @Override - public void onBackPressed() { - } - - private native void start(int fd); - private native void surface(Surface sfc, int width, int height); - - static { - System.loadLibrary("lorie"); - } -} diff --git a/x11-client-experimental/src/main/res/drawable-anydpi-v24/ic_x11_icon.xml b/x11-client-experimental/src/main/res/drawable-anydpi-v24/ic_x11_icon.xml deleted file mode 100644 index 3046d3563..000000000 --- a/x11-client-experimental/src/main/res/drawable-anydpi-v24/ic_x11_icon.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/x11-client-experimental/src/main/res/drawable-hdpi/ic_x11_icon.png b/x11-client-experimental/src/main/res/drawable-hdpi/ic_x11_icon.png deleted file mode 100644 index 2d86741b2..000000000 Binary files a/x11-client-experimental/src/main/res/drawable-hdpi/ic_x11_icon.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/drawable-mdpi/ic_x11_icon.png b/x11-client-experimental/src/main/res/drawable-mdpi/ic_x11_icon.png deleted file mode 100644 index b108458ff..000000000 Binary files a/x11-client-experimental/src/main/res/drawable-mdpi/ic_x11_icon.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/drawable-xhdpi/ic_x11_icon.png b/x11-client-experimental/src/main/res/drawable-xhdpi/ic_x11_icon.png deleted file mode 100644 index ea7caaa71..000000000 Binary files a/x11-client-experimental/src/main/res/drawable-xhdpi/ic_x11_icon.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/drawable-xxhdpi/ic_x11_icon.png b/x11-client-experimental/src/main/res/drawable-xxhdpi/ic_x11_icon.png deleted file mode 100644 index 8f9022f49..000000000 Binary files a/x11-client-experimental/src/main/res/drawable-xxhdpi/ic_x11_icon.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/layout/getting_started_activity.xml b/x11-client-experimental/src/main/res/layout/getting_started_activity.xml deleted file mode 100644 index e65d46b6e..000000000 --- a/x11-client-experimental/src/main/res/layout/getting_started_activity.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/layout/main_activity.xml b/x11-client-experimental/src/main/res/layout/main_activity.xml deleted file mode 100644 index 07d092926..000000000 --- a/x11-client-experimental/src/main/res/layout/main_activity.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - diff --git a/x11-client-experimental/src/main/res/layout/partial_primary_toolbar.xml b/x11-client-experimental/src/main/res/layout/partial_primary_toolbar.xml deleted file mode 100644 index 6124c04b2..000000000 --- a/x11-client-experimental/src/main/res/layout/partial_primary_toolbar.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/layout/preferences_toolbar.xml b/x11-client-experimental/src/main/res/layout/preferences_toolbar.xml deleted file mode 100644 index 151d34ec5..000000000 --- a/x11-client-experimental/src/main/res/layout/preferences_toolbar.xml +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 036d09bc5..000000000 --- a/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 036d09bc5..000000000 --- a/x11-client-experimental/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher.png b/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index dcba64030..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 59b66bda7..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_round.png b/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index f8fbd7a1c..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher.png b/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 404d8c149..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 4fe19aad8..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_round.png b/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index b6ff6e2bf..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher.png b/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 17efe24c0..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 071bdfeaa..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 7437fef97..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher.png b/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 675a86023..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index c1283789a..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index bcde5cd97..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 90d86bc54..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index b38690602..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 0aae7116d..000000000 Binary files a/x11-client-experimental/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/x11-client-experimental/src/main/res/values/arrays.xml b/x11-client-experimental/src/main/res/values/arrays.xml deleted file mode 100644 index 6b5380b83..000000000 --- a/x11-client-experimental/src/main/res/values/arrays.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - Emulate mouse - Emulate touchpad - - - 0 - 1 - - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/values/colors.xml b/x11-client-experimental/src/main/res/values/colors.xml deleted file mode 100644 index 01baea95b..000000000 --- a/x11-client-experimental/src/main/res/values/colors.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - #008577 - #00574B - #D81B60 - #DC143C - #FC143C - diff --git a/x11-client-experimental/src/main/res/values/dimens.xml b/x11-client-experimental/src/main/res/values/dimens.xml deleted file mode 100644 index 7605196c6..000000000 --- a/x11-client-experimental/src/main/res/values/dimens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 16dp - 4dip - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/values/ic_launcher_background.xml b/x11-client-experimental/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index beab31f75..000000000 --- a/x11-client-experimental/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #000000 - \ No newline at end of file diff --git a/x11-client-experimental/src/main/res/values/strings.xml b/x11-client-experimental/src/main/res/values/strings.xml deleted file mode 100644 index ddfc11c20..000000000 --- a/x11-client-experimental/src/main/res/values/strings.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - ]> - - &TERMUX_X11_APP_NAME; - &TERMUX_X11_APP_NAME; is a plugin app for the &TERMUX_APP_NAME; app. - \n\nCheck &TERMUX_APP_NAME; app github %1$s and &TERMUX_X11_APP_NAME; app github %2$s for more info. - - - The storage permission must be granted - to &TERMUX_X11_APP_NAME; app to... - Grant Storage Permission - - Android battery optimizations - should be disabled for the &TERMUX_X11_APP_NAME; app so that… - Check https://developer.android.com/about/versions/oreo/background for more info and - https://developer.android.com/guide/components/foreground-services#background-start-restrictions - for more info. - - \n\nAlso check https://dontkillmyapp.com for info on vendor specific app killers. - Depending on vendor you may need to do things like enable AutoStart, disable DuraSpeed, - enable `Display pop-up windows while running in the background` for the app. - Disable Battery Optimizations - - The display over other - apps permission should be granted to &TERMUX_X11_APP_NAME; app for starting foreground - activities from background. Check https://developer.android.com/guide/components/activities/background-starts - for more info. - - Grant Draw Over Apps Permission - - Already Granted - Already Disabled - Not conected - Getting started - Preferences - diff --git a/x11-client-experimental/src/main/res/values/styles.xml b/x11-client-experimental/src/main/res/values/styles.xml deleted file mode 100644 index 92cf37110..000000000 --- a/x11-client-experimental/src/main/res/values/styles.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/x11-client-experimental/src/main/res/xml/preferences.xml b/x11-client-experimental/src/main/res/xml/preferences.xml deleted file mode 100644 index 812cb887b..000000000 --- a/x11-client-experimental/src/main/res/xml/preferences.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/x11-client-experimental/src/main/res/xml/shortcuts.xml b/x11-client-experimental/src/main/res/xml/shortcuts.xml deleted file mode 100644 index d48471eaa..000000000 --- a/x11-client-experimental/src/main/res/xml/shortcuts.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -