summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/.gitignore1
-rw-r--r--app/CMakeLists.txt86
-rw-r--r--app/build.gradle44
-rw-r--r--app/libs/LibVNCServer-0.9.11.tar.gzbin0 -> 1413739 bytes
-rwxr-xr-xapp/libs/build-openssl.sh31
-rw-r--r--app/libs/cmake/FindJPEG.cmake9
-rw-r--r--app/libs/cmake/FindOpenSSL.cmake12
-rw-r--r--app/libs/cmake/FindPNG.cmake1
-rw-r--r--app/libs/libjpeg-turbo-2.0.0.tar.gzbin0 -> 2158457 bytes
-rw-r--r--app/libs/libvncserver-LibVNCServer-0.9.11.patch236
-rw-r--r--app/libs/openssl-1.1.1.tar.gzbin0 -> 8337920 bytes
-rwxr-xr-xapp/libs/prepare.sh13
-rw-r--r--app/proguard-rules.pro21
-rw-r--r--app/src/main/AndroidManifest.xml41
-rw-r--r--app/src/main/cpp/native-lib.cpp361
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ControlService.java47
-rw-r--r--app/src/main/java/com/javispedro/vndroid/KeyEventOutput.java286
-rw-r--r--app/src/main/java/com/javispedro/vndroid/PointerEventOutput.java101
-rw-r--r--app/src/main/java/com/javispedro/vndroid/RFBServer.java98
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ScreenGrabber.java83
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ScreenMirrorGrabber.java110
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ScreenVirtualGrabber.java38
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ServerRunningNotification.java108
-rw-r--r--app/src/main/java/com/javispedro/vndroid/ServerService.java175
-rw-r--r--app/src/main/java/com/javispedro/vndroid/SetupActivity.java78
-rw-r--r--app/src/main/java/com/javispedro/vndroid/keymaps/AndroidKeyHandler.java69
-rw-r--r--app/src/main/java/com/javispedro/vndroid/keymaps/KeyActionHandler.java20
-rw-r--r--app/src/main/java/com/javispedro/vndroid/keymaps/KeyHandler.java12
-rw-r--r--app/src/main/java/com/javispedro/vndroid/keymaps/KeySyms.java1321
-rw-r--r--app/src/main/java/com/javispedro/vndroid/keymaps/SpanishKeyHandler.java51
-rw-r--r--app/src/main/res/drawable-hdpi/ic_action_stat_reply.pngbin0 -> 1480 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_action_stat_share.pngbin0 -> 1606 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.pngbin0 -> 444 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_stat_server_running.pngbin0 -> 345 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_action_stat_reply.pngbin0 -> 1314 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_action_stat_share.pngbin0 -> 1341 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.pngbin0 -> 321 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_stat_server_running.pngbin0 -> 264 bytes
-rw-r--r--app/src/main/res/drawable-nodpi/example_picture.pngbin0 -> 1885 bytes
-rw-r--r--app/src/main/res/drawable-v24/ic_launcher_foreground.xml34
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_action_stat_reply.pngbin0 -> 1692 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_action_stat_share.pngbin0 -> 1780 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.pngbin0 -> 594 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_stat_server_running.pngbin0 -> 431 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.pngbin0 -> 887 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_stat_server_running.pngbin0 -> 618 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.pngbin0 -> 1168 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.pngbin0 -> 873 bytes
-rw-r--r--app/src/main/res/drawable/ic_launcher_background.xml170
-rw-r--r--app/src/main/res/layout/activity_setup.xml45
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2963 bytes
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 4905 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2060 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2783 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4490 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 6895 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 6387 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10413 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9128 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 15132 bytes
-rw-r--r--app/src/main/res/values/colors.xml6
-rw-r--r--app/src/main/res/values/strings.xml11
-rw-r--r--app/src/main/res/values/styles.xml11
-rw-r--r--app/src/main/res/xml/controlservice.xml6
66 files changed, 3746 insertions, 0 deletions
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
--- /dev/null
+++ b/app/libs/LibVNCServer-0.9.11.tar.gz
Binary files 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
--- /dev/null
+++ b/app/libs/libjpeg-turbo-2.0.0.tar.gz
Binary files 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
--- /dev/null
+++ b/app/libs/openssl-1.1.1.tar.gz
Binary files 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.javispedro.vndroid">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".SetupActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".ServerService"
+ android:enabled="true"
+ android:exported="true" />
+
+ <service
+ android:name=".ControlService"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/controlservice" />
+ </service>
+
+ </application>
+
+</manifest> \ 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 <android/log.h>
+#include <sys/eventfd.h>
+#include <thread>
+
+#include <jni.h>
+#include <rfb/rfb.h>
+
+#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<bool> pendingPtrEvent;
+ int ptrButtonMask, ptrX, ptrY;
+
+ std::atomic<bool> pendingKeyEvent;
+ rfbKeySym key;
+ bool keyState;
+};
+
+static inline Data * getData(JNIEnv *env, jobject instance)
+{
+ jclass cls = env->GetObjectClass(instance);
+ cls = reinterpret_cast<jclass>(env->NewGlobalRef(cls));
+
+ jfieldID fid = env->GetFieldID(cls, "nativeData", "J");
+
+ Data *data = reinterpret_cast<Data*>(env->GetLongField(instance, fid));
+
+ assert(data);
+
+ return data;
+}
+
+static inline Data * getData(rfbClientPtr client)
+{
+ Data *data = reinterpret_cast<Data*>(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<jclass>(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<jclass>(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<jlong>(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<char *>(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<KeyHandler> handlers = new ArrayList<KeyHandler>();
+
+ @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.
+ * <p>
+ * 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
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_action_stat_reply.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_action_stat_share.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_action_stop_screen_sharing.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_stat_server_running.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_action_stat_reply.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_action_stat_share.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_action_stop_screen_sharing.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_stat_server_running.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-nodpi/example_picture.png
Binary files 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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillType="evenOdd"
+ android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="78.5885"
+ android:endY="90.9159"
+ android:startX="48.7653"
+ android:startY="61.0927"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
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
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_action_stat_reply.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_action_stat_share.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_action_stop_screen_sharing.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_server_running.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_action_stop_screen_sharing.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_stat_server_running.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_action_stop_screen_sharing.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/ic_stat_server_running.png
Binary files 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#008577"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".SetupActivity">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginBottom="8dp"
+ android:gravity="center"
+ android:orientation="horizontal"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.19">
+
+ <Button
+ android:id="@+id/btnStart"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="onStartClick"
+ android:text="@string/action_start" />
+
+ <Space
+ android:layout_width="75dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ <Button
+ android:id="@+id/btnStop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="onStopClick"
+ android:text="@string/action_stop" />
+
+ </LinearLayout>
+
+</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#008577</color>
+ <color name="colorPrimaryDark">#00574B</color>
+ <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9c0ca47
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,11 @@
+<resources>
+ <string name="app_name">Vndroid</string>
+
+ <string name="server_running_notification_channel">Server status</string>
+ <string name="server_running_notification_title">Server active</string>
+
+ <string name="action_start">Start</string>
+ <string name="action_stop">Stop</string>
+
+ <string name="toast_no_input_service">Accessibility service not enabled: clients will not be able to control</string>
+</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/app/src/main/res/xml/controlservice.xml b/app/src/main/res/xml/controlservice.xml
new file mode 100644
index 0000000..29a16b7
--- /dev/null
+++ b/app/src/main/res/xml/controlservice.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:canRetrieveWindowContent="true"
+ android:canPerformGestures="true">
+
+</accessibility-service> \ No newline at end of file