From 3f42c61ead715884ac6b1f85c0b6054ff437646d Mon Sep 17 00:00:00 2001 From: Javier Date: Thu, 1 Nov 2018 13:01:39 +0100 Subject: Initial import --- app/.gitignore | 1 + app/CMakeLists.txt | 86 ++ app/build.gradle | 44 + app/libs/LibVNCServer-0.9.11.tar.gz | Bin 0 -> 1413739 bytes app/libs/build-openssl.sh | 31 + app/libs/cmake/FindJPEG.cmake | 9 + app/libs/cmake/FindOpenSSL.cmake | 12 + app/libs/cmake/FindPNG.cmake | 1 + app/libs/libjpeg-turbo-2.0.0.tar.gz | Bin 0 -> 2158457 bytes app/libs/libvncserver-LibVNCServer-0.9.11.patch | 236 ++++ app/libs/openssl-1.1.1.tar.gz | Bin 0 -> 8337920 bytes app/libs/prepare.sh | 13 + app/proguard-rules.pro | 21 + app/src/main/AndroidManifest.xml | 41 + app/src/main/cpp/native-lib.cpp | 361 ++++++ .../com/javispedro/vndroid/ControlService.java | 47 + .../com/javispedro/vndroid/KeyEventOutput.java | 286 +++++ .../com/javispedro/vndroid/PointerEventOutput.java | 101 ++ .../java/com/javispedro/vndroid/RFBServer.java | 98 ++ .../java/com/javispedro/vndroid/ScreenGrabber.java | 83 ++ .../javispedro/vndroid/ScreenMirrorGrabber.java | 110 ++ .../javispedro/vndroid/ScreenVirtualGrabber.java | 38 + .../vndroid/ServerRunningNotification.java | 108 ++ .../java/com/javispedro/vndroid/ServerService.java | 175 +++ .../java/com/javispedro/vndroid/SetupActivity.java | 78 ++ .../vndroid/keymaps/AndroidKeyHandler.java | 69 + .../vndroid/keymaps/KeyActionHandler.java | 20 + .../com/javispedro/vndroid/keymaps/KeyHandler.java | 12 + .../com/javispedro/vndroid/keymaps/KeySyms.java | 1321 ++++++++++++++++++++ .../vndroid/keymaps/SpanishKeyHandler.java | 51 + .../res/drawable-hdpi/ic_action_stat_reply.png | Bin 0 -> 1480 bytes .../res/drawable-hdpi/ic_action_stat_share.png | Bin 0 -> 1606 bytes .../ic_action_stop_screen_sharing.png | Bin 0 -> 444 bytes .../res/drawable-hdpi/ic_stat_server_running.png | Bin 0 -> 345 bytes .../res/drawable-mdpi/ic_action_stat_reply.png | Bin 0 -> 1314 bytes .../res/drawable-mdpi/ic_action_stat_share.png | Bin 0 -> 1341 bytes .../ic_action_stop_screen_sharing.png | Bin 0 -> 321 bytes .../res/drawable-mdpi/ic_stat_server_running.png | Bin 0 -> 264 bytes .../main/res/drawable-nodpi/example_picture.png | Bin 0 -> 1885 bytes .../res/drawable-v24/ic_launcher_foreground.xml | 34 + .../res/drawable-xhdpi/ic_action_stat_reply.png | Bin 0 -> 1692 bytes .../res/drawable-xhdpi/ic_action_stat_share.png | Bin 0 -> 1780 bytes .../ic_action_stop_screen_sharing.png | Bin 0 -> 594 bytes .../res/drawable-xhdpi/ic_stat_server_running.png | Bin 0 -> 431 bytes .../ic_action_stop_screen_sharing.png | Bin 0 -> 887 bytes .../res/drawable-xxhdpi/ic_stat_server_running.png | Bin 0 -> 618 bytes .../ic_action_stop_screen_sharing.png | Bin 0 -> 1168 bytes .../drawable-xxxhdpi/ic_stat_server_running.png | Bin 0 -> 873 bytes .../main/res/drawable/ic_launcher_background.xml | 170 +++ app/src/main/res/layout/activity_setup.xml | 45 + app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../res/mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes app/src/main/res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes app/src/main/res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../main/res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../main/res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../main/res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 11 + app/src/main/res/values/styles.xml | 11 + app/src/main/res/xml/controlservice.xml | 6 + 66 files changed, 3746 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/CMakeLists.txt create mode 100644 app/build.gradle create mode 100644 app/libs/LibVNCServer-0.9.11.tar.gz create mode 100755 app/libs/build-openssl.sh create mode 100644 app/libs/cmake/FindJPEG.cmake create mode 100644 app/libs/cmake/FindOpenSSL.cmake create mode 100644 app/libs/cmake/FindPNG.cmake create mode 100644 app/libs/libjpeg-turbo-2.0.0.tar.gz create mode 100644 app/libs/libvncserver-LibVNCServer-0.9.11.patch create mode 100644 app/libs/openssl-1.1.1.tar.gz create mode 100755 app/libs/prepare.sh create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/cpp/native-lib.cpp create mode 100644 app/src/main/java/com/javispedro/vndroid/ControlService.java create mode 100644 app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java create mode 100644 app/src/main/java/com/javispedro/vndroid/PointerEventOutput.java create mode 100644 app/src/main/java/com/javispedro/vndroid/RFBServer.java create mode 100644 app/src/main/java/com/javispedro/vndroid/ScreenGrabber.java create mode 100644 app/src/main/java/com/javispedro/vndroid/ScreenMirrorGrabber.java create mode 100644 app/src/main/java/com/javispedro/vndroid/ScreenVirtualGrabber.java create mode 100644 app/src/main/java/com/javispedro/vndroid/ServerRunningNotification.java create mode 100644 app/src/main/java/com/javispedro/vndroid/ServerService.java create mode 100644 app/src/main/java/com/javispedro/vndroid/SetupActivity.java create mode 100644 app/src/main/java/com/javispedro/vndroid/keymaps/AndroidKeyHandler.java create mode 100644 app/src/main/java/com/javispedro/vndroid/keymaps/KeyActionHandler.java create mode 100644 app/src/main/java/com/javispedro/vndroid/keymaps/KeyHandler.java create mode 100644 app/src/main/java/com/javispedro/vndroid/keymaps/KeySyms.java create mode 100644 app/src/main/java/com/javispedro/vndroid/keymaps/SpanishKeyHandler.java create mode 100644 app/src/main/res/drawable-hdpi/ic_action_stat_reply.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_stat_share.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_server_running.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_stat_reply.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_stat_share.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.png create mode 100644 app/src/main/res/drawable-mdpi/ic_stat_server_running.png create mode 100644 app/src/main/res/drawable-nodpi/example_picture.png create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_stat_reply.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_stat_share.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_server_running.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_stat_server_running.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.png create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_setup.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/xml/controlservice.xml (limited to 'app') diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..c56f72d --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,86 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs/cmake) + +# OpenSSL stuff +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/openssl/include) +add_custom_command(OUTPUT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libssl.so ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrypto.so + COMMAND ${CMAKE_COMMAND} -E env + SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl + OUTPUT_DIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + ANDROID_NDK=${ANDROID_NDK} + ANDROID_ABI=${ANDROID_ABI} + ANDROID_LLVM_TOOLCHAIN_PREFIX=${ANDROID_LLVM_TOOLCHAIN_PREFIX} + ${CMAKE_CURRENT_SOURCE_DIR}/libs/build-openssl.sh + COMMENT "Building OpenSSL" + WORKING_DIRECTORY openssl) +add_custom_target(openssl DEPENDS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libssl.so ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrypto.so) + +add_library(libssl SHARED IMPORTED) +add_dependencies(libssl openssl) +set_property(TARGET libssl PROPERTY IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libssl.so) +set_property(TARGET libssl PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/openssl/include ${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl/include) + +add_library(libcrypto SHARED IMPORTED) +add_dependencies(libcrypto openssl) +set_property(TARGET libcrypto PROPERTY IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrypto.so) +set_property(TARGET libssl PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/openssl/include ${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl/include) + +# libjpeg-turbo +set(ENABLE_STATIC OFF CACHE BOOL "Disable turbojpeg static libs") +set(WITH_TURBOJPEG OFF CACHE BOOL "Disable turbojpeg libturbojpeg") +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/libjpeg-turbo libjpeg-turbo EXCLUDE_FROM_ALL) +target_include_directories(jpeg + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/libs/libjpeg-turbo + INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo + ) + +# libvncserver +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/libvncserver libvncserver EXCLUDE_FROM_ALL) + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +add_library( # Sets the name of the library. + native-lib + + # Sets the library as a shared library. + SHARED + + # Provides a relative path to your source file(s). + src/main/cpp/native-lib.cpp ) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +find_library( # Sets the name of the path variable. + log-lib + + # Specifies the name of the NDK library that + # you want CMake to locate. + log ) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +target_link_libraries( # Specifies the target library. + native-lib + + libssl + libcrypto + jpeg + vncserver + + # Links the target library to the log library + # included in the NDK. + ${log-lib} ) \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..523c8a4 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,44 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.javispedro.vndroid" + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + ndk { + //abiFilters 'x86' + } + externalNativeBuild { + cmake { + targets 'native-lib', 'libssl', 'jpeg', 'vncserver' + } + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + productFlavors { + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'com.android.support:support-v4:28.0.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} diff --git a/app/libs/LibVNCServer-0.9.11.tar.gz b/app/libs/LibVNCServer-0.9.11.tar.gz new file mode 100644 index 0000000..c33564a Binary files /dev/null and b/app/libs/LibVNCServer-0.9.11.tar.gz differ diff --git a/app/libs/build-openssl.sh b/app/libs/build-openssl.sh new file mode 100755 index 0000000..5e32899 --- /dev/null +++ b/app/libs/build-openssl.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +case $ANDROID_ABI in +armeabi*) + target=android-arm + ;; +arm64-v8a) + target=android-arm64 + ;; +x86) + target=android-x86 + ;; +x86_64) + target=android-x86_64 + ;; +*) + target=android + ;; +esac + +export PATH="$ANDROID_LLVM_TOOLCHAIN_PREFIX:$PATH" + +perl $SOURCE_DIR/Configure shared $target + +make -j$(nproc) SHLIB_EXT=.so + +cp libcrypto.so $OUTPUT_DIR/libcrypto.so +cp libssl.so $OUTPUT_DIR/libssl.so + diff --git a/app/libs/cmake/FindJPEG.cmake b/app/libs/cmake/FindJPEG.cmake new file mode 100644 index 0000000..b3d7778 --- /dev/null +++ b/app/libs/cmake/FindJPEG.cmake @@ -0,0 +1,9 @@ + +set(JPEG_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/libs/libjpeg-turbo ${CMAKE_BINARY_DIR}/libjpeg-turbo) +set(JPEG_LIBRARIES jpeg) + +find_package_handle_standard_args(JPEG "Could NOT find JPEG" + JPEG_LIBRARIES + JPEG_INCLUDE_DIR + ) + diff --git a/app/libs/cmake/FindOpenSSL.cmake b/app/libs/cmake/FindOpenSSL.cmake new file mode 100644 index 0000000..c9ea679 --- /dev/null +++ b/app/libs/cmake/FindOpenSSL.cmake @@ -0,0 +1,12 @@ + +set(OPENSSL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/openssl/include) +set(OPENSSL_SSL_LIBRARY libssl) +set(OPENSSL_CRYPTO_LIBRARY libcrypto) + +set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) + +find_package_handle_standard_args(OpenSSL "Could NOT find OpenSSL" + OPENSSL_LIBRARIES + OPENSSL_INCLUDE_DIR + ) + diff --git a/app/libs/cmake/FindPNG.cmake b/app/libs/cmake/FindPNG.cmake new file mode 100644 index 0000000..42900e8 --- /dev/null +++ b/app/libs/cmake/FindPNG.cmake @@ -0,0 +1 @@ +message(STATUS PNG) diff --git a/app/libs/libjpeg-turbo-2.0.0.tar.gz b/app/libs/libjpeg-turbo-2.0.0.tar.gz new file mode 100644 index 0000000..89fcfba Binary files /dev/null and b/app/libs/libjpeg-turbo-2.0.0.tar.gz differ diff --git a/app/libs/libvncserver-LibVNCServer-0.9.11.patch b/app/libs/libvncserver-LibVNCServer-0.9.11.patch new file mode 100644 index 0000000..71adf2a --- /dev/null +++ b/app/libs/libvncserver-LibVNCServer-0.9.11.patch @@ -0,0 +1,236 @@ +diff -rup a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt 2016-12-30 14:01:28.000000000 +0100 ++++ b/CMakeLists.txt 2018-11-03 23:17:24.323450995 +0100 +@@ -18,7 +18,6 @@ set(VERSION_PATCHLEVEL "11") + set(VERSION_SO "0") + set(PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCHLEVEL}") + set(PROJECT_BUGREPORT_PATH "http://sourceforge.net/projects/libvncserver") +-set(CMAKE_C_FLAGS "-O2 -W -Wall -g") + set(LIBVNCSERVER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libvncserver) + set(COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) + set(LIBVNCCLIENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libvncclient) +@@ -192,7 +191,7 @@ TEST_BIG_ENDIAN(LIBVNCSERVER_WORDS_BIGEN + # LIBVNCSERVER_ENOENT_WORKAROUND + # inline + +-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/rfb/rfbconfig.h.cmake ${CMAKE_BINARY_DIR}/rfb/rfbconfig.h) ++configure_file(${CMAKE_CURRENT_SOURCE_DIR}/rfb/rfbconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/rfb/rfbconfig.h) + + set(LIBVNCSERVER_SOURCES + ${LIBVNCSERVER_DIR}/main.c +@@ -315,6 +314,11 @@ target_link_libraries(vncserver + ${WEBSOCKET_LIBRARIES} + ) + ++target_include_directories(vncserver ++ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ++ INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ++ ) ++ + SET_TARGET_PROPERTIES(vncclient vncserver + PROPERTIES SOVERSION "${VERSION_SO}" VERSION "${PACKAGE_VERSION}" + ) +@@ -378,19 +382,6 @@ if(HAVE_FFMPEG) + ) + endif(HAVE_FFMPEG) + +- +-file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/examples) +-foreach(test ${LIBVNCSERVER_TESTS}) +- add_executable(examples_${test} ${LIBVNCSRVTEST_DIR}/${test}.c) +- target_link_libraries(examples_${test} vncserver ${CMAKE_THREAD_LIBS_INIT}) +-endforeach(test ${LIBVNCSERVER_TESTS}) +- +-file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/client_examples) +-foreach(test ${LIBVNCCLIENT_TESTS}) +- add_executable(client_examples_${test} ${LIBVNCCLITEST_DIR}/${test}.c ${LIBVNCCLITEST_DIR}/${${test}_EXTRA_SOURCES} ) +- target_link_libraries(client_examples_${test} vncclient ${CMAKE_THREAD_LIBS_INIT} ${X11_LIBRARIES} ${SDL_LIBRARY} ${FFMPEG_LIBRARIES}) +-endforeach(test ${LIBVNCCLIENT_TESTS}) +- + install_targets(/lib vncserver) + install_targets(/lib vncclient) + install_files(/include/rfb FILES +diff -rup a/libvncclient/listen.c b/libvncclient/listen.c +--- a/libvncclient/listen.c 2016-12-30 14:01:28.000000000 +0100 ++++ b/libvncclient/listen.c 2018-11-03 23:17:24.318450981 +0100 +@@ -85,7 +85,7 @@ listenForIncomingConnections(rfbClient* + int r; + /* reap any zombies */ + int status, pid; +- while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0); ++ while ((pid = waitpid(-1, &status, WNOHANG))>0); + + /* TODO: callback for discard any events (like X11 events) */ + +diff -rup a/libvncclient/tls_openssl.c b/libvncclient/tls_openssl.c +--- a/libvncclient/tls_openssl.c 2016-12-30 14:01:28.000000000 +0100 ++++ b/libvncclient/tls_openssl.c 2018-11-03 23:17:24.318450981 +0100 +@@ -189,7 +189,7 @@ ssl_verify (int ok, X509_STORE_CTX *ctx) + + ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ()); + +- client = SSL_CTX_get_app_data (ssl->ctx); ++ client = SSL_CTX_get_app_data (SSL_get_SSL_CTX (ssl)); + + cert = X509_STORE_CTX_get_current_cert (ctx); + err = X509_STORE_CTX_get_error (ctx); +@@ -287,11 +287,10 @@ open_ssl_connection (rfbClient *client, + { + if (wait_for_data(ssl, n, 1) != 1) + { +- finished = 1; +- if (ssl->ctx) +- SSL_CTX_free (ssl->ctx); +- SSL_free(ssl); ++ finished = 1; + SSL_shutdown (ssl); ++ SSL_free(ssl); ++ SSL_CTX_free (ssl_ctx); + + return NULL; + } +@@ -365,10 +364,11 @@ return TRUE; + static rfbBool + ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result) + { ++ static const unsigned int max_auth = 256; + uint8_t count=0; + uint8_t loop=0; + uint8_t flag=0; +- uint32_t tAuth[256], t; ++ uint32_t tAuth[max_auth], t; + char buf1[500],buf2[10]; + uint32_t authScheme; + +@@ -380,9 +380,9 @@ ReadVeNCryptSecurityType(rfbClient* clie + return FALSE; + } + +- if (count>sizeof(tAuth)) ++ if (count>=max_auth) + { +- rfbClientLog("%d security types are too many; maximum is %d\n", count, sizeof(tAuth)); ++ rfbClientLog("%d security types are too many; maximum is %d\n", count, max_auth); + return FALSE; + } + +diff -rup a/libvncserver/main.c b/libvncserver/main.c +--- a/libvncserver/main.c 2016-12-30 14:01:28.000000000 +0100 ++++ b/libvncserver/main.c 2018-11-03 23:17:24.320450987 +0100 +@@ -561,6 +561,7 @@ clientInput(void *data) + } + } + ++ rfbLog("input: waiting for output thread"); + /* Get rid of the output thread. */ + LOCK(cl->updateMutex); + TSIGNAL(cl->updateCond); +@@ -569,6 +570,8 @@ clientInput(void *data) + + rfbClientConnectionGone(cl); + ++ rfbLog("input: exit thread"); ++ + return NULL; + } + +@@ -945,7 +948,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc, + void rfbNewFramebuffer(rfbScreenInfoPtr screen, char *framebuffer, + int width, int height, + int bitsPerSample, int samplesPerPixel, +- int bytesPerPixel) ++ int bytesPerPixel, int bytesPerRow) + { + rfbPixelFormat old_format; + rfbBool format_changed = FALSE; +@@ -962,7 +965,7 @@ void rfbNewFramebuffer(rfbScreenInfoPtr + screen->width = width; + screen->height = height; + screen->bitsPerPixel = screen->depth = 8*bytesPerPixel; +- screen->paddedWidthInBytes = width*bytesPerPixel; ++ screen->paddedWidthInBytes = bytesPerRow; + + rfbInitServerFormat(screen, bitsPerSample); + +@@ -1062,22 +1065,30 @@ void rfbInitServer(rfbScreenInfoPtr scre + #endif + } + +-void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { ++void rfbShutdownServer(rfbScreenInfoPtr screen, rfbBool disconnectClients) { ++ rfbShutdownSockets(screen); ++ rfbHttpShutdownSockets(screen); ++ + if(disconnectClients) { + rfbClientPtr cl; +- rfbClientIteratorPtr iter = rfbGetClientIterator(screen); +- while( (cl = rfbClientIteratorNext(iter)) ) { +- if (cl->sock > -1) { +- /* we don't care about maxfd here, because the server goes away */ +- rfbCloseClient(cl); +- rfbClientConnectionGone(cl); +- } ++ ++ cl = screen->clientHead; ++ ++ while (cl) { ++ rfbClientPtr next = cl->next; ++ if (cl->sock != -1) { ++ rfbCloseClient(cl); ++ if (screen->backgroundLoop) { ++ pthread_join(cl->client_thread, NULL); ++ } else { ++ rfbClientConnectionGone(cl); ++ } ++ } ++ cl = next; + } +- rfbReleaseClientIterator(iter); + } + +- rfbShutdownSockets(screen); +- rfbHttpShutdownSockets(screen); ++ + } + + #ifndef LIBVNCSERVER_HAVE_GETTIMEOFDAY +diff -rup a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c +--- a/libvncserver/rfbserver.c 2016-12-30 14:01:28.000000000 +0100 ++++ b/libvncserver/rfbserver.c 2018-11-03 23:17:24.320450987 +0100 +@@ -552,8 +552,10 @@ rfbClientConnectionGone(rfbClientPtr cl) + do { + LOCK(cl->refCountMutex); + i=cl->refCount; +- if(i>0) +- WAIT(cl->deleteCond,cl->refCountMutex); ++ if(i>0) { ++ rfbLog("Client %s still has %d refs\n",cl->host, i); ++ WAIT(cl->deleteCond, cl->refCountMutex); ++ } + UNLOCK(cl->refCountMutex); + } while(i>0); + } +diff -rup a/libvncserver/rfbssl_openssl.c b/libvncserver/rfbssl_openssl.c +--- a/libvncserver/rfbssl_openssl.c 2016-12-30 14:01:28.000000000 +0100 ++++ b/libvncserver/rfbssl_openssl.c 2018-11-03 23:17:24.320450987 +0100 +@@ -56,7 +56,7 @@ int rfbssl_init(rfbClientPtr cl) + rfbErr("OOM\n"); + } else if (!cl->screen->sslcertfile || !cl->screen->sslcertfile[0]) { + rfbErr("SSL connection but no cert specified\n"); +- } else if (NULL == (ctx->ssl_ctx = SSL_CTX_new(TLSv1_server_method()))) { ++ } else if (NULL == (ctx->ssl_ctx = SSL_CTX_new(TLS_server_method()))) { + rfbssl_error(); + } else if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, keyfile, SSL_FILETYPE_PEM) <= 0) { + rfbErr("Unable to load private key file %s\n", keyfile); +diff -rup a/rfb/rfb.h b/rfb/rfb.h +--- a/rfb/rfb.h 2016-12-30 14:01:28.000000000 +0100 ++++ b/rfb/rfb.h 2018-11-03 23:17:24.320450987 +0100 +@@ -1034,7 +1034,7 @@ extern void rfbInitServer(rfbScreenInfoP + extern void rfbShutdownServer(rfbScreenInfoPtr rfbScreen,rfbBool disconnectClients); + extern void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen,char *framebuffer, + int width,int height, int bitsPerSample,int samplesPerPixel, +- int bytesPerPixel); ++ int bytesPerPixel, int bytesPerRow); + + extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo); + extern void rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...); diff --git a/app/libs/openssl-1.1.1.tar.gz b/app/libs/openssl-1.1.1.tar.gz new file mode 100644 index 0000000..8f743ea Binary files /dev/null and b/app/libs/openssl-1.1.1.tar.gz differ diff --git a/app/libs/prepare.sh b/app/libs/prepare.sh new file mode 100755 index 0000000..820e17e --- /dev/null +++ b/app/libs/prepare.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -ve + +tar xvf openssl-1.1.1.tar.gz +ln -sf openssl-1.1.1 openssl + +tar xvf libjpeg-turbo-2.0.0.tar.gz +ln -sf libjpeg-turbo-2.0.0 libjpeg-turbo + +tar xvf LibVNCServer-0.9.11.tar.gz +ln -sf libvncserver-LibVNCServer-0.9.11 libvncserver +(cd libvncserver && patch -p1 < ../libvncserver-LibVNCServer-0.9.11.patch) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5786f0f --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp new file mode 100644 index 0000000..3a1811c --- /dev/null +++ b/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,361 @@ +#include +#include +#include + +#include +#include + +#define LOG_TAG "RFBServerNative" + +#define CLASS_EVENT_CALLBACK "com/javispedro/vndroid/RFBServer$EventCallback" + +static void rfb_err(const char *format, ...) { + va_list args; + va_start(args, format); + __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); + va_end(args); +} + +static void rfb_log(const char *format, ...) { + va_list args; + va_start(args, format); + __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args); + va_end(args); +} + +struct Data +{ + jclass cls; + jfieldID fid; + jfieldID fid_cb; + + rfbScreenInfoPtr screen; + + std::thread listenThread; + int listenEventFd; + + std::thread eventThread; + int eventEventFd; + + jclass cb_cls; + jobject cb_obj; + jmethodID cb_ev_ptr; + jmethodID cb_ev_key; + + std::atomic pendingPtrEvent; + int ptrButtonMask, ptrX, ptrY; + + std::atomic pendingKeyEvent; + rfbKeySym key; + bool keyState; +}; + +static inline Data * getData(JNIEnv *env, jobject instance) +{ + jclass cls = env->GetObjectClass(instance); + cls = reinterpret_cast(env->NewGlobalRef(cls)); + + jfieldID fid = env->GetFieldID(cls, "nativeData", "J"); + + Data *data = reinterpret_cast(env->GetLongField(instance, fid)); + + assert(data); + + return data; +} + +static inline Data * getData(rfbClientPtr client) +{ + Data *data = reinterpret_cast(client->screen->screenData); + assert(data); + return data; +} + +static void listen_thread_main(Data *data, JavaVM *vm) +{ + rfbScreenInfoPtr screen = data->screen; + + while (rfbIsActive(screen)) { + int client_fd = -1; + fd_set listen_fds; /* temp file descriptor list for select() */ + FD_ZERO(&listen_fds); + if(screen->listenSock >= 0) + FD_SET(screen->listenSock, &listen_fds); + if(screen->listen6Sock >= 0) + FD_SET(screen->listen6Sock, &listen_fds); + + assert(data->listenEventFd >= 0); + FD_SET(data->listenEventFd, &listen_fds); + + int max_fd = std::max(screen->maxFd, data->listenEventFd) + 1; + + if (select(max_fd, &listen_fds, NULL, NULL, NULL) == -1) { + rfb_err("listen_thread_main: error in select"); + return; + } + + /* there is something on the listening sockets, handle new connections */ + struct sockaddr_storage peer; + socklen_t len = sizeof (peer); + if (screen->listenSock >= 0 && FD_ISSET(screen->listenSock, &listen_fds)) + client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len); + else if (screen->listen6Sock >= 0 && FD_ISSET(screen->listen6Sock, &listen_fds)) + client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len); + else if (data->listenEventFd >= 0 && FD_ISSET(data->listenEventFd, &listen_fds)) + break; + + rfbClientPtr cl = NULL; + if(client_fd >= 0) + cl = rfbNewClient(screen,client_fd); + if (cl && !cl->onHold ) + rfbStartOnHoldClient(cl); + } +} + +static void event_thread_main(Data *data, JavaVM *vm) +{ + rfbScreenInfoPtr screen = data->screen; + + JNIEnv *env = NULL; + vm->AttachCurrentThread(&env, 0); + assert(env); + + eventfd_t value; + while (rfbIsActive(screen)) { + if (eventfd_read(data->eventEventFd, &value) != 0) + break; + + if (data->pendingPtrEvent) { + env->CallVoidMethod(data->cb_obj, data->cb_ev_ptr, (jint)data->ptrButtonMask, data->ptrX, data->ptrY); + data->pendingPtrEvent = false; + } + + if (data->pendingKeyEvent) { + env->CallVoidMethod(data->cb_obj, data->cb_ev_key, (jint)data->key, (jboolean)data->keyState); + data->pendingKeyEvent = false; + } + } + + vm->DetachCurrentThread(); +} + +static void ptr_event(int buttonMask, int x, int y, rfbClientPtr cl) +{ + Data *data = getData(cl); + + data->ptrButtonMask = buttonMask; + data->ptrX = x; + data->ptrY = y; + data->pendingPtrEvent = true; + + eventfd_write(data->eventEventFd, 1); + + rfbDefaultPtrAddEvent(buttonMask, x, y, cl); +} + +static void key_event(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) +{ + Data *data = getData(cl); + + // TODO This misses keys... + + data->key = keySym; + data->keyState = down; + data->pendingKeyEvent = true; + + eventfd_write(data->eventEventFd, 1); +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_javispedro_vndroid_RFBServer_allocate(JNIEnv *env, jobject instance) +{ + jclass cls = env->GetObjectClass(instance); + cls = reinterpret_cast(env->NewGlobalRef(cls)); + + jfieldID fid = env->GetFieldID(cls, "nativeData", "J"); + + assert(fid); + assert(env->GetLongField(instance, fid) == 0); + + rfb_log("starting server"); + + rfbErr = rfb_err; + rfbLog = rfb_log; + + Data *data = new Data(); + assert(data); + + data->cls = cls; + data->fid = fid; + data->fid_cb = env->GetFieldID(cls, "callback", "L" CLASS_EVENT_CALLBACK ";"); + assert(data->fid_cb); + + jclass cb_cls = env->FindClass(CLASS_EVENT_CALLBACK); + assert(cb_cls); + data->cb_cls = cb_cls = reinterpret_cast(env->NewGlobalRef(cb_cls)); + data->cb_obj = 0; + data->cb_ev_ptr = env->GetMethodID(cb_cls, "onPointerEvent", "(III)V"); + assert(data->cb_ev_ptr); + data->cb_ev_key = env->GetMethodID(cb_cls, "onKeyEvent", "(IZ)V"); + assert(data->cb_ev_key); + + data->screen = 0; + data->listenEventFd = -1; + data->eventEventFd = -1; + + env->SetLongField(instance, fid, reinterpret_cast(data)); + + return JNI_TRUE; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_javispedro_vndroid_RFBServer_deallocate(JNIEnv *env, jobject instance) +{ + Data *data = getData(env, instance); + + assert(data->screen == 0); + + env->SetLongField(instance, data->fid, 0); + env->DeleteGlobalRef(data->cb_cls); + if (data->cb_obj) env->DeleteGlobalRef(data->cb_obj); + env->DeleteGlobalRef(data->cls); + + data->cb_cls = 0; + data->cb_obj = 0; + data->cls = 0; + + delete data; +} + + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_javispedro_vndroid_RFBServer_init(JNIEnv *env, jobject instance) +{ + Data *data = getData(env, instance); + + if (data->screen) { + rfb_err("server already initialized"); + return JNI_FALSE; + } + + JavaVM *vm = NULL; + env->GetJavaVM(&vm); + + rfb_log("allocating rfb screen"); + data->screen = rfbGetScreen(NULL, NULL, 0, 0, 0, 0, 0); + rfbInitServer(data->screen); + + data->screen->screenData = data; + data->screen->ptrAddEvent = ptr_event; + data->screen->kbdAddEvent = key_event; + + rfb_log("starting listen thread"); + data->screen->backgroundLoop = TRUE; + data->listenEventFd = eventfd(0, EFD_CLOEXEC); + if (data->listenEventFd == -1) { + rfbLogPerror("eventfd"); + return FALSE; + } + data->listenThread = std::thread(listen_thread_main, data, vm); + + rfb_log("starting event thread"); + data->eventThread = std::thread(event_thread_main, data, vm); + data->eventEventFd = eventfd(0, EFD_CLOEXEC); + if (data->eventEventFd == -1) { + rfbLogPerror("eventfd"); + return FALSE; + } + + return JNI_TRUE; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_javispedro_vndroid_RFBServer_shutdown(JNIEnv *env, jobject instance) +{ + Data *data = getData(env, instance); + + if (!data->screen) { + return; // Nothing to do + } + + rfb_log("shutting down rfb screen"); + rfbShutdownServer(data->screen, TRUE); + + rfb_log("waiting for listen thread"); + if (data->listenThread.joinable()) { + assert(data->listenEventFd != -1); + eventfd_write(data->listenEventFd, 1); + data->listenThread.join(); + } + close(data->listenEventFd); + data->listenEventFd = -1; + + rfb_log("waiting for event thread"); + if (data->eventThread.joinable()) { + assert(data->eventEventFd != -1); + eventfd_write(data->eventEventFd, 1); + data->eventThread.join(); + } + close(data->eventEventFd); + data->eventEventFd = -1; + + rfb_log("freeing up resources"); + rfbScreenCleanup(data->screen); + data->screen = 0; +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_javispedro_vndroid_RFBServer_set_1event_1callback(JNIEnv *env, jobject instance, + jobject callback) { + Data *data = getData(env, instance); + + if (data->cb_obj) { + env->DeleteGlobalRef(data->cb_obj); + } + + if (callback) { + data->cb_obj = env->NewGlobalRef(callback); + } else { + data->cb_obj = 0; + } +} + +extern "C" +JNIEXPORT jboolean JNICALL +Java_com_javispedro_vndroid_RFBServer_put_1image(JNIEnv *env, jobject instance, jint width, + jint height, jobject buffer, jint pixel_stride, + jint row_stride) { + Data *data = getData(env, instance); + if (!data->screen) { + rfb_err("no screen"); + return JNI_FALSE; + } + + const int bitsPerSample = 8; + const int samplesPerPixel = 3; + const int bytesPerPixel = pixel_stride; + const int bitsPerPixel = 8 * bytesPerPixel; + const int bytesPerRow = row_stride; + + bool size_change = data->screen->width != width || data->screen->height != height; + bool format_change = data->screen->bitsPerPixel != bitsPerPixel or data->screen->paddedWidthInBytes != bytesPerRow; + + char * fb = reinterpret_cast(env->GetDirectBufferAddress(buffer)); + + if (size_change || format_change) { + rfb_log("size or format changed"); + + rfbNewFramebuffer(data->screen, fb, width, height, bitsPerSample, samplesPerPixel, + bytesPerPixel, bytesPerRow); + } else { + data->screen->frameBuffer = fb; + rfbMarkRectAsModified(data->screen, 0, 0, width, height); + } + + return JNI_TRUE; +} diff --git a/app/src/main/java/com/javispedro/vndroid/ControlService.java b/app/src/main/java/com/javispedro/vndroid/ControlService.java new file mode 100644 index 0000000..db5362d --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ControlService.java @@ -0,0 +1,47 @@ +package com.javispedro.vndroid; + +import android.accessibilityservice.AccessibilityService; +import android.content.Intent; +import android.support.annotation.Nullable; +import android.util.Log; +import android.view.accessibility.AccessibilityEvent; + +public class ControlService extends AccessibilityService { + private final String TAG = ControlService.class.getSimpleName(); + + @Nullable + private static ControlService instance = null; + + @Override + public void onServiceConnected() { + super.onServiceConnected(); + Log.d(TAG, "onServiceConnected"); + instance = this; + } + + @Override + public boolean onUnbind(Intent intent) { + Log.d(TAG, "onUnbind"); + instance = null; + return super.onUnbind(intent); + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + + } + + @Override + public void onInterrupt() { + + } + + @Nullable + public static ControlService getInstance() { + return instance; + } + + public static boolean isServiceStarted() { + return instance != null; + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java b/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java new file mode 100644 index 0000000..597942a --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java @@ -0,0 +1,286 @@ +package com.javispedro.vndroid; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Log; +import android.view.accessibility.AccessibilityNodeInfo; + +import com.javispedro.vndroid.keymaps.KeyActionHandler; +import com.javispedro.vndroid.keymaps.KeyHandler; + +import java.util.ArrayList; +import java.util.List; + +public class KeyEventOutput implements KeyActionHandler { + private final String TAG = KeyEventOutput.class.getSimpleName(); + + private final List handlers = new ArrayList(); + + @Nullable + private AccessibilityNodeInfo getFocusNode() { + ControlService service = ControlService.getInstance(); + if (service != null) { + return service.findFocus(AccessibilityNodeInfo.FOCUS_INPUT); + } + return null; + } + + public void addHandler(KeyHandler handler) { + handler.setActionHandler(this); + handlers.add(handler); + } + + public void postKeyEvent(int key, boolean state) { + if (state) Log.d(TAG, "keysym pressed: " + Integer.toHexString(key)); + for (KeyHandler handler : handlers) { + boolean handled; + if (state) { + handled = handler.keyDown(key); + } else { + handled = handler.keyUp(key); + } + if (handled) { + break; + } + } + } + + @Override + public void postText(CharSequence text) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + final int textLen = text.length(); + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = new StringBuilder(curTextLen + textLen); + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + // No selection, no cursor + if (curTextLen > 0) builder.append(curText); + builder.append(text); + } else { + builder.append(curText.subSequence(0, selStart)); + builder.append(text); + builder.append(curText.subSequence(selEnd, curText.length())); + + selStart = selEnd + textLen; + selEnd = selStart; + } + + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + + if (selStart != -1 && selEnd != -1 && selStart != builder.length()) { + args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postChar(char c) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = new StringBuilder(curTextLen + 1); + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + // No selection, no cursor + if (curTextLen > 0) builder.append(curText); + builder.append(c); + } else { + builder.append(curText.subSequence(0, selStart)); + builder.append(c); + builder.append(curText.subSequence(selEnd, curText.length())); + + selStart = selEnd + 1; + selEnd = selStart; + } + + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + + if (selStart != -1 && selEnd != -1 && selStart != builder.length()) { + args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postLocalAction(int action) { + AccessibilityNodeInfo node = getFocusNode(); + if (node == null || !node.isEditable()) { + Log.d(TAG, "no input focus or not editable"); + return; + } + + final CharSequence curText = node.getText(); + final int curTextLen = curText != null ? curText.length() : 0; + int selStart = node.getTextSelectionStart(); + int selEnd = node.getTextSelectionEnd(); + StringBuilder builder = null; + + Log.d(TAG, " cur text: " + curText + " start=" + selStart + " end=" + selEnd); + + switch (action) { + case KeyActionHandler.ACTION_BACKSPACE: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + builder = new StringBuilder(curTextLen - 1); + if (selStart == selEnd && selStart > 0) { + builder.append(curText.subSequence(0, selStart - 1)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selStart = selStart - 1; + selEnd = selStart; + } else if (selStart != selEnd) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_DEL: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + builder = new StringBuilder(curTextLen - 1); + if (selStart == selEnd && selStart < curTextLen) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd + 1, curTextLen)); + selStart = selStart; + selEnd = selStart; + } else if (selStart != selEnd) { + builder.append(curText.subSequence(0, selStart)); + builder.append(curText.subSequence(selEnd, curTextLen)); + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_LEFT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selStart > 0) { + selStart = selStart - 1; + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_RIGHT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selEnd < curTextLen) { + selStart = selEnd + 1; + selEnd = selStart; + } else { + return; + } + break; + case KeyActionHandler.ACTION_MOVE_LEFTMOST: + selStart = 0; + selEnd = 0; + break; + case KeyActionHandler.ACTION_MOVE_RIGHTMOST: + if (curTextLen == 0) { + return; + } + selStart = curTextLen; + selEnd = curTextLen; + break; + case KeyActionHandler.ACTION_SELECT_LEFT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selStart > 0) { + selStart = selStart - 1; + } else { + return; + } + break; + case KeyActionHandler.ACTION_SELECT_RIGHT: + if (selStart == -1 || selEnd == -1 || curTextLen == 0) { + return; + } + if (selEnd < curTextLen) { + selEnd = selEnd + 1; + } else { + return; + } + break; + case KeyActionHandler.ACTION_SELECT_LEFTMOST: + selStart = 0; + break; + case KeyActionHandler.ACTION_SELECT_RIGHTMOST: + if (curTextLen == 0) { + return; + } + selEnd = curTextLen; + break; + default: + return; + } + + if (builder != null) { + Log.d(TAG, " new text: " + builder.toString() + " start=" + selStart + " end=" + selEnd); + } else { + Log.d(TAG, " new start=" + selStart + " end=" + selEnd); + } + + if (builder != null && builder.toString() != curText) { + Bundle args = new Bundle(); + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, + builder.toString()); + node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); + } + + if (selStart != -1 && selEnd != -1 && (builder == null || selStart != builder.length())) { + Bundle args = new Bundle(); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, selStart); + args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, selEnd); + node.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, args); + } + } + + @Override + public void postGlobalAction(int action) { + ControlService service = ControlService.getInstance(); + if (service != null) { + if (!service.performGlobalAction(action)) { + Log.e(TAG, "could not perform global action: " + action); + } + } + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/PointerEventOutput.java b/app/src/main/java/com/javispedro/vndroid/PointerEventOutput.java new file mode 100644 index 0000000..f380671 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/PointerEventOutput.java @@ -0,0 +1,101 @@ +package com.javispedro.vndroid; + +import android.accessibilityservice.AccessibilityService; +import android.accessibilityservice.GestureDescription; +import android.graphics.Path; +import android.os.SystemClock; +import android.util.Log; + +public class PointerEventOutput extends AccessibilityService.GestureResultCallback { + private final String TAG = PointerEventOutput.class.getSimpleName(); + + private boolean btnPressed = false; + + private void dispatchGesture(GestureDescription gesture) { + ControlService service = ControlService.getInstance(); + if (service != null) { + if (!service.dispatchGesture(gesture, this, null)) { + Log.w(TAG, "gesture not dispatched"); + } + } else { + Log.e(TAG, "no controlservice"); + } + } + + private long lastTime = 0; + private GestureDescription lastGesture = null; + private int lastX = -1, lastY = -1; + + private void pointerGesture(boolean cont, int x, int y, long curTime, boolean willContinue) { + Path path = new Path(); + long duration = 1; + + if (cont && lastGesture == null) { + Log.w(TAG, "continuing gesture but no previous data"); + } + + if (cont && lastGesture != null) { + assert lastX != -1 && lastY != -1; + path.moveTo(lastX, lastY); + duration = curTime - lastTime; + assert duration > 0; + } else { + path.moveTo(x, y); + } + + path.lineTo(x, y); + + GestureDescription.Builder builder = new GestureDescription.Builder(); + GestureDescription.StrokeDescription stroke; + if (cont && lastGesture != null) { + stroke = lastGesture.getStroke(0); + stroke = stroke.continueStroke(path, 0, duration, willContinue); + } else { + stroke = new GestureDescription.StrokeDescription(path, 0, duration, willContinue); + } + builder.addStroke(stroke); + GestureDescription gesture = builder.build(); + dispatchGesture(gesture); + + if (willContinue) { + lastGesture = gesture; + lastTime = curTime; + lastX = x; + lastY = y; + } else { + lastGesture = null; + lastTime = 0; + lastX = -1; + lastY = -1; + } + } + + public void postPointerEvent(byte buttonMask, int x, int y) { + final long curTime = SystemClock.uptimeMillis(); + + if ((buttonMask & 1) != 0) { + // Main button pressed + if (!btnPressed) { + pointerGesture(false, x, y, curTime, true); + btnPressed = true; + } else { + // Button moved while pressed + pointerGesture(true, x, y, curTime, true); + } + } else if (btnPressed) { + // Button was pressed but now released + pointerGesture(true, x, y, curTime, false); + + btnPressed = false; + } + } + + @Override + public void onCompleted(GestureDescription gestureDescription) { + } + + @Override + public void onCancelled(GestureDescription gestureDescription) { + Log.d(TAG, "gesture cancelled"); + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/RFBServer.java b/app/src/main/java/com/javispedro/vndroid/RFBServer.java new file mode 100644 index 0000000..f5af05c --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/RFBServer.java @@ -0,0 +1,98 @@ +package com.javispedro.vndroid; + +import android.graphics.PixelFormat; +import android.media.Image; +import android.support.annotation.Nullable; +import android.util.EventLog; + +import java.nio.ByteBuffer; + +public class RFBServer { + private static final String TAG = RFBServer.class.getSimpleName(); + + @Nullable + private Image lastImage = null; + + @Nullable + private EventCallback callback = null; + + public class ServerException extends RuntimeException { + public ServerException(String what) { + super(what); + } + } + + public interface EventCallback { + void onPointerEvent(int buttonMask, int x, int y); + void onKeyEvent(int key, boolean state); + } + + public RFBServer() { + if (!allocate()) { + throw new ServerException("failure to allocate()"); + } + } + + public void start() { + if (!init()) { + throw new ServerException("failure to init()"); + } + } + + public void stop() { + forgetLastImage(); + shutdown(); + } + + public void finalize() { + forgetLastImage(); + shutdown(); + deallocate(); + } + + public void setEventCallback(EventCallback c) { + callback = c; + set_event_callback(c); + } + + public void putImage(Image image) { + Image.Plane[] planes = image.getPlanes(); + + if (image.getFormat() != PixelFormat.RGBA_8888) { + String msg = "Unknown pixel format: " + image.getFormat(); + throw new UnsupportedOperationException(msg); + } + if (planes.length != 1) { + String msg = "Unknown number of planes: " + planes.length; + throw new UnsupportedOperationException(msg); + } + + Image.Plane plane = planes[0]; + + if (!put_image(image.getWidth(), image.getHeight(), plane.getBuffer(), plane.getPixelStride(), plane.getRowStride())) { + throw new ServerException("failed to put image"); + } + + forgetLastImage(); + lastImage = image; + } + + private void forgetLastImage() { + if (lastImage != null) { + lastImage.close(); + } + lastImage = null; + } + + private long nativeData = 0; + + private native boolean allocate(); + private native void deallocate(); + + private native boolean init(); + private native void shutdown(); + + private native void set_event_callback(EventCallback c); + + private native boolean put_image(int width, int height, ByteBuffer buffer, int pixel_stride, int row_stride); +} diff --git a/app/src/main/java/com/javispedro/vndroid/ScreenGrabber.java b/app/src/main/java/com/javispedro/vndroid/ScreenGrabber.java new file mode 100644 index 0000000..54d11bc --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ScreenGrabber.java @@ -0,0 +1,83 @@ +package com.javispedro.vndroid; + +import android.content.Context; +import android.content.ContextWrapper; +import android.hardware.display.VirtualDisplay; +import android.media.Image; +import android.media.ImageReader; +import android.support.annotation.Nullable; +import android.util.Log; + +public abstract class ScreenGrabber extends ContextWrapper { + private static final String TAG = ScreenGrabber.class.getSimpleName(); + + protected static final int MAX_IMAGES = 3; + + @Nullable protected ImageReader reader; + @Nullable protected VirtualDisplay display; + @Nullable protected Callback callback; + + public interface Callback { + void onImage(Image image); + } + + protected class VirtualDisplayCallback extends VirtualDisplay.Callback { + @Override + public void onPaused() { + Log.d(TAG, "onVirtualDisplayPaused"); + } + + @Override + public void onResumed() { + Log.d(TAG, "onVirtualDisplayResumed"); + } + + @Override + public void onStopped() { + Log.d(TAG, "onVirtualDisplayStopped"); + } + } + + protected class ImageReaderCallback implements ImageReader.OnImageAvailableListener { + @Override + public void onImageAvailable(ImageReader reader) { + if (callback != null) { + Image image = reader.acquireLatestImage(); + callback.onImage(image); + } + } + } + + protected ScreenGrabber(Context context) { + super(context); + } + + public abstract void start(); + + public void stop() { + if (display != null) { + display.release(); + display = null; + } + if (reader != null) { + reader.close(); + reader = null; + } + } + + public void setCallback(Callback c) { + callback = c; + } + + public int scaleInputX(int x) { + return x; + } + + public int scaleInputY(int y) { + return y; + } + + public boolean hasSizeChanged() { return false; } + + public void updateScreenSize() { } +} diff --git a/app/src/main/java/com/javispedro/vndroid/ScreenMirrorGrabber.java b/app/src/main/java/com/javispedro/vndroid/ScreenMirrorGrabber.java new file mode 100644 index 0000000..9f78b3c --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ScreenMirrorGrabber.java @@ -0,0 +1,110 @@ +package com.javispedro.vndroid; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.hardware.display.DisplayManager; +import android.media.ImageReader; +import android.media.projection.MediaProjection; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; + +public class ScreenMirrorGrabber extends ScreenGrabber { + private static final String TAG = ScreenMirrorGrabber.class.getSimpleName(); + + protected final MediaProjection projection; + protected final Display realDisplay; + + protected final DisplayMetrics realDisplayMetrics; + + private float scale = 0.5f; + + public ScreenMirrorGrabber(Context context, @NonNull MediaProjection proj, @NonNull Display display) { + super(context); + projection = proj; + realDisplay = display; + realDisplayMetrics = new DisplayMetrics(); + } + + private void initDisplay() { + realDisplay.getRealMetrics(realDisplayMetrics); + + Log.d(TAG, "real display size: " + realDisplayMetrics.widthPixels + "x" + realDisplayMetrics.heightPixels); + + int width = Math.round(realDisplayMetrics.widthPixels * scale); + int height = Math.round(realDisplayMetrics.heightPixels * scale); + int dpi = realDisplayMetrics.densityDpi; + + Log.d(TAG, "starting mirror display with size: " + width + "x" + height + " dpi: " + dpi); + + reader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, MAX_IMAGES); + reader.setOnImageAvailableListener(new ImageReaderCallback(), null); + + display = projection.createVirtualDisplay("vndroid", + width, height, dpi, + DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, + reader.getSurface(), + new VirtualDisplayCallback(), null); + } + + @Override + public void start() { + if (reader != null || display != null) { + Log.w(TAG, "already started"); + return; + } + + initDisplay(); + } + + @Override + public void stop() { + super.stop(); + projection.stop(); + } + + @Override + public int scaleInputX(int x) { + return Math.round(x / scale); + } + + @Override + public int scaleInputY(int y) { + return Math.round(y / scale); + } + + @Override + public boolean hasSizeChanged() { + DisplayMetrics metrics = new DisplayMetrics(); + realDisplay.getRealMetrics(metrics); + return metrics.widthPixels != realDisplayMetrics.widthPixels || metrics.heightPixels != realDisplayMetrics.heightPixels; + } + + @Override + public void updateScreenSize() { + final ImageReader oldReader = reader; + reader = null; + + if (display != null) { + display.release(); + display = null; + } + + initDisplay(); + + Log.d(TAG, "new buffers set"); + + // Delay destruction of old image buffers to minimize multithread issues... + if (oldReader != null) { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + Log.d(TAG, "old buffers closed"); + oldReader.close(); + } + }, 1000); + } + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/ScreenVirtualGrabber.java b/app/src/main/java/com/javispedro/vndroid/ScreenVirtualGrabber.java new file mode 100644 index 0000000..5eef75d --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ScreenVirtualGrabber.java @@ -0,0 +1,38 @@ +package com.javispedro.vndroid; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.hardware.display.DisplayManager; +import android.media.ImageReader; +import android.util.Log; + +public class ScreenVirtualGrabber extends ScreenGrabber { + private static final String TAG = ScreenVirtualGrabber.class.getSimpleName(); + + public ScreenVirtualGrabber(Context context) { + super(context); + } + + @Override + public void start() { + if (reader != null || display != null) { + Log.w(TAG, "already started"); + return; + } + + int width = 1024; + int height = 768; + int dpi = 96; + + Log.d(TAG, "starting virtual display with width " + width + " height: " + height + " dpi: " + dpi); + + reader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, MAX_IMAGES); + reader.setOnImageAvailableListener(new ImageReaderCallback(), null); + + DisplayManager manager = getSystemService(DisplayManager.class); + display = manager.createVirtualDisplay("vndroid", + width, height, dpi, reader.getSurface(), + DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, + new VirtualDisplayCallback(), null); + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/ServerRunningNotification.java b/app/src/main/java/com/javispedro/vndroid/ServerRunningNotification.java new file mode 100644 index 0000000..6fcf8ab --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ServerRunningNotification.java @@ -0,0 +1,108 @@ +package com.javispedro.vndroid; + +import android.annotation.TargetApi; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.support.v4.app.NotificationCompat; + +/** + * Helper class for showing and canceling server running + * notifications. + *

+ * This class makes heavy use of the {@link NotificationCompat.Builder} helper + * class to create notifications in a backward-compatible way. + */ +public class ServerRunningNotification { + /** + * The unique identifier for this type of notification. + */ + private static final String NOTIFICATION_TAG = "ServerRunning"; + + private static final String NOTIFICATION_CHANNEL = NOTIFICATION_TAG; + + public static NotificationChannel createNotificationChannel(final Context context) { + final Resources res = context.getResources(); + NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL, + res.getString(R.string.server_running_notification_channel), + NotificationManager.IMPORTANCE_NONE); + channel.setShowBadge(false); + return channel; + } + + public static void initNotificationChannel(final Context context) { + NotificationManager manager = context.getSystemService(NotificationManager.class); + manager.createNotificationChannel(createNotificationChannel(context)); + } + + public static Notification build(final Context context) { + final Resources res = context.getResources(); + + final String title = res.getString(R.string.server_running_notification_title); + + final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL) + + // Set appropriate defaults for the notification light, sound, + // and vibration. + .setDefaults(Notification.DEFAULT_ALL) + .setCategory(Notification.CATEGORY_SERVICE) + .setOngoing(true) + + // Set required fields, including the small icon, the + // notification title, and text. + .setSmallIcon(R.drawable.ic_stat_server_running) + .setContentTitle(title) + //.setContentText(text) + + // All fields below this line are optional. + + // Use a default priority (recognized on devices running Android + // 4.1 or later) + .setPriority(NotificationCompat.PRIORITY_MIN) + + // Set ticker text (preview) information for this notification. + //.setTicker(ticker) + + // If this notification relates to a past or upcoming event, you + // should set the relevant time information using the setWhen + // method below. If this call is omitted, the notification's + // timestamp will by set to the time at which it was shown. + // TODO: Call setWhen if this notification relates to a past or + // upcoming event. The sole argument to this method should be + // the notification timestamp in milliseconds. + //.setWhen(...) + + // Set the pending intent to be initiated when the user touches + // the notification. + .setContentIntent( + PendingIntent.getActivity( + context, + 0, + new Intent(context, SetupActivity.class), + PendingIntent.FLAG_UPDATE_CURRENT)) + + // Example additional actions for this notification. These will + // only show on devices running Android 4.1 or later, so you + // should ensure that the activity in this notification's + // content intent provides access to the same actions in + // another way. + .addAction( + R.drawable.ic_action_stop_screen_sharing, + res.getString(R.string.action_stop), + PendingIntent.getForegroundService( + context, + 0, + new Intent(context, ServerService.class).setAction(ServerService.ACTION_STOP), + PendingIntent.FLAG_UPDATE_CURRENT)); + + return builder.build(); + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/ServerService.java b/app/src/main/java/com/javispedro/vndroid/ServerService.java new file mode 100644 index 0000000..bf72d21 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/ServerService.java @@ -0,0 +1,175 @@ +package com.javispedro.vndroid; + +import android.app.Activity; +import android.app.Notification; +import android.app.Service; +import android.content.Intent; +import android.content.res.Configuration; +import android.media.Image; +import android.media.projection.MediaProjection; +import android.media.projection.MediaProjectionManager; +import android.os.IBinder; +import android.util.Log; +import android.view.WindowManager; +import android.widget.Toast; + +import com.javispedro.vndroid.keymaps.AndroidKeyHandler; +import com.javispedro.vndroid.keymaps.SpanishKeyHandler; + +public class ServerService extends Service { + private static final String TAG = ServerService.class.getSimpleName(); + public static final String ACTION_START = "ACTION_START"; + public static final String ACTION_STOP = "ACTION_STOP"; + public static final String ACTION_NOTIFY_MEDIA_PROJECTION_RESULT = "ACTION_NOTIFY_MEDIA_PROJECTION_RESULT"; + + private ScreenGrabber screenGrabber; + private RFBServer rfbServer; + private PointerEventOutput pointerOut; + private KeyEventOutput keyOut; + + public ServerService() { + } + + @Override + public void onCreate() { + ServerRunningNotification.initNotificationChannel(this); + System.loadLibrary("native-lib"); + } + + @Override + public IBinder onBind(Intent intent) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent != null) { + switch (intent.getAction()) { + case ACTION_START: + start(); + break; + case ACTION_STOP: + stop(); + break; + case ACTION_NOTIFY_MEDIA_PROJECTION_RESULT: + notifyMediaProjectionResult(intent.getIntExtra("resultCode", Activity.RESULT_CANCELED), + (Intent) intent.getParcelableExtra("resultData")); + break; + } + } + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (screenGrabber != null && screenGrabber.hasSizeChanged()) { + Log.d(TAG, "screen size has changed"); + screenGrabber.updateScreenSize(); + } + } + + protected class ScreenGrabberCallback implements ScreenGrabber.Callback { + @Override + public void onImage(Image image) { + if (rfbServer != null) { + rfbServer.putImage(image); + } else { + image.close(); + } + } + } + + protected class EventCallback implements RFBServer.EventCallback { + @Override + public void onPointerEvent(int buttonMask, int x, int y) { + try { + x = screenGrabber.scaleInputX(x); + y = screenGrabber.scaleInputY(y); + pointerOut.postPointerEvent((byte) buttonMask, x, y); + } catch (Exception e) { + Log.e(TAG, "Exception on pointer EventCallback: " + e.toString()); + e.printStackTrace(); + // Need to supress the exception, otherwise we'll crash JNI + } + } + + @Override + public void onKeyEvent(int key, boolean state) { + try { + keyOut.postKeyEvent(key, state); + } catch (Exception e) { + Log.e(TAG, "Exception on key EventCallback: " + e.toString()); + e.printStackTrace(); + } + } + } + + protected void start() { + if (rfbServer != null) { + Log.w(TAG, "cannot start, already started"); + return; + } + + Log.d(TAG, "starting"); + + if (!ControlService.isServiceStarted()) { + Toast toast = Toast.makeText(this, R.string.toast_no_input_service, Toast.LENGTH_SHORT); + toast.show(); + } + + pointerOut = new PointerEventOutput(); + keyOut = new KeyEventOutput(); + keyOut.addHandler(new AndroidKeyHandler()); + keyOut.addHandler(new SpanishKeyHandler()); + + + if (screenGrabber == null) { + screenGrabber = new ScreenVirtualGrabber(this); + } + + rfbServer = new RFBServer(); + rfbServer.setEventCallback(new EventCallback()); + rfbServer.start(); + + screenGrabber.setCallback(new ScreenGrabberCallback()); + screenGrabber.start(); + + Notification notification = ServerRunningNotification.build(this); + startForeground(1, notification); + } + + protected void stop() { + Log.d(TAG, "stopping"); + + if (rfbServer != null) { + rfbServer.stop(); + rfbServer = null; + } + if (screenGrabber != null) { + screenGrabber.stop(); + screenGrabber = null; + } + if (pointerOut != null) { + pointerOut = null; + } + if (keyOut != null) { + keyOut = null; + } + + stopForeground(true); + stopSelf(); + } + + protected void notifyMediaProjectionResult(int resultCode, Intent data) { + if (screenGrabber != null) { + Log.w(TAG, "already have an screen grabber"); + } + MediaProjectionManager manager = getSystemService(MediaProjectionManager.class); + MediaProjection projection = manager.getMediaProjection(resultCode, data); + + WindowManager wm = getSystemService(WindowManager.class); + + screenGrabber = new ScreenMirrorGrabber(this, projection, wm.getDefaultDisplay()); + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/SetupActivity.java b/app/src/main/java/com/javispedro/vndroid/SetupActivity.java new file mode 100644 index 0000000..123bbe7 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/SetupActivity.java @@ -0,0 +1,78 @@ +package com.javispedro.vndroid; + +import android.app.Activity; +import android.content.Intent; +import android.media.projection.MediaProjectionManager; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; + +public class SetupActivity extends AppCompatActivity { + private static String TAG = SetupActivity.class.getSimpleName(); + + private static final int REQUEST_MEDIA_PROJECTION = 1; + + private boolean mirror = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_setup); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + switch (requestCode) { + case REQUEST_MEDIA_PROJECTION: + if (resultCode != Activity.RESULT_OK) { + Log.w(TAG, "User cancelled media projection"); + return; + } + + notifyMediaProjectionResult(resultCode, data); + startServer(); + + break; + } + } + + private void startServer() + { + Intent intent = new Intent(this, ServerService.class); + intent.setAction(ServerService.ACTION_START); + startService(intent); + } + + private void stopServer() + { + Intent intent = new Intent(this, ServerService.class); + intent.setAction(ServerService.ACTION_STOP); + startService(intent); + } + + private void notifyMediaProjectionResult(int resultCode, Intent resultData) + { + Intent intent = new Intent(this, ServerService.class); + intent.setAction(ServerService.ACTION_NOTIFY_MEDIA_PROJECTION_RESULT); + intent.putExtra("resultCode", resultCode); + intent.putExtra("resultData", resultData); + startService(intent); + } + + public void onStartClick(View view) { + Log.d(TAG, "onStartClick"); + if (mirror) { + MediaProjectionManager manager = getSystemService(MediaProjectionManager.class); + startActivityForResult(manager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); + } else { + startServer(); + } + } + + public void onStopClick(View view) { + Log.d(TAG, "onStopClick"); + stopServer(); + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/keymaps/AndroidKeyHandler.java b/app/src/main/java/com/javispedro/vndroid/keymaps/AndroidKeyHandler.java new file mode 100644 index 0000000..b0ac08e --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/keymaps/AndroidKeyHandler.java @@ -0,0 +1,69 @@ +package com.javispedro.vndroid.keymaps; + +import android.accessibilityservice.AccessibilityService; + +public class AndroidKeyHandler extends KeyHandler { + private boolean shiftPressed = false; + + @Override + public boolean keyDown(int key) { + switch (key) { + case KeySyms.Key_Shift_L: + case KeySyms.Key_Shift_R: + shiftPressed = true; + return false; + case KeySyms.Key_Escape: + action.postGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); + return true; + case KeySyms.Key_F1: + action.postGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME); + return true; + case KeySyms.Key_BackSpace: + action.postLocalAction(KeyActionHandler.ACTION_BACKSPACE); + return true; + case KeySyms.Key_Delete: + action.postLocalAction(KeyActionHandler.ACTION_DEL); + return true; + case KeySyms.Key_Left: + if (shiftPressed) { + action.postLocalAction(KeyActionHandler.ACTION_SELECT_LEFT); + } else { + action.postLocalAction(KeyActionHandler.ACTION_MOVE_LEFT); + } + return true; + case KeySyms.Key_Right: + if (shiftPressed) { + action.postLocalAction(KeyActionHandler.ACTION_SELECT_RIGHT); + } else { + action.postLocalAction(KeyActionHandler.ACTION_MOVE_RIGHT); + } + return true; + case KeySyms.Key_Home: + if (shiftPressed) { + action.postLocalAction(KeyActionHandler.ACTION_SELECT_LEFTMOST); + } else { + action.postLocalAction(KeyActionHandler.ACTION_MOVE_LEFTMOST); + } + return true; + case KeySyms.Key_End: + if (shiftPressed) { + action.postLocalAction(KeyActionHandler.ACTION_SELECT_RIGHTMOST); + } else { + action.postLocalAction(KeyActionHandler.ACTION_MOVE_RIGHTMOST); + } + return true; + } + return false; + } + + @Override + public boolean keyUp(int key) { + switch (key) { + case KeySyms.Key_Shift_L: + case KeySyms.Key_Shift_R: + shiftPressed = false; + return false; + } + return false; + } +} diff --git a/app/src/main/java/com/javispedro/vndroid/keymaps/KeyActionHandler.java b/app/src/main/java/com/javispedro/vndroid/keymaps/KeyActionHandler.java new file mode 100644 index 0000000..41fd510 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/keymaps/KeyActionHandler.java @@ -0,0 +1,20 @@ +package com.javispedro.vndroid.keymaps; + +public interface KeyActionHandler { + int ACTION_NONE = 0; + int ACTION_BACKSPACE = 1; + int ACTION_DEL = 2; + int ACTION_MOVE_LEFT = 10; + int ACTION_MOVE_RIGHT = 11; + int ACTION_MOVE_LEFTMOST = 12; + int ACTION_MOVE_RIGHTMOST = 13; + int ACTION_SELECT_LEFT = 20; + int ACTION_SELECT_RIGHT = 21; + int ACTION_SELECT_LEFTMOST = 22; + int ACTION_SELECT_RIGHTMOST = 23; + + void postText(CharSequence text); + void postChar(char c); + void postLocalAction(int action); + void postGlobalAction(int action); +} diff --git a/app/src/main/java/com/javispedro/vndroid/keymaps/KeyHandler.java b/app/src/main/java/com/javispedro/vndroid/keymaps/KeyHandler.java new file mode 100644 index 0000000..5f64f34 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/keymaps/KeyHandler.java @@ -0,0 +1,12 @@ +package com.javispedro.vndroid.keymaps; + +public abstract class KeyHandler { + protected KeyActionHandler action; + + public void setActionHandler(KeyActionHandler handler) { + action = handler; + } + + public abstract boolean keyDown(int key); + public abstract boolean keyUp(int key); +} diff --git a/app/src/main/java/com/javispedro/vndroid/keymaps/KeySyms.java b/app/src/main/java/com/javispedro/vndroid/keymaps/KeySyms.java new file mode 100644 index 0000000..033cd32 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/keymaps/KeySyms.java @@ -0,0 +1,1321 @@ +package com.javispedro.vndroid.keymaps; + +public class KeySyms { + public static final int Key_BackSpace = 0xFF08 /* back space, back char */; + public static final int Key_Tab = 0xFF09; + public static final int Key_Linefeed = 0xFF0A /* Linefeed, LF */; + public static final int Key_Clear = 0xFF0B; + public static final int Key_Return = 0xFF0D /* Return, enter */; + public static final int Key_Pause = 0xFF13 /* Pause, hold */; + public static final int Key_Scroll_Lock = 0xFF14; + public static final int Key_Sys_Req = 0xFF15; + public static final int Key_Escape = 0xFF1B; + public static final int Key_Delete = 0xFFFF /* Delete, rubout */; + public static final int Key_Multi_key = 0xFF20 /* Multi-key character compose */; + public static final int Key_SingleCandidate = 0xFF3C; + public static final int Key_MultipleCandidate = 0xFF3D; + public static final int Key_PreviousCandidate = 0xFF3E; + public static final int Key_Kanji = 0xFF21 /* Kanji, Kanji convert */; + public static final int Key_Muhenkan = 0xFF22 /* Cancel Conversion */; + public static final int Key_Henkan_Mode = 0xFF23 /* Start/Stop Conversion */; + public static final int Key_Henkan = 0xFF23 /* Alias for Henkan_Mode */; + public static final int Key_Romaji = 0xFF24 /* to Romaji */; + public static final int Key_Hiragana = 0xFF25 /* to Hiragana */; + public static final int Key_Katakana = 0xFF26 /* to Katakana */; + public static final int Key_Hiragana_Katakana = 0xFF27 /* Hiragana/Katakana toggle */; + public static final int Key_Zenkaku = 0xFF28 /* to Zenkaku */; + public static final int Key_Hankaku = 0xFF29 /* to Hankaku */; + public static final int Key_Zenkaku_Hankaku = 0xFF2A /* Zenkaku/Hankaku toggle */; + public static final int Key_Touroku = 0xFF2B /* Add to Dictionary */; + public static final int Key_Massyo = 0xFF2C /* Delete from Dictionary */; + public static final int Key_Kana_Lock = 0xFF2D /* Kana Lock */; + public static final int Key_Kana_Shift = 0xFF2E /* Kana Shift */; + public static final int Key_Eisu_Shift = 0xFF2F /* Alphanumeric Shift */; + public static final int Key_Eisu_toggle = 0xFF30 /* Alphanumeric toggle */; + public static final int Key_Zen_Koho = 0xFF3D /* Multiple/All Candidate(s) */; + public static final int Key_Mae_Koho = 0xFF3E /* Previous Candidate */; + public static final int Key_Home = 0xFF50; + public static final int Key_Left = 0xFF51 /* Move left, left arrow */; + public static final int Key_Up = 0xFF52 /* Move up, up arrow */; + public static final int Key_Right = 0xFF53 /* Move right, right arrow */; + public static final int Key_Down = 0xFF54 /* Move down, down arrow */; + public static final int Key_Prior = 0xFF55 /* Prior, previous */; + public static final int Key_Page_Up = 0xFF55; + public static final int Key_Next = 0xFF56 /* Next */; + public static final int Key_Page_Down = 0xFF56; + public static final int Key_End = 0xFF57 /* EOL */; + public static final int Key_Begin = 0xFF58 /* BOL */; + public static final int Key_Select = 0xFF60 /* Select, mark */; + public static final int Key_Print = 0xFF61; + public static final int Key_Execute = 0xFF62 /* Execute, run, do */; + public static final int Key_Insert = 0xFF63 /* Insert, insert here */; + public static final int Key_Undo = 0xFF65 /* Undo, oops */; + public static final int Key_Redo = 0xFF66 /* redo, again */; + public static final int Key_Menu = 0xFF67; + public static final int Key_Find = 0xFF68 /* Find, search */; + public static final int Key_Cancel = 0xFF69 /* Cancel, stop, abort, exit */; + public static final int Key_Help = 0xFF6A /* Help */; + public static final int Key_Break = 0xFF6B; + public static final int Key_Mode_switch = 0xFF7E /* Character set switch */; + public static final int Key_script_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_Num_Lock = 0xFF7F; + public static final int Key_KP_Space = 0xFF80 /* space */; + public static final int Key_KP_Tab = 0xFF89; + public static final int Key_KP_Enter = 0xFF8D /* enter */; + public static final int Key_KP_F1 = 0xFF91 /* PF1, KP_A, ... */; + public static final int Key_KP_F2 = 0xFF92; + public static final int Key_KP_F3 = 0xFF93; + public static final int Key_KP_F4 = 0xFF94; + public static final int Key_KP_Home = 0xFF95; + public static final int Key_KP_Left = 0xFF96; + public static final int Key_KP_Up = 0xFF97; + public static final int Key_KP_Right = 0xFF98; + public static final int Key_KP_Down = 0xFF99; + public static final int Key_KP_Prior = 0xFF9A; + public static final int Key_KP_Page_Up = 0xFF9A; + public static final int Key_KP_Next = 0xFF9B; + public static final int Key_KP_Page_Down = 0xFF9B; + public static final int Key_KP_End = 0xFF9C; + public static final int Key_KP_Begin = 0xFF9D; + public static final int Key_KP_Insert = 0xFF9E; + public static final int Key_KP_Delete = 0xFF9F; + public static final int Key_KP_Equal = 0xFFBD /* equals */; + public static final int Key_KP_Multiply = 0xFFAA; + public static final int Key_KP_Add = 0xFFAB; + public static final int Key_KP_Separator = 0xFFAC /* separator, often comma */; + public static final int Key_KP_Subtract = 0xFFAD; + public static final int Key_KP_Decimal = 0xFFAE; + public static final int Key_KP_Divide = 0xFFAF; + public static final int Key_KP_0 = 0xFFB0; + public static final int Key_KP_1 = 0xFFB1; + public static final int Key_KP_2 = 0xFFB2; + public static final int Key_KP_3 = 0xFFB3; + public static final int Key_KP_4 = 0xFFB4; + public static final int Key_KP_5 = 0xFFB5; + public static final int Key_KP_6 = 0xFFB6; + public static final int Key_KP_7 = 0xFFB7; + public static final int Key_KP_8 = 0xFFB8; + public static final int Key_KP_9 = 0xFFB9; + public static final int Key_F1 = 0xFFBE; + public static final int Key_F2 = 0xFFBF; + public static final int Key_F3 = 0xFFC0; + public static final int Key_F4 = 0xFFC1; + public static final int Key_F5 = 0xFFC2; + public static final int Key_F6 = 0xFFC3; + public static final int Key_F7 = 0xFFC4; + public static final int Key_F8 = 0xFFC5; + public static final int Key_F9 = 0xFFC6; + public static final int Key_F10 = 0xFFC7; + public static final int Key_F11 = 0xFFC8; + public static final int Key_L1 = 0xFFC8; + public static final int Key_F12 = 0xFFC9; + public static final int Key_L2 = 0xFFC9; + public static final int Key_F13 = 0xFFCA; + public static final int Key_L3 = 0xFFCA; + public static final int Key_F14 = 0xFFCB; + public static final int Key_L4 = 0xFFCB; + public static final int Key_F15 = 0xFFCC; + public static final int Key_L5 = 0xFFCC; + public static final int Key_F16 = 0xFFCD; + public static final int Key_L6 = 0xFFCD; + public static final int Key_F17 = 0xFFCE; + public static final int Key_L7 = 0xFFCE; + public static final int Key_F18 = 0xFFCF; + public static final int Key_L8 = 0xFFCF; + public static final int Key_F19 = 0xFFD0; + public static final int Key_L9 = 0xFFD0; + public static final int Key_F20 = 0xFFD1; + public static final int Key_L10 = 0xFFD1; + public static final int Key_F21 = 0xFFD2; + public static final int Key_R1 = 0xFFD2; + public static final int Key_F22 = 0xFFD3; + public static final int Key_R2 = 0xFFD3; + public static final int Key_F23 = 0xFFD4; + public static final int Key_R3 = 0xFFD4; + public static final int Key_F24 = 0xFFD5; + public static final int Key_R4 = 0xFFD5; + public static final int Key_F25 = 0xFFD6; + public static final int Key_R5 = 0xFFD6; + public static final int Key_F26 = 0xFFD7; + public static final int Key_R6 = 0xFFD7; + public static final int Key_F27 = 0xFFD8; + public static final int Key_R7 = 0xFFD8; + public static final int Key_F28 = 0xFFD9; + public static final int Key_R8 = 0xFFD9; + public static final int Key_F29 = 0xFFDA; + public static final int Key_R9 = 0xFFDA; + public static final int Key_F30 = 0xFFDB; + public static final int Key_R10 = 0xFFDB; + public static final int Key_F31 = 0xFFDC; + public static final int Key_R11 = 0xFFDC; + public static final int Key_F32 = 0xFFDD; + public static final int Key_R12 = 0xFFDD; + public static final int Key_F33 = 0xFFDE; + public static final int Key_R13 = 0xFFDE; + public static final int Key_F34 = 0xFFDF; + public static final int Key_R14 = 0xFFDF; + public static final int Key_F35 = 0xFFE0; + public static final int Key_R15 = 0xFFE0; + public static final int Key_Shift_L = 0xFFE1 /* Left shift */; + public static final int Key_Shift_R = 0xFFE2 /* Right shift */; + public static final int Key_Control_L = 0xFFE3 /* Left control */; + public static final int Key_Control_R = 0xFFE4 /* Right control */; + public static final int Key_Caps_Lock = 0xFFE5 /* Caps lock */; + public static final int Key_Shift_Lock = 0xFFE6 /* Shift lock */; + public static final int Key_Meta_L = 0xFFE7 /* Left meta */; + public static final int Key_Meta_R = 0xFFE8 /* Right meta */; + public static final int Key_Alt_L = 0xFFE9 /* Left alt */; + public static final int Key_Alt_R = 0xFFEA /* Right alt */; + public static final int Key_Super_L = 0xFFEB /* Left super */; + public static final int Key_Super_R = 0xFFEC /* Right super */; + public static final int Key_Hyper_L = 0xFFED /* Left hyper */; + public static final int Key_Hyper_R = 0xFFEE /* Right hyper */; + public static final int Key_ISO_Lock = 0xFE01; + public static final int Key_ISO_Level2_Latch = 0xFE02; + public static final int Key_ISO_Level3_Shift = 0xFE03; + public static final int Key_ISO_Level3_Latch = 0xFE04; + public static final int Key_ISO_Level3_Lock = 0xFE05; + public static final int Key_ISO_Group_Shift = 0xFF7E /* Alias for mode_switch */; + public static final int Key_ISO_Group_Latch = 0xFE06; + public static final int Key_ISO_Group_Lock = 0xFE07; + public static final int Key_ISO_Next_Group = 0xFE08; + public static final int Key_ISO_Next_Group_Lock = 0xFE09; + public static final int Key_ISO_Prev_Group = 0xFE0A; + public static final int Key_ISO_Prev_Group_Lock = 0xFE0B; + public static final int Key_ISO_First_Group = 0xFE0C; + public static final int Key_ISO_First_Group_Lock = 0xFE0D; + public static final int Key_ISO_Last_Group = 0xFE0E; + public static final int Key_ISO_Last_Group_Lock = 0xFE0F; + public static final int Key_ISO_Left_Tab = 0xFE20; + public static final int Key_ISO_Move_Line_Up = 0xFE21; + public static final int Key_ISO_Move_Line_Down = 0xFE22; + public static final int Key_ISO_Partial_Line_Up = 0xFE23; + public static final int Key_ISO_Partial_Line_Down = 0xFE24; + public static final int Key_ISO_Partial_Space_Left = 0xFE25; + public static final int Key_ISO_Partial_Space_Right = 0xFE26; + public static final int Key_ISO_Set_Margin_Left = 0xFE27; + public static final int Key_ISO_Set_Margin_Right = 0xFE28; + public static final int Key_ISO_Release_Margin_Left = 0xFE29; + public static final int Key_ISO_Release_Margin_Right = 0xFE2A; + public static final int Key_ISO_Release_Both_Margins = 0xFE2B; + public static final int Key_ISO_Fast_Cursor_Left = 0xFE2C; + public static final int Key_ISO_Fast_Cursor_Right = 0xFE2D; + public static final int Key_ISO_Fast_Cursor_Up = 0xFE2E; + public static final int Key_ISO_Fast_Cursor_Down = 0xFE2F; + public static final int Key_ISO_Continuous_Underline = 0xFE30; + public static final int Key_ISO_Discontinuous_Underline = 0xFE31; + public static final int Key_ISO_Emphasize = 0xFE32; + public static final int Key_ISO_Center_Object = 0xFE33; + public static final int Key_ISO_Enter = 0xFE34; + public static final int Key_dead_grave = 0xFE50; + public static final int Key_dead_acute = 0xFE51; + public static final int Key_dead_circumflex = 0xFE52; + public static final int Key_dead_tilde = 0xFE53; + public static final int Key_dead_macron = 0xFE54; + public static final int Key_dead_breve = 0xFE55; + public static final int Key_dead_abovedot = 0xFE56; + public static final int Key_dead_diaeresis = 0xFE57; + public static final int Key_dead_abovering = 0xFE58; + public static final int Key_dead_doubleacute = 0xFE59; + public static final int Key_dead_caron = 0xFE5A; + public static final int Key_dead_cedilla = 0xFE5B; + public static final int Key_dead_ogonek = 0xFE5C; + public static final int Key_dead_iota = 0xFE5D; + public static final int Key_dead_voiced_sound = 0xFE5E; + public static final int Key_dead_semivoiced_sound = 0xFE5F; + public static final int Key_dead_belowdot = 0xFE60; + public static final int Key_First_Virtual_Screen = 0xFED0; + public static final int Key_Prev_Virtual_Screen = 0xFED1; + public static final int Key_Next_Virtual_Screen = 0xFED2; + public static final int Key_Last_Virtual_Screen = 0xFED4; + public static final int Key_Terminate_Server = 0xFED5; + public static final int Key_AccessX_Enable = 0xFE70; + public static final int Key_AccessX_Feedback_Enable = 0xFE71; + public static final int Key_RepeatKeys_Enable = 0xFE72; + public static final int Key_SlowKeys_Enable = 0xFE73; + public static final int Key_BounceKeys_Enable = 0xFE74; + public static final int Key_StickyKeys_Enable = 0xFE75; + public static final int Key_MouseKeys_Enable = 0xFE76; + public static final int Key_MouseKeys_Accel_Enable = 0xFE77; + public static final int Key_Overlay1_Enable = 0xFE78; + public static final int Key_Overlay2_Enable = 0xFE79; + public static final int Key_AudibleBell_Enable = 0xFE7A; + public static final int Key_Pointer_Left = 0xFEE0; + public static final int Key_Pointer_Right = 0xFEE1; + public static final int Key_Pointer_Up = 0xFEE2; + public static final int Key_Pointer_Down = 0xFEE3; + public static final int Key_Pointer_UpLeft = 0xFEE4; + public static final int Key_Pointer_UpRight = 0xFEE5; + public static final int Key_Pointer_DownLeft = 0xFEE6; + public static final int Key_Pointer_DownRight = 0xFEE7; + public static final int Key_Pointer_Button_Dflt = 0xFEE8; + public static final int Key_Pointer_Button1 = 0xFEE9; + public static final int Key_Pointer_Button2 = 0xFEEA; + public static final int Key_Pointer_Button3 = 0xFEEB; + public static final int Key_Pointer_Button4 = 0xFEEC; + public static final int Key_Pointer_Button5 = 0xFEED; + public static final int Key_Pointer_DblClick_Dflt = 0xFEEE; + public static final int Key_Pointer_DblClick1 = 0xFEEF; + public static final int Key_Pointer_DblClick2 = 0xFEF0; + public static final int Key_Pointer_DblClick3 = 0xFEF1; + public static final int Key_Pointer_DblClick4 = 0xFEF2; + public static final int Key_Pointer_DblClick5 = 0xFEF3; + public static final int Key_Pointer_Drag_Dflt = 0xFEF4; + public static final int Key_Pointer_Drag1 = 0xFEF5; + public static final int Key_Pointer_Drag2 = 0xFEF6; + public static final int Key_Pointer_Drag3 = 0xFEF7; + public static final int Key_Pointer_Drag4 = 0xFEF8; + public static final int Key_Pointer_Drag5 = 0xFEFD; + public static final int Key_Pointer_EnableKeys = 0xFEF9; + public static final int Key_Pointer_Accelerate = 0xFEFA; + public static final int Key_Pointer_DfltBtnNext = 0xFEFB; + public static final int Key_Pointer_DfltBtnPrev = 0xFEFC; + public static final int Key_3270_Duplicate = 0xFD01; + public static final int Key_3270_FieldMark = 0xFD02; + public static final int Key_3270_Right2 = 0xFD03; + public static final int Key_3270_Left2 = 0xFD04; + public static final int Key_3270_BackTab = 0xFD05; + public static final int Key_3270_EraseEOF = 0xFD06; + public static final int Key_3270_EraseInput = 0xFD07; + public static final int Key_3270_Reset = 0xFD08; + public static final int Key_3270_Quit = 0xFD09; + public static final int Key_3270_PA1 = 0xFD0A; + public static final int Key_3270_PA2 = 0xFD0B; + public static final int Key_3270_PA3 = 0xFD0C; + public static final int Key_3270_Test = 0xFD0D; + public static final int Key_3270_Attn = 0xFD0E; + public static final int Key_3270_CursorBlink = 0xFD0F; + public static final int Key_3270_AltCursor = 0xFD10; + public static final int Key_3270_KeyClick = 0xFD11; + public static final int Key_3270_Jump = 0xFD12; + public static final int Key_3270_Ident = 0xFD13; + public static final int Key_3270_Rule = 0xFD14; + public static final int Key_3270_Copy = 0xFD15; + public static final int Key_3270_Play = 0xFD16; + public static final int Key_3270_Setup = 0xFD17; + public static final int Key_3270_Record = 0xFD18; + public static final int Key_3270_ChangeScreen = 0xFD19; + public static final int Key_3270_DeleteWord = 0xFD1A; + public static final int Key_3270_ExSelect = 0xFD1B; + public static final int Key_3270_CursorSelect = 0xFD1C; + public static final int Key_3270_PrintScreen = 0xFD1D; + public static final int Key_3270_Enter = 0xFD1E; + public static final int Key_space = 0x020; + public static final int Key_exclam = 0x021; + public static final int Key_quotedbl = 0x022; + public static final int Key_numbersign = 0x023; + public static final int Key_dollar = 0x024; + public static final int Key_percent = 0x025; + public static final int Key_ampersand = 0x026; + public static final int Key_apostrophe = 0x027; + public static final int Key_quoteright = 0x027 /* deprecated */; + public static final int Key_parenleft = 0x028; + public static final int Key_parenright = 0x029; + public static final int Key_asterisk = 0x02a; + public static final int Key_plus = 0x02b; + public static final int Key_comma = 0x02c; + public static final int Key_minus = 0x02d; + public static final int Key_period = 0x02e; + public static final int Key_slash = 0x02f; + public static final int Key_0 = 0x030; + public static final int Key_1 = 0x031; + public static final int Key_2 = 0x032; + public static final int Key_3 = 0x033; + public static final int Key_4 = 0x034; + public static final int Key_5 = 0x035; + public static final int Key_6 = 0x036; + public static final int Key_7 = 0x037; + public static final int Key_8 = 0x038; + public static final int Key_9 = 0x039; + public static final int Key_colon = 0x03a; + public static final int Key_semicolon = 0x03b; + public static final int Key_less = 0x03c; + public static final int Key_equal = 0x03d; + public static final int Key_greater = 0x03e; + public static final int Key_question = 0x03f; + public static final int Key_at = 0x040; + public static final int Key_A = 0x041; + public static final int Key_B = 0x042; + public static final int Key_C = 0x043; + public static final int Key_D = 0x044; + public static final int Key_E = 0x045; + public static final int Key_F = 0x046; + public static final int Key_G = 0x047; + public static final int Key_H = 0x048; + public static final int Key_I = 0x049; + public static final int Key_J = 0x04a; + public static final int Key_K = 0x04b; + public static final int Key_L = 0x04c; + public static final int Key_M = 0x04d; + public static final int Key_N = 0x04e; + public static final int Key_O = 0x04f; + public static final int Key_P = 0x050; + public static final int Key_Q = 0x051; + public static final int Key_R = 0x052; + public static final int Key_S = 0x053; + public static final int Key_T = 0x054; + public static final int Key_U = 0x055; + public static final int Key_V = 0x056; + public static final int Key_W = 0x057; + public static final int Key_X = 0x058; + public static final int Key_Y = 0x059; + public static final int Key_Z = 0x05a; + public static final int Key_bracketleft = 0x05b; + public static final int Key_backslash = 0x05c; + public static final int Key_bracketright = 0x05d; + public static final int Key_asciicircum = 0x05e; + public static final int Key_underscore = 0x05f; + public static final int Key_grave = 0x060; + public static final int Key_quoteleft = 0x060 /* deprecated */; + public static final int Key_a = 0x061; + public static final int Key_b = 0x062; + public static final int Key_c = 0x063; + public static final int Key_d = 0x064; + public static final int Key_e = 0x065; + public static final int Key_f = 0x066; + public static final int Key_g = 0x067; + public static final int Key_h = 0x068; + public static final int Key_i = 0x069; + public static final int Key_j = 0x06a; + public static final int Key_k = 0x06b; + public static final int Key_l = 0x06c; + public static final int Key_m = 0x06d; + public static final int Key_n = 0x06e; + public static final int Key_o = 0x06f; + public static final int Key_p = 0x070; + public static final int Key_q = 0x071; + public static final int Key_r = 0x072; + public static final int Key_s = 0x073; + public static final int Key_t = 0x074; + public static final int Key_u = 0x075; + public static final int Key_v = 0x076; + public static final int Key_w = 0x077; + public static final int Key_x = 0x078; + public static final int Key_y = 0x079; + public static final int Key_z = 0x07a; + public static final int Key_braceleft = 0x07b; + public static final int Key_bar = 0x07c; + public static final int Key_braceright = 0x07d; + public static final int Key_asciitilde = 0x07e; + public static final int Key_nobreakspace = 0x0a0; + public static final int Key_exclamdown = 0x0a1; + public static final int Key_cent = 0x0a2; + public static final int Key_sterling = 0x0a3; + public static final int Key_currency = 0x0a4; + public static final int Key_yen = 0x0a5; + public static final int Key_brokenbar = 0x0a6; + public static final int Key_section = 0x0a7; + public static final int Key_diaeresis = 0x0a8; + public static final int Key_copyright = 0x0a9; + public static final int Key_ordfeminine = 0x0aa; + public static final int Key_guillemotleft = 0x0ab /* left angle quotation mark */; + public static final int Key_notsign = 0x0ac; + public static final int Key_hyphen = 0x0ad; + public static final int Key_registered = 0x0ae; + public static final int Key_macron = 0x0af; + public static final int Key_degree = 0x0b0; + public static final int Key_plusminus = 0x0b1; + public static final int Key_twosuperior = 0x0b2; + public static final int Key_threesuperior = 0x0b3; + public static final int Key_acute = 0x0b4; + public static final int Key_mu = 0x0b5; + public static final int Key_paragraph = 0x0b6; + public static final int Key_periodcentered = 0x0b7; + public static final int Key_cedilla = 0x0b8; + public static final int Key_onesuperior = 0x0b9; + public static final int Key_masculine = 0x0ba; + public static final int Key_guillemotright = 0x0bb /* right angle quotation mark */; + public static final int Key_onequarter = 0x0bc; + public static final int Key_onehalf = 0x0bd; + public static final int Key_threequarters = 0x0be; + public static final int Key_questiondown = 0x0bf; + public static final int Key_Agrave = 0x0c0; + public static final int Key_Aacute = 0x0c1; + public static final int Key_Acircumflex = 0x0c2; + public static final int Key_Atilde = 0x0c3; + public static final int Key_Adiaeresis = 0x0c4; + public static final int Key_Aring = 0x0c5; + public static final int Key_AE = 0x0c6; + public static final int Key_Ccedilla = 0x0c7; + public static final int Key_Egrave = 0x0c8; + public static final int Key_Eacute = 0x0c9; + public static final int Key_Ecircumflex = 0x0ca; + public static final int Key_Ediaeresis = 0x0cb; + public static final int Key_Igrave = 0x0cc; + public static final int Key_Iacute = 0x0cd; + public static final int Key_Icircumflex = 0x0ce; + public static final int Key_Idiaeresis = 0x0cf; + public static final int Key_ETH = 0x0d0; + public static final int Key_Eth = 0x0d0 /* deprecated */; + public static final int Key_Ntilde = 0x0d1; + public static final int Key_Ograve = 0x0d2; + public static final int Key_Oacute = 0x0d3; + public static final int Key_Ocircumflex = 0x0d4; + public static final int Key_Otilde = 0x0d5; + public static final int Key_Odiaeresis = 0x0d6; + public static final int Key_multiply = 0x0d7; + public static final int Key_Ooblique = 0x0d8; + public static final int Key_Ugrave = 0x0d9; + public static final int Key_Uacute = 0x0da; + public static final int Key_Ucircumflex = 0x0db; + public static final int Key_Udiaeresis = 0x0dc; + public static final int Key_Yacute = 0x0dd; + public static final int Key_THORN = 0x0de; + public static final int Key_Thorn = 0x0de /* deprecated */; + public static final int Key_ssharp = 0x0df; + public static final int Key_agrave = 0x0e0; + public static final int Key_aacute = 0x0e1; + public static final int Key_acircumflex = 0x0e2; + public static final int Key_atilde = 0x0e3; + public static final int Key_adiaeresis = 0x0e4; + public static final int Key_aring = 0x0e5; + public static final int Key_ae = 0x0e6; + public static final int Key_ccedilla = 0x0e7; + public static final int Key_egrave = 0x0e8; + public static final int Key_eacute = 0x0e9; + public static final int Key_ecircumflex = 0x0ea; + public static final int Key_ediaeresis = 0x0eb; + public static final int Key_igrave = 0x0ec; + public static final int Key_iacute = 0x0ed; + public static final int Key_icircumflex = 0x0ee; + public static final int Key_idiaeresis = 0x0ef; + public static final int Key_eth = 0x0f0; + public static final int Key_ntilde = 0x0f1; + public static final int Key_ograve = 0x0f2; + public static final int Key_oacute = 0x0f3; + public static final int Key_ocircumflex = 0x0f4; + public static final int Key_otilde = 0x0f5; + public static final int Key_odiaeresis = 0x0f6; + public static final int Key_division = 0x0f7; + public static final int Key_oslash = 0x0f8; + public static final int Key_ugrave = 0x0f9; + public static final int Key_uacute = 0x0fa; + public static final int Key_ucircumflex = 0x0fb; + public static final int Key_udiaeresis = 0x0fc; + public static final int Key_yacute = 0x0fd; + public static final int Key_thorn = 0x0fe; + public static final int Key_ydiaeresis = 0x0ff; + public static final int Key_Aogonek = 0x1a1; + public static final int Key_breve = 0x1a2; + public static final int Key_Lstroke = 0x1a3; + public static final int Key_Lcaron = 0x1a5; + public static final int Key_Sacute = 0x1a6; + public static final int Key_Scaron = 0x1a9; + public static final int Key_Scedilla = 0x1aa; + public static final int Key_Tcaron = 0x1ab; + public static final int Key_Zacute = 0x1ac; + public static final int Key_Zcaron = 0x1ae; + public static final int Key_Zabovedot = 0x1af; + public static final int Key_aogonek = 0x1b1; + public static final int Key_ogonek = 0x1b2; + public static final int Key_lstroke = 0x1b3; + public static final int Key_lcaron = 0x1b5; + public static final int Key_sacute = 0x1b6; + public static final int Key_caron = 0x1b7; + public static final int Key_scaron = 0x1b9; + public static final int Key_scedilla = 0x1ba; + public static final int Key_tcaron = 0x1bb; + public static final int Key_zacute = 0x1bc; + public static final int Key_doubleacute = 0x1bd; + public static final int Key_zcaron = 0x1be; + public static final int Key_zabovedot = 0x1bf; + public static final int Key_Racute = 0x1c0; + public static final int Key_Abreve = 0x1c3; + public static final int Key_Lacute = 0x1c5; + public static final int Key_Cacute = 0x1c6; + public static final int Key_Ccaron = 0x1c8; + public static final int Key_Eogonek = 0x1ca; + public static final int Key_Ecaron = 0x1cc; + public static final int Key_Dcaron = 0x1cf; + public static final int Key_Dstroke = 0x1d0; + public static final int Key_Nacute = 0x1d1; + public static final int Key_Ncaron = 0x1d2; + public static final int Key_Odoubleacute = 0x1d5; + public static final int Key_Rcaron = 0x1d8; + public static final int Key_Uring = 0x1d9; + public static final int Key_Udoubleacute = 0x1db; + public static final int Key_Tcedilla = 0x1de; + public static final int Key_racute = 0x1e0; + public static final int Key_abreve = 0x1e3; + public static final int Key_lacute = 0x1e5; + public static final int Key_cacute = 0x1e6; + public static final int Key_ccaron = 0x1e8; + public static final int Key_eogonek = 0x1ea; + public static final int Key_ecaron = 0x1ec; + public static final int Key_dcaron = 0x1ef; + public static final int Key_dstroke = 0x1f0; + public static final int Key_nacute = 0x1f1; + public static final int Key_ncaron = 0x1f2; + public static final int Key_odoubleacute = 0x1f5; + public static final int Key_udoubleacute = 0x1fb; + public static final int Key_rcaron = 0x1f8; + public static final int Key_uring = 0x1f9; + public static final int Key_tcedilla = 0x1fe; + public static final int Key_abovedot = 0x1ff; + public static final int Key_Hstroke = 0x2a1; + public static final int Key_Hcircumflex = 0x2a6; + public static final int Key_Iabovedot = 0x2a9; + public static final int Key_Gbreve = 0x2ab; + public static final int Key_Jcircumflex = 0x2ac; + public static final int Key_hstroke = 0x2b1; + public static final int Key_hcircumflex = 0x2b6; + public static final int Key_idotless = 0x2b9; + public static final int Key_gbreve = 0x2bb; + public static final int Key_jcircumflex = 0x2bc; + public static final int Key_Cabovedot = 0x2c5; + public static final int Key_Ccircumflex = 0x2c6; + public static final int Key_Gabovedot = 0x2d5; + public static final int Key_Gcircumflex = 0x2d8; + public static final int Key_Ubreve = 0x2dd; + public static final int Key_Scircumflex = 0x2de; + public static final int Key_cabovedot = 0x2e5; + public static final int Key_ccircumflex = 0x2e6; + public static final int Key_gabovedot = 0x2f5; + public static final int Key_gcircumflex = 0x2f8; + public static final int Key_ubreve = 0x2fd; + public static final int Key_scircumflex = 0x2fe; + public static final int Key_kra = 0x3a2; + public static final int Key_kappa = 0x3a2 /* deprecated */; + public static final int Key_Rcedilla = 0x3a3; + public static final int Key_Itilde = 0x3a5; + public static final int Key_Lcedilla = 0x3a6; + public static final int Key_Emacron = 0x3aa; + public static final int Key_Gcedilla = 0x3ab; + public static final int Key_Tslash = 0x3ac; + public static final int Key_rcedilla = 0x3b3; + public static final int Key_itilde = 0x3b5; + public static final int Key_lcedilla = 0x3b6; + public static final int Key_emacron = 0x3ba; + public static final int Key_gcedilla = 0x3bb; + public static final int Key_tslash = 0x3bc; + public static final int Key_ENG = 0x3bd; + public static final int Key_eng = 0x3bf; + public static final int Key_Amacron = 0x3c0; + public static final int Key_Iogonek = 0x3c7; + public static final int Key_Eabovedot = 0x3cc; + public static final int Key_Imacron = 0x3cf; + public static final int Key_Ncedilla = 0x3d1; + public static final int Key_Omacron = 0x3d2; + public static final int Key_Kcedilla = 0x3d3; + public static final int Key_Uogonek = 0x3d9; + public static final int Key_Utilde = 0x3dd; + public static final int Key_Umacron = 0x3de; + public static final int Key_amacron = 0x3e0; + public static final int Key_iogonek = 0x3e7; + public static final int Key_eabovedot = 0x3ec; + public static final int Key_imacron = 0x3ef; + public static final int Key_ncedilla = 0x3f1; + public static final int Key_omacron = 0x3f2; + public static final int Key_kcedilla = 0x3f3; + public static final int Key_uogonek = 0x3f9; + public static final int Key_utilde = 0x3fd; + public static final int Key_umacron = 0x3fe; + public static final int Key_overline = 0x47e; + public static final int Key_kana_fullstop = 0x4a1; + public static final int Key_kana_openingbracket = 0x4a2; + public static final int Key_kana_closingbracket = 0x4a3; + public static final int Key_kana_comma = 0x4a4; + public static final int Key_kana_conjunctive = 0x4a5; + public static final int Key_kana_middledot = 0x4a5 /* deprecated */; + public static final int Key_kana_WO = 0x4a6; + public static final int Key_kana_a = 0x4a7; + public static final int Key_kana_i = 0x4a8; + public static final int Key_kana_u = 0x4a9; + public static final int Key_kana_e = 0x4aa; + public static final int Key_kana_o = 0x4ab; + public static final int Key_kana_ya = 0x4ac; + public static final int Key_kana_yu = 0x4ad; + public static final int Key_kana_yo = 0x4ae; + public static final int Key_kana_tsu = 0x4af; + public static final int Key_kana_tu = 0x4af /* deprecated */; + public static final int Key_prolongedsound = 0x4b0; + public static final int Key_kana_A = 0x4b1; + public static final int Key_kana_I = 0x4b2; + public static final int Key_kana_U = 0x4b3; + public static final int Key_kana_E = 0x4b4; + public static final int Key_kana_O = 0x4b5; + public static final int Key_kana_KA = 0x4b6; + public static final int Key_kana_KI = 0x4b7; + public static final int Key_kana_KU = 0x4b8; + public static final int Key_kana_KE = 0x4b9; + public static final int Key_kana_KO = 0x4ba; + public static final int Key_kana_SA = 0x4bb; + public static final int Key_kana_SHI = 0x4bc; + public static final int Key_kana_SU = 0x4bd; + public static final int Key_kana_SE = 0x4be; + public static final int Key_kana_SO = 0x4bf; + public static final int Key_kana_TA = 0x4c0; + public static final int Key_kana_CHI = 0x4c1; + public static final int Key_kana_TI = 0x4c1 /* deprecated */; + public static final int Key_kana_TSU = 0x4c2; + public static final int Key_kana_TU = 0x4c2 /* deprecated */; + public static final int Key_kana_TE = 0x4c3; + public static final int Key_kana_TO = 0x4c4; + public static final int Key_kana_NA = 0x4c5; + public static final int Key_kana_NI = 0x4c6; + public static final int Key_kana_NU = 0x4c7; + public static final int Key_kana_NE = 0x4c8; + public static final int Key_kana_NO = 0x4c9; + public static final int Key_kana_HA = 0x4ca; + public static final int Key_kana_HI = 0x4cb; + public static final int Key_kana_FU = 0x4cc; + public static final int Key_kana_HU = 0x4cc /* deprecated */; + public static final int Key_kana_HE = 0x4cd; + public static final int Key_kana_HO = 0x4ce; + public static final int Key_kana_MA = 0x4cf; + public static final int Key_kana_MI = 0x4d0; + public static final int Key_kana_MU = 0x4d1; + public static final int Key_kana_ME = 0x4d2; + public static final int Key_kana_MO = 0x4d3; + public static final int Key_kana_YA = 0x4d4; + public static final int Key_kana_YU = 0x4d5; + public static final int Key_kana_YO = 0x4d6; + public static final int Key_kana_RA = 0x4d7; + public static final int Key_kana_RI = 0x4d8; + public static final int Key_kana_RU = 0x4d9; + public static final int Key_kana_RE = 0x4da; + public static final int Key_kana_RO = 0x4db; + public static final int Key_kana_WA = 0x4dc; + public static final int Key_kana_N = 0x4dd; + public static final int Key_voicedsound = 0x4de; + public static final int Key_semivoicedsound = 0x4df; + public static final int Key_kana_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_Arabic_comma = 0x5ac; + public static final int Key_Arabic_semicolon = 0x5bb; + public static final int Key_Arabic_question_mark = 0x5bf; + public static final int Key_Arabic_hamza = 0x5c1; + public static final int Key_Arabic_maddaonalef = 0x5c2; + public static final int Key_Arabic_hamzaonalef = 0x5c3; + public static final int Key_Arabic_hamzaonwaw = 0x5c4; + public static final int Key_Arabic_hamzaunderalef = 0x5c5; + public static final int Key_Arabic_hamzaonyeh = 0x5c6; + public static final int Key_Arabic_alef = 0x5c7; + public static final int Key_Arabic_beh = 0x5c8; + public static final int Key_Arabic_tehmarbuta = 0x5c9; + public static final int Key_Arabic_teh = 0x5ca; + public static final int Key_Arabic_theh = 0x5cb; + public static final int Key_Arabic_jeem = 0x5cc; + public static final int Key_Arabic_hah = 0x5cd; + public static final int Key_Arabic_khah = 0x5ce; + public static final int Key_Arabic_dal = 0x5cf; + public static final int Key_Arabic_thal = 0x5d0; + public static final int Key_Arabic_ra = 0x5d1; + public static final int Key_Arabic_zain = 0x5d2; + public static final int Key_Arabic_seen = 0x5d3; + public static final int Key_Arabic_sheen = 0x5d4; + public static final int Key_Arabic_sad = 0x5d5; + public static final int Key_Arabic_dad = 0x5d6; + public static final int Key_Arabic_tah = 0x5d7; + public static final int Key_Arabic_zah = 0x5d8; + public static final int Key_Arabic_ain = 0x5d9; + public static final int Key_Arabic_ghain = 0x5da; + public static final int Key_Arabic_tatweel = 0x5e0; + public static final int Key_Arabic_feh = 0x5e1; + public static final int Key_Arabic_qaf = 0x5e2; + public static final int Key_Arabic_kaf = 0x5e3; + public static final int Key_Arabic_lam = 0x5e4; + public static final int Key_Arabic_meem = 0x5e5; + public static final int Key_Arabic_noon = 0x5e6; + public static final int Key_Arabic_ha = 0x5e7; + public static final int Key_Arabic_heh = 0x5e7 /* deprecated */; + public static final int Key_Arabic_waw = 0x5e8; + public static final int Key_Arabic_alefmaksura = 0x5e9; + public static final int Key_Arabic_yeh = 0x5ea; + public static final int Key_Arabic_fathatan = 0x5eb; + public static final int Key_Arabic_dammatan = 0x5ec; + public static final int Key_Arabic_kasratan = 0x5ed; + public static final int Key_Arabic_fatha = 0x5ee; + public static final int Key_Arabic_damma = 0x5ef; + public static final int Key_Arabic_kasra = 0x5f0; + public static final int Key_Arabic_shadda = 0x5f1; + public static final int Key_Arabic_sukun = 0x5f2; + public static final int Key_Arabic_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_Serbian_dje = 0x6a1; + public static final int Key_Macedonia_gje = 0x6a2; + public static final int Key_Cyrillic_io = 0x6a3; + public static final int Key_Ukrainian_ie = 0x6a4; + public static final int Key_Ukranian_je = 0x6a4 /* deprecated */; + public static final int Key_Macedonia_dse = 0x6a5; + public static final int Key_Ukrainian_i = 0x6a6; + public static final int Key_Ukranian_i = 0x6a6 /* deprecated */; + public static final int Key_Ukrainian_yi = 0x6a7; + public static final int Key_Ukranian_yi = 0x6a7 /* deprecated */; + public static final int Key_Cyrillic_je = 0x6a8; + public static final int Key_Serbian_je = 0x6a8 /* deprecated */; + public static final int Key_Cyrillic_lje = 0x6a9; + public static final int Key_Serbian_lje = 0x6a9 /* deprecated */; + public static final int Key_Cyrillic_nje = 0x6aa; + public static final int Key_Serbian_nje = 0x6aa /* deprecated */; + public static final int Key_Serbian_tshe = 0x6ab; + public static final int Key_Macedonia_kje = 0x6ac; + public static final int Key_Byelorussian_shortu = 0x6ae; + public static final int Key_Cyrillic_dzhe = 0x6af; + public static final int Key_Serbian_dze = 0x6af /* deprecated */; + public static final int Key_numerosign = 0x6b0; + public static final int Key_Serbian_DJE = 0x6b1; + public static final int Key_Macedonia_GJE = 0x6b2; + public static final int Key_Cyrillic_IO = 0x6b3; + public static final int Key_Ukrainian_IE = 0x6b4; + public static final int Key_Ukranian_JE = 0x6b4 /* deprecated */; + public static final int Key_Macedonia_DSE = 0x6b5; + public static final int Key_Ukrainian_I = 0x6b6; + public static final int Key_Ukranian_I = 0x6b6 /* deprecated */; + public static final int Key_Ukrainian_YI = 0x6b7; + public static final int Key_Ukranian_YI = 0x6b7 /* deprecated */; + public static final int Key_Cyrillic_JE = 0x6b8; + public static final int Key_Serbian_JE = 0x6b8 /* deprecated */; + public static final int Key_Cyrillic_LJE = 0x6b9; + public static final int Key_Serbian_LJE = 0x6b9 /* deprecated */; + public static final int Key_Cyrillic_NJE = 0x6ba; + public static final int Key_Serbian_NJE = 0x6ba /* deprecated */; + public static final int Key_Serbian_TSHE = 0x6bb; + public static final int Key_Macedonia_KJE = 0x6bc; + public static final int Key_Byelorussian_SHORTU = 0x6be; + public static final int Key_Cyrillic_DZHE = 0x6bf; + public static final int Key_Serbian_DZE = 0x6bf /* deprecated */; + public static final int Key_Cyrillic_yu = 0x6c0; + public static final int Key_Cyrillic_a = 0x6c1; + public static final int Key_Cyrillic_be = 0x6c2; + public static final int Key_Cyrillic_tse = 0x6c3; + public static final int Key_Cyrillic_de = 0x6c4; + public static final int Key_Cyrillic_ie = 0x6c5; + public static final int Key_Cyrillic_ef = 0x6c6; + public static final int Key_Cyrillic_ghe = 0x6c7; + public static final int Key_Cyrillic_ha = 0x6c8; + public static final int Key_Cyrillic_i = 0x6c9; + public static final int Key_Cyrillic_shorti = 0x6ca; + public static final int Key_Cyrillic_ka = 0x6cb; + public static final int Key_Cyrillic_el = 0x6cc; + public static final int Key_Cyrillic_em = 0x6cd; + public static final int Key_Cyrillic_en = 0x6ce; + public static final int Key_Cyrillic_o = 0x6cf; + public static final int Key_Cyrillic_pe = 0x6d0; + public static final int Key_Cyrillic_ya = 0x6d1; + public static final int Key_Cyrillic_er = 0x6d2; + public static final int Key_Cyrillic_es = 0x6d3; + public static final int Key_Cyrillic_te = 0x6d4; + public static final int Key_Cyrillic_u = 0x6d5; + public static final int Key_Cyrillic_zhe = 0x6d6; + public static final int Key_Cyrillic_ve = 0x6d7; + public static final int Key_Cyrillic_softsign = 0x6d8; + public static final int Key_Cyrillic_yeru = 0x6d9; + public static final int Key_Cyrillic_ze = 0x6da; + public static final int Key_Cyrillic_sha = 0x6db; + public static final int Key_Cyrillic_e = 0x6dc; + public static final int Key_Cyrillic_shcha = 0x6dd; + public static final int Key_Cyrillic_che = 0x6de; + public static final int Key_Cyrillic_hardsign = 0x6df; + public static final int Key_Cyrillic_YU = 0x6e0; + public static final int Key_Cyrillic_A = 0x6e1; + public static final int Key_Cyrillic_BE = 0x6e2; + public static final int Key_Cyrillic_TSE = 0x6e3; + public static final int Key_Cyrillic_DE = 0x6e4; + public static final int Key_Cyrillic_IE = 0x6e5; + public static final int Key_Cyrillic_EF = 0x6e6; + public static final int Key_Cyrillic_GHE = 0x6e7; + public static final int Key_Cyrillic_HA = 0x6e8; + public static final int Key_Cyrillic_I = 0x6e9; + public static final int Key_Cyrillic_SHORTI = 0x6ea; + public static final int Key_Cyrillic_KA = 0x6eb; + public static final int Key_Cyrillic_EL = 0x6ec; + public static final int Key_Cyrillic_EM = 0x6ed; + public static final int Key_Cyrillic_EN = 0x6ee; + public static final int Key_Cyrillic_O = 0x6ef; + public static final int Key_Cyrillic_PE = 0x6f0; + public static final int Key_Cyrillic_YA = 0x6f1; + public static final int Key_Cyrillic_ER = 0x6f2; + public static final int Key_Cyrillic_ES = 0x6f3; + public static final int Key_Cyrillic_TE = 0x6f4; + public static final int Key_Cyrillic_U = 0x6f5; + public static final int Key_Cyrillic_ZHE = 0x6f6; + public static final int Key_Cyrillic_VE = 0x6f7; + public static final int Key_Cyrillic_SOFTSIGN = 0x6f8; + public static final int Key_Cyrillic_YERU = 0x6f9; + public static final int Key_Cyrillic_ZE = 0x6fa; + public static final int Key_Cyrillic_SHA = 0x6fb; + public static final int Key_Cyrillic_E = 0x6fc; + public static final int Key_Cyrillic_SHCHA = 0x6fd; + public static final int Key_Cyrillic_CHE = 0x6fe; + public static final int Key_Cyrillic_HARDSIGN = 0x6ff; + public static final int Key_Greek_ALPHAaccent = 0x7a1; + public static final int Key_Greek_EPSILONaccent = 0x7a2; + public static final int Key_Greek_ETAaccent = 0x7a3; + public static final int Key_Greek_IOTAaccent = 0x7a4; + public static final int Key_Greek_IOTAdieresis = 0x7a5; + public static final int Key_Greek_OMICRONaccent = 0x7a7; + public static final int Key_Greek_UPSILONaccent = 0x7a8; + public static final int Key_Greek_UPSILONdieresis = 0x7a9; + public static final int Key_Greek_OMEGAaccent = 0x7ab; + public static final int Key_Greek_accentdieresis = 0x7ae; + public static final int Key_Greek_horizbar = 0x7af; + public static final int Key_Greek_alphaaccent = 0x7b1; + public static final int Key_Greek_epsilonaccent = 0x7b2; + public static final int Key_Greek_etaaccent = 0x7b3; + public static final int Key_Greek_iotaaccent = 0x7b4; + public static final int Key_Greek_iotadieresis = 0x7b5; + public static final int Key_Greek_iotaaccentdieresis = 0x7b6; + public static final int Key_Greek_omicronaccent = 0x7b7; + public static final int Key_Greek_upsilonaccent = 0x7b8; + public static final int Key_Greek_upsilondieresis = 0x7b9; + public static final int Key_Greek_upsilonaccentdieresis = 0x7ba; + public static final int Key_Greek_omegaaccent = 0x7bb; + public static final int Key_Greek_ALPHA = 0x7c1; + public static final int Key_Greek_BETA = 0x7c2; + public static final int Key_Greek_GAMMA = 0x7c3; + public static final int Key_Greek_DELTA = 0x7c4; + public static final int Key_Greek_EPSILON = 0x7c5; + public static final int Key_Greek_ZETA = 0x7c6; + public static final int Key_Greek_ETA = 0x7c7; + public static final int Key_Greek_THETA = 0x7c8; + public static final int Key_Greek_IOTA = 0x7c9; + public static final int Key_Greek_KAPPA = 0x7ca; + public static final int Key_Greek_LAMDA = 0x7cb; + public static final int Key_Greek_LAMBDA = 0x7cb; + public static final int Key_Greek_MU = 0x7cc; + public static final int Key_Greek_NU = 0x7cd; + public static final int Key_Greek_XI = 0x7ce; + public static final int Key_Greek_OMICRON = 0x7cf; + public static final int Key_Greek_PI = 0x7d0; + public static final int Key_Greek_RHO = 0x7d1; + public static final int Key_Greek_SIGMA = 0x7d2; + public static final int Key_Greek_TAU = 0x7d4; + public static final int Key_Greek_UPSILON = 0x7d5; + public static final int Key_Greek_PHI = 0x7d6; + public static final int Key_Greek_CHI = 0x7d7; + public static final int Key_Greek_PSI = 0x7d8; + public static final int Key_Greek_OMEGA = 0x7d9; + public static final int Key_Greek_alpha = 0x7e1; + public static final int Key_Greek_beta = 0x7e2; + public static final int Key_Greek_gamma = 0x7e3; + public static final int Key_Greek_delta = 0x7e4; + public static final int Key_Greek_epsilon = 0x7e5; + public static final int Key_Greek_zeta = 0x7e6; + public static final int Key_Greek_eta = 0x7e7; + public static final int Key_Greek_theta = 0x7e8; + public static final int Key_Greek_iota = 0x7e9; + public static final int Key_Greek_kappa = 0x7ea; + public static final int Key_Greek_lamda = 0x7eb; + public static final int Key_Greek_lambda = 0x7eb; + public static final int Key_Greek_mu = 0x7ec; + public static final int Key_Greek_nu = 0x7ed; + public static final int Key_Greek_xi = 0x7ee; + public static final int Key_Greek_omicron = 0x7ef; + public static final int Key_Greek_pi = 0x7f0; + public static final int Key_Greek_rho = 0x7f1; + public static final int Key_Greek_sigma = 0x7f2; + public static final int Key_Greek_finalsmallsigma = 0x7f3; + public static final int Key_Greek_tau = 0x7f4; + public static final int Key_Greek_upsilon = 0x7f5; + public static final int Key_Greek_phi = 0x7f6; + public static final int Key_Greek_chi = 0x7f7; + public static final int Key_Greek_psi = 0x7f8; + public static final int Key_Greek_omega = 0x7f9; + public static final int Key_Greek_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_leftradical = 0x8a1; + public static final int Key_topleftradical = 0x8a2; + public static final int Key_horizconnector = 0x8a3; + public static final int Key_topintegral = 0x8a4; + public static final int Key_botintegral = 0x8a5; + public static final int Key_vertconnector = 0x8a6; + public static final int Key_topleftsqbracket = 0x8a7; + public static final int Key_botleftsqbracket = 0x8a8; + public static final int Key_toprightsqbracket = 0x8a9; + public static final int Key_botrightsqbracket = 0x8aa; + public static final int Key_topleftparens = 0x8ab; + public static final int Key_botleftparens = 0x8ac; + public static final int Key_toprightparens = 0x8ad; + public static final int Key_botrightparens = 0x8ae; + public static final int Key_leftmiddlecurlybrace = 0x8af; + public static final int Key_rightmiddlecurlybrace = 0x8b0; + public static final int Key_topleftsummation = 0x8b1; + public static final int Key_botleftsummation = 0x8b2; + public static final int Key_topvertsummationconnector = 0x8b3; + public static final int Key_botvertsummationconnector = 0x8b4; + public static final int Key_toprightsummation = 0x8b5; + public static final int Key_botrightsummation = 0x8b6; + public static final int Key_rightmiddlesummation = 0x8b7; + public static final int Key_lessthanequal = 0x8bc; + public static final int Key_notequal = 0x8bd; + public static final int Key_greaterthanequal = 0x8be; + public static final int Key_integral = 0x8bf; + public static final int Key_therefore = 0x8c0; + public static final int Key_variation = 0x8c1; + public static final int Key_infinity = 0x8c2; + public static final int Key_nabla = 0x8c5; + public static final int Key_approximate = 0x8c8; + public static final int Key_similarequal = 0x8c9; + public static final int Key_ifonlyif = 0x8cd; + public static final int Key_implies = 0x8ce; + public static final int Key_identical = 0x8cf; + public static final int Key_radical = 0x8d6; + public static final int Key_includedin = 0x8da; + public static final int Key_includes = 0x8db; + public static final int Key_intersection = 0x8dc; + public static final int Key_union = 0x8dd; + public static final int Key_logicaland = 0x8de; + public static final int Key_logicalor = 0x8df; + public static final int Key_partialderivative = 0x8ef; + public static final int Key_function = 0x8f6; + public static final int Key_leftarrow = 0x8fb; + public static final int Key_uparrow = 0x8fc; + public static final int Key_rightarrow = 0x8fd; + public static final int Key_downarrow = 0x8fe; + public static final int Key_blank = 0x9df; + public static final int Key_soliddiamond = 0x9e0; + public static final int Key_checkerboard = 0x9e1; + public static final int Key_ht = 0x9e2; + public static final int Key_ff = 0x9e3; + public static final int Key_cr = 0x9e4; + public static final int Key_lf = 0x9e5; + public static final int Key_nl = 0x9e8; + public static final int Key_vt = 0x9e9; + public static final int Key_lowrightcorner = 0x9ea; + public static final int Key_uprightcorner = 0x9eb; + public static final int Key_upleftcorner = 0x9ec; + public static final int Key_lowleftcorner = 0x9ed; + public static final int Key_crossinglines = 0x9ee; + public static final int Key_horizlinescan1 = 0x9ef; + public static final int Key_horizlinescan3 = 0x9f0; + public static final int Key_horizlinescan5 = 0x9f1; + public static final int Key_horizlinescan7 = 0x9f2; + public static final int Key_horizlinescan9 = 0x9f3; + public static final int Key_leftt = 0x9f4; + public static final int Key_rightt = 0x9f5; + public static final int Key_bott = 0x9f6; + public static final int Key_topt = 0x9f7; + public static final int Key_vertbar = 0x9f8; + public static final int Key_emspace = 0xaa1; + public static final int Key_enspace = 0xaa2; + public static final int Key_em3space = 0xaa3; + public static final int Key_em4space = 0xaa4; + public static final int Key_digitspace = 0xaa5; + public static final int Key_punctspace = 0xaa6; + public static final int Key_thinspace = 0xaa7; + public static final int Key_hairspace = 0xaa8; + public static final int Key_emdash = 0xaa9; + public static final int Key_endash = 0xaaa; + public static final int Key_signifblank = 0xaac; + public static final int Key_ellipsis = 0xaae; + public static final int Key_doubbaselinedot = 0xaaf; + public static final int Key_onethird = 0xab0; + public static final int Key_twothirds = 0xab1; + public static final int Key_onefifth = 0xab2; + public static final int Key_twofifths = 0xab3; + public static final int Key_threefifths = 0xab4; + public static final int Key_fourfifths = 0xab5; + public static final int Key_onesixth = 0xab6; + public static final int Key_fivesixths = 0xab7; + public static final int Key_careof = 0xab8; + public static final int Key_figdash = 0xabb; + public static final int Key_leftanglebracket = 0xabc; + public static final int Key_decimalpoint = 0xabd; + public static final int Key_rightanglebracket = 0xabe; + public static final int Key_marker = 0xabf; + public static final int Key_oneeighth = 0xac3; + public static final int Key_threeeighths = 0xac4; + public static final int Key_fiveeighths = 0xac5; + public static final int Key_seveneighths = 0xac6; + public static final int Key_trademark = 0xac9; + public static final int Key_signaturemark = 0xaca; + public static final int Key_trademarkincircle = 0xacb; + public static final int Key_leftopentriangle = 0xacc; + public static final int Key_rightopentriangle = 0xacd; + public static final int Key_emopencircle = 0xace; + public static final int Key_emopenrectangle = 0xacf; + public static final int Key_leftsinglequotemark = 0xad0; + public static final int Key_rightsinglequotemark = 0xad1; + public static final int Key_leftdoublequotemark = 0xad2; + public static final int Key_rightdoublequotemark = 0xad3; + public static final int Key_prescription = 0xad4; + public static final int Key_minutes = 0xad6; + public static final int Key_seconds = 0xad7; + public static final int Key_latincross = 0xad9; + public static final int Key_hexagram = 0xada; + public static final int Key_filledrectbullet = 0xadb; + public static final int Key_filledlefttribullet = 0xadc; + public static final int Key_filledrighttribullet = 0xadd; + public static final int Key_emfilledcircle = 0xade; + public static final int Key_emfilledrect = 0xadf; + public static final int Key_enopencircbullet = 0xae0; + public static final int Key_enopensquarebullet = 0xae1; + public static final int Key_openrectbullet = 0xae2; + public static final int Key_opentribulletup = 0xae3; + public static final int Key_opentribulletdown = 0xae4; + public static final int Key_openstar = 0xae5; + public static final int Key_enfilledcircbullet = 0xae6; + public static final int Key_enfilledsqbullet = 0xae7; + public static final int Key_filledtribulletup = 0xae8; + public static final int Key_filledtribulletdown = 0xae9; + public static final int Key_leftpointer = 0xaea; + public static final int Key_rightpointer = 0xaeb; + public static final int Key_club = 0xaec; + public static final int Key_diamond = 0xaed; + public static final int Key_heart = 0xaee; + public static final int Key_maltesecross = 0xaf0; + public static final int Key_dagger = 0xaf1; + public static final int Key_doubledagger = 0xaf2; + public static final int Key_checkmark = 0xaf3; + public static final int Key_ballotcross = 0xaf4; + public static final int Key_musicalsharp = 0xaf5; + public static final int Key_musicalflat = 0xaf6; + public static final int Key_malesymbol = 0xaf7; + public static final int Key_femalesymbol = 0xaf8; + public static final int Key_telephone = 0xaf9; + public static final int Key_telephonerecorder = 0xafa; + public static final int Key_phonographcopyright = 0xafb; + public static final int Key_caret = 0xafc; + public static final int Key_singlelowquotemark = 0xafd; + public static final int Key_doublelowquotemark = 0xafe; + public static final int Key_cursor = 0xaff; + public static final int Key_leftcaret = 0xba3; + public static final int Key_rightcaret = 0xba6; + public static final int Key_downcaret = 0xba8; + public static final int Key_upcaret = 0xba9; + public static final int Key_overbar = 0xbc0; + public static final int Key_downtack = 0xbc2; + public static final int Key_upshoe = 0xbc3; + public static final int Key_downstile = 0xbc4; + public static final int Key_underbar = 0xbc6; + public static final int Key_jot = 0xbca; + public static final int Key_quad = 0xbcc; + public static final int Key_uptack = 0xbce; + public static final int Key_circle = 0xbcf; + public static final int Key_upstile = 0xbd3; + public static final int Key_downshoe = 0xbd6; + public static final int Key_rightshoe = 0xbd8; + public static final int Key_leftshoe = 0xbda; + public static final int Key_lefttack = 0xbdc; + public static final int Key_righttack = 0xbfc; + public static final int Key_hebrew_doublelowline = 0xcdf; + public static final int Key_hebrew_aleph = 0xce0; + public static final int Key_hebrew_bet = 0xce1; + public static final int Key_hebrew_beth = 0xce1 /* deprecated */; + public static final int Key_hebrew_gimel = 0xce2; + public static final int Key_hebrew_gimmel = 0xce2 /* deprecated */; + public static final int Key_hebrew_dalet = 0xce3; + public static final int Key_hebrew_daleth = 0xce3 /* deprecated */; + public static final int Key_hebrew_he = 0xce4; + public static final int Key_hebrew_waw = 0xce5; + public static final int Key_hebrew_zain = 0xce6; + public static final int Key_hebrew_zayin = 0xce6 /* deprecated */; + public static final int Key_hebrew_chet = 0xce7; + public static final int Key_hebrew_het = 0xce7 /* deprecated */; + public static final int Key_hebrew_tet = 0xce8; + public static final int Key_hebrew_teth = 0xce8 /* deprecated */; + public static final int Key_hebrew_yod = 0xce9; + public static final int Key_hebrew_finalkaph = 0xcea; + public static final int Key_hebrew_kaph = 0xceb; + public static final int Key_hebrew_lamed = 0xcec; + public static final int Key_hebrew_finalmem = 0xced; + public static final int Key_hebrew_mem = 0xcee; + public static final int Key_hebrew_finalnun = 0xcef; + public static final int Key_hebrew_nun = 0xcf0; + public static final int Key_hebrew_samech = 0xcf1; + public static final int Key_hebrew_samekh = 0xcf1 /* deprecated */; + public static final int Key_hebrew_ayin = 0xcf2; + public static final int Key_hebrew_finalpe = 0xcf3; + public static final int Key_hebrew_pe = 0xcf4; + public static final int Key_hebrew_finalzade = 0xcf5; + public static final int Key_hebrew_finalzadi = 0xcf5 /* deprecated */; + public static final int Key_hebrew_zade = 0xcf6; + public static final int Key_hebrew_zadi = 0xcf6 /* deprecated */; + public static final int Key_hebrew_qoph = 0xcf7; + public static final int Key_hebrew_kuf = 0xcf7 /* deprecated */; + public static final int Key_hebrew_resh = 0xcf8; + public static final int Key_hebrew_shin = 0xcf9; + public static final int Key_hebrew_taw = 0xcfa; + public static final int Key_hebrew_taf = 0xcfa /* deprecated */; + public static final int Key_Hebrew_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_Thai_kokai = 0xda1; + public static final int Key_Thai_khokhai = 0xda2; + public static final int Key_Thai_khokhuat = 0xda3; + public static final int Key_Thai_khokhwai = 0xda4; + public static final int Key_Thai_khokhon = 0xda5; + public static final int Key_Thai_khorakhang = 0xda6 ; + public static final int Key_Thai_ngongu = 0xda7 ; + public static final int Key_Thai_chochan = 0xda8 ; + public static final int Key_Thai_choching = 0xda9 ; + public static final int Key_Thai_chochang = 0xdaa ; + public static final int Key_Thai_soso = 0xdab; + public static final int Key_Thai_chochoe = 0xdac; + public static final int Key_Thai_yoying = 0xdad; + public static final int Key_Thai_dochada = 0xdae; + public static final int Key_Thai_topatak = 0xdaf; + public static final int Key_Thai_thothan = 0xdb0; + public static final int Key_Thai_thonangmontho = 0xdb1; + public static final int Key_Thai_thophuthao = 0xdb2; + public static final int Key_Thai_nonen = 0xdb3; + public static final int Key_Thai_dodek = 0xdb4; + public static final int Key_Thai_totao = 0xdb5; + public static final int Key_Thai_thothung = 0xdb6; + public static final int Key_Thai_thothahan = 0xdb7; + public static final int Key_Thai_thothong = 0xdb8; + public static final int Key_Thai_nonu = 0xdb9; + public static final int Key_Thai_bobaimai = 0xdba; + public static final int Key_Thai_popla = 0xdbb; + public static final int Key_Thai_phophung = 0xdbc; + public static final int Key_Thai_fofa = 0xdbd; + public static final int Key_Thai_phophan = 0xdbe; + public static final int Key_Thai_fofan = 0xdbf; + public static final int Key_Thai_phosamphao = 0xdc0; + public static final int Key_Thai_moma = 0xdc1; + public static final int Key_Thai_yoyak = 0xdc2; + public static final int Key_Thai_rorua = 0xdc3; + public static final int Key_Thai_ru = 0xdc4; + public static final int Key_Thai_loling = 0xdc5; + public static final int Key_Thai_lu = 0xdc6; + public static final int Key_Thai_wowaen = 0xdc7; + public static final int Key_Thai_sosala = 0xdc8; + public static final int Key_Thai_sorusi = 0xdc9; + public static final int Key_Thai_sosua = 0xdca; + public static final int Key_Thai_hohip = 0xdcb; + public static final int Key_Thai_lochula = 0xdcc; + public static final int Key_Thai_oang = 0xdcd; + public static final int Key_Thai_honokhuk = 0xdce; + public static final int Key_Thai_paiyannoi = 0xdcf; + public static final int Key_Thai_saraa = 0xdd0; + public static final int Key_Thai_maihanakat = 0xdd1; + public static final int Key_Thai_saraaa = 0xdd2; + public static final int Key_Thai_saraam = 0xdd3; + public static final int Key_Thai_sarai = 0xdd4 ; + public static final int Key_Thai_saraii = 0xdd5 ; + public static final int Key_Thai_saraue = 0xdd6 ; + public static final int Key_Thai_sarauee = 0xdd7 ; + public static final int Key_Thai_sarau = 0xdd8 ; + public static final int Key_Thai_sarauu = 0xdd9 ; + public static final int Key_Thai_phinthu = 0xdda; + public static final int Key_Thai_maihanakat_maitho = 0xdde; + public static final int Key_Thai_baht = 0xddf; + public static final int Key_Thai_sarae = 0xde0 ; + public static final int Key_Thai_saraae = 0xde1; + public static final int Key_Thai_sarao = 0xde2; + public static final int Key_Thai_saraaimaimuan = 0xde3 ; + public static final int Key_Thai_saraaimaimalai = 0xde4 ; + public static final int Key_Thai_lakkhangyao = 0xde5; + public static final int Key_Thai_maiyamok = 0xde6; + public static final int Key_Thai_maitaikhu = 0xde7; + public static final int Key_Thai_maiek = 0xde8 ; + public static final int Key_Thai_maitho = 0xde9; + public static final int Key_Thai_maitri = 0xdea; + public static final int Key_Thai_maichattawa = 0xdeb; + public static final int Key_Thai_thanthakhat = 0xdec; + public static final int Key_Thai_nikhahit = 0xded; + public static final int Key_Thai_leksun = 0xdf0 ; + public static final int Key_Thai_leknung = 0xdf1 ; + public static final int Key_Thai_leksong = 0xdf2 ; + public static final int Key_Thai_leksam = 0xdf3; + public static final int Key_Thai_leksi = 0xdf4 ; + public static final int Key_Thai_lekha = 0xdf5 ; + public static final int Key_Thai_lekhok = 0xdf6 ; + public static final int Key_Thai_lekchet = 0xdf7 ; + public static final int Key_Thai_lekpaet = 0xdf8 ; + public static final int Key_Thai_lekkao = 0xdf9 ; + public static final int Key_Hangul = 0xff31 /* Hangul start/stop(toggle) */; + public static final int Key_Hangul_Start = 0xff32 /* Hangul start */; + public static final int Key_Hangul_End = 0xff33 /* Hangul end, English start */; + public static final int Key_Hangul_Hanja = 0xff34 /* Start Hangul->Hanja Conversion */; + public static final int Key_Hangul_Jamo = 0xff35 /* Hangul Jamo mode */; + public static final int Key_Hangul_Romaja = 0xff36 /* Hangul Romaja mode */; + public static final int Key_Hangul_Codeinput = 0xff37 /* Hangul code input mode */; + public static final int Key_Hangul_Jeonja = 0xff38 /* Jeonja mode */; + public static final int Key_Hangul_Banja = 0xff39 /* Banja mode */; + public static final int Key_Hangul_PreHanja = 0xff3a /* Pre Hanja conversion */; + public static final int Key_Hangul_PostHanja = 0xff3b /* Post Hanja conversion */; + public static final int Key_Hangul_SingleCandidate = 0xff3c /* Single candidate */; + public static final int Key_Hangul_MultipleCandidate = 0xff3d /* Multiple candidate */; + public static final int Key_Hangul_PreviousCandidate = 0xff3e /* Previous candidate */; + public static final int Key_Hangul_Special = 0xff3f /* Special symbols */; + public static final int Key_Hangul_switch = 0xFF7E /* Alias for mode_switch */; + public static final int Key_Hangul_Kiyeog = 0xea1; + public static final int Key_Hangul_SsangKiyeog = 0xea2; + public static final int Key_Hangul_KiyeogSios = 0xea3; + public static final int Key_Hangul_Nieun = 0xea4; + public static final int Key_Hangul_NieunJieuj = 0xea5; + public static final int Key_Hangul_NieunHieuh = 0xea6; + public static final int Key_Hangul_Dikeud = 0xea7; + public static final int Key_Hangul_SsangDikeud = 0xea8; + public static final int Key_Hangul_Rieul = 0xea9; + public static final int Key_Hangul_RieulKiyeog = 0xeaa; + public static final int Key_Hangul_RieulMieum = 0xeab; + public static final int Key_Hangul_RieulPieub = 0xeac; + public static final int Key_Hangul_RieulSios = 0xead; + public static final int Key_Hangul_RieulTieut = 0xeae; + public static final int Key_Hangul_RieulPhieuf = 0xeaf; + public static final int Key_Hangul_RieulHieuh = 0xeb0; + public static final int Key_Hangul_Mieum = 0xeb1; + public static final int Key_Hangul_Pieub = 0xeb2; + public static final int Key_Hangul_SsangPieub = 0xeb3; + public static final int Key_Hangul_PieubSios = 0xeb4; + public static final int Key_Hangul_Sios = 0xeb5; + public static final int Key_Hangul_SsangSios = 0xeb6; + public static final int Key_Hangul_Ieung = 0xeb7; + public static final int Key_Hangul_Jieuj = 0xeb8; + public static final int Key_Hangul_SsangJieuj = 0xeb9; + public static final int Key_Hangul_Cieuc = 0xeba; + public static final int Key_Hangul_Khieuq = 0xebb; + public static final int Key_Hangul_Tieut = 0xebc; + public static final int Key_Hangul_Phieuf = 0xebd; + public static final int Key_Hangul_Hieuh = 0xebe; + public static final int Key_Hangul_A = 0xebf; + public static final int Key_Hangul_AE = 0xec0; + public static final int Key_Hangul_YA = 0xec1; + public static final int Key_Hangul_YAE = 0xec2; + public static final int Key_Hangul_EO = 0xec3; + public static final int Key_Hangul_E = 0xec4; + public static final int Key_Hangul_YEO = 0xec5; + public static final int Key_Hangul_YE = 0xec6; + public static final int Key_Hangul_O = 0xec7; + public static final int Key_Hangul_WA = 0xec8; + public static final int Key_Hangul_WAE = 0xec9; + public static final int Key_Hangul_OE = 0xeca; + public static final int Key_Hangul_YO = 0xecb; + public static final int Key_Hangul_U = 0xecc; + public static final int Key_Hangul_WEO = 0xecd; + public static final int Key_Hangul_WE = 0xece; + public static final int Key_Hangul_WI = 0xecf; + public static final int Key_Hangul_YU = 0xed0; + public static final int Key_Hangul_EU = 0xed1; + public static final int Key_Hangul_YI = 0xed2; + public static final int Key_Hangul_I = 0xed3; + public static final int Key_Hangul_J_Kiyeog = 0xed4; + public static final int Key_Hangul_J_SsangKiyeog = 0xed5; + public static final int Key_Hangul_J_KiyeogSios = 0xed6; + public static final int Key_Hangul_J_Nieun = 0xed7; + public static final int Key_Hangul_J_NieunJieuj = 0xed8; + public static final int Key_Hangul_J_NieunHieuh = 0xed9; + public static final int Key_Hangul_J_Dikeud = 0xeda; + public static final int Key_Hangul_J_Rieul = 0xedb; + public static final int Key_Hangul_J_RieulKiyeog = 0xedc; + public static final int Key_Hangul_J_RieulMieum = 0xedd; + public static final int Key_Hangul_J_RieulPieub = 0xede; + public static final int Key_Hangul_J_RieulSios = 0xedf; + public static final int Key_Hangul_J_RieulTieut = 0xee0; + public static final int Key_Hangul_J_RieulPhieuf = 0xee1; + public static final int Key_Hangul_J_RieulHieuh = 0xee2; + public static final int Key_Hangul_J_Mieum = 0xee3; + public static final int Key_Hangul_J_Pieub = 0xee4; + public static final int Key_Hangul_J_PieubSios = 0xee5; + public static final int Key_Hangul_J_Sios = 0xee6; + public static final int Key_Hangul_J_SsangSios = 0xee7; + public static final int Key_Hangul_J_Ieung = 0xee8; + public static final int Key_Hangul_J_Jieuj = 0xee9; + public static final int Key_Hangul_J_Cieuc = 0xeea; + public static final int Key_Hangul_J_Khieuq = 0xeeb; + public static final int Key_Hangul_J_Tieut = 0xeec; + public static final int Key_Hangul_J_Phieuf = 0xeed; + public static final int Key_Hangul_J_Hieuh = 0xeee; + public static final int Key_Hangul_RieulYeorinHieuh = 0xeef; + public static final int Key_Hangul_SunkyeongeumMieum = 0xef0; + public static final int Key_Hangul_SunkyeongeumPieub = 0xef1; + public static final int Key_Hangul_PanSios = 0xef2; + public static final int Key_Hangul_KkogjiDalrinIeung = 0xef3; + public static final int Key_Hangul_SunkyeongeumPhieuf = 0xef4; + public static final int Key_Hangul_YeorinHieuh = 0xef5; + public static final int Key_Hangul_AraeA = 0xef6; + public static final int Key_Hangul_AraeAE = 0xef7; + public static final int Key_Hangul_J_PanSios = 0xef8; + public static final int Key_Hangul_J_KkogjiDalrinIeung = 0xef9; + public static final int Key_Hangul_J_YeorinHieuh = 0xefa; + public static final int Key_Korean_Won = 0xeff; + public static final int Key_EuroSign = 0x20ac; +} diff --git a/app/src/main/java/com/javispedro/vndroid/keymaps/SpanishKeyHandler.java b/app/src/main/java/com/javispedro/vndroid/keymaps/SpanishKeyHandler.java new file mode 100644 index 0000000..4337b61 --- /dev/null +++ b/app/src/main/java/com/javispedro/vndroid/keymaps/SpanishKeyHandler.java @@ -0,0 +1,51 @@ +package com.javispedro.vndroid.keymaps; + +import java.text.Normalizer; + +import static com.javispedro.vndroid.keymaps.KeySyms.Key_dead_acute; +import static com.javispedro.vndroid.keymaps.KeySyms.Key_dead_grave; + +public class SpanishKeyHandler extends KeyHandler { + + private char deadKey = 0; + + @Override + public boolean keyDown(int key) { + if (key >= KeySyms.Key_space && key <= KeySyms.Key_z) { + // Printable keysyms + char c = (char) (' ' + (key - KeySyms.Key_space)); + if (deadKey != 0) { + StringBuilder builder = new StringBuilder(2); + builder.append(c); + builder.append(deadKey); + String text = Normalizer.normalize(builder.toString(), Normalizer.Form.NFKC); + action.postText(text); + deadKey = 0; + return true; + } + action.postChar(c); + return true; + } else { + switch (key) { + case KeySyms.Key_ccedilla: + action.postChar('ç'); + return true; + case KeySyms.Key_ntilde: + action.postChar('ñ'); + return true; + case Key_dead_acute: + deadKey = '\u0301'; + return true; + case Key_dead_grave: + deadKey = '\u0300'; + return true; + } + } + return false; + } + + @Override + public boolean keyUp(int key) { + return false; + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_action_stat_reply.png b/app/src/main/res/drawable-hdpi/ic_action_stat_reply.png new file mode 100644 index 0000000..835d96f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_stat_reply.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_stat_share.png b/app/src/main/res/drawable-hdpi/ic_action_stat_share.png new file mode 100644 index 0000000..c329f58 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_stat_share.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.png b/app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.png new file mode 100644 index 0000000..1a6aac4 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_stat_server_running.png b/app/src/main/res/drawable-hdpi/ic_stat_server_running.png new file mode 100644 index 0000000..1079b5a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_server_running.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_stat_reply.png b/app/src/main/res/drawable-mdpi/ic_action_stat_reply.png new file mode 100644 index 0000000..9e34465 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_stat_reply.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_stat_share.png b/app/src/main/res/drawable-mdpi/ic_action_stat_share.png new file mode 100644 index 0000000..056deb5 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_stat_share.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.png b/app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.png new file mode 100644 index 0000000..db5b758 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_stat_server_running.png b/app/src/main/res/drawable-mdpi/ic_stat_server_running.png new file mode 100644 index 0000000..ccb0d18 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stat_server_running.png differ diff --git a/app/src/main/res/drawable-nodpi/example_picture.png b/app/src/main/res/drawable-nodpi/example_picture.png new file mode 100644 index 0000000..e0627f5 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/example_picture.png differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/ic_action_stat_reply.png b/app/src/main/res/drawable-xhdpi/ic_action_stat_reply.png new file mode 100644 index 0000000..4cc854a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_stat_reply.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_stat_share.png b/app/src/main/res/drawable-xhdpi/ic_action_stat_share.png new file mode 100644 index 0000000..15549b0 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_stat_share.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.png b/app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.png new file mode 100644 index 0000000..d6500af Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_server_running.png b/app/src/main/res/drawable-xhdpi/ic_stat_server_running.png new file mode 100644 index 0000000..ea4ddbc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_server_running.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.png b/app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.png new file mode 100644 index 0000000..ab74d54 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_server_running.png b/app/src/main/res/drawable-xxhdpi/ic_stat_server_running.png new file mode 100644 index 0000000..3f7db26 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stat_server_running.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.png b/app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.png new file mode 100644 index 0000000..2d2374e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.png b/app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.png new file mode 100644 index 0000000..e34cce7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.png differ diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_setup.xml b/app/src/main/res/layout/activity_setup.xml new file mode 100644 index 0000000..9512149 --- /dev/null +++ b/app/src/main/res/layout/activity_setup.xml @@ -0,0 +1,45 @@ + + + + + +