Unified · Split
| @@ -0,0 +1,38 @@ | ||
| 1 | +# Android | |
| 2 | +SDKPREFIX=$(HOME)/Android/Sdk | |
| 3 | +JAVA_HOME=/usr | |
| 4 | +OBJS=lib/arm64-v8a/libdrawterm.so lib/armeabi-v7a/libdrawterm.so lib/x86/libdrawterm.so lib/x86_64/libdrawterm.so | |
| 5 | + | |
| 6 | +all: drawterm.apk | |
| 7 | + | |
| 8 | +clean: | |
| 9 | + rm -f *.apk lib/*/*.so | |
| 10 | + | |
| 11 | +lib/arm64-v8a/libdrawterm.so: | |
| 12 | + CONF=android-arm64 make -j5; | |
| 13 | + CONF=android-arm64 make clean; | |
| 14 | + | |
| 15 | +lib/armeabi-v7a/libdrawterm.so: | |
| 16 | + CONF=android-arm make -j5; | |
| 17 | + CONF=android-arm make clean; | |
| 18 | + | |
| 19 | +lib/x86/libdrawterm.so: | |
| 20 | + CONF=android-386 make -j5; | |
| 21 | + CONF=android-386 make clean; | |
| 22 | + | |
| 23 | +lib/x86_64/libdrawterm.so: | |
| 24 | + CONF=android-amd64 make -j5; | |
| 25 | + CONF=android-amd64 make clean; | |
| 26 | + | |
| 27 | +drawterm.apk: drawterm-signed.apk | |
| 28 | + $(SDKPREFIX)/build-tools/30.0.3/zipalign -v -f 4 $< $@ | |
| 29 | + | |
| 30 | +drawterm-signed.apk: drawterm-unsigned.apk drawterm.keystore | |
| 31 | + $(JAVA_HOME)/bin/jarsigner -verbose -keystore ./drawterm.keystore -storepass glendarocks -keypass glendarocks -signedjar $@ $< drawtermKey | |
| 32 | + | |
| 33 | +drawterm-unsigned.apk: $(OBJS) | |
| 34 | + $(SDKPREFIX)/build-tools/30.0.3/aapt package -v -f -M gui-android/AndroidManifest.xml -S gui-android/res -I $(SDKPREFIX)/platforms/android-21/android.jar -F $@ gui-android/bin | |
| 35 | + $(SDKPREFIX)/build-tools/30.0.3/aapt add $@ $(OBJS) | |
| 36 | + | |
| 37 | +drawterm.keystore: | |
| 38 | + $(JAVA_HOME)/bin/keytool -genkeypair -validity 1000 -dname "CN=9front,O=Android,C=US" -keystore $@ -storepass glendarocks -keypass glendarocks -alias drawtermKey -keyalg RSA -v | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Android | |
| 2 | +SDKPREFIX=$(HOME)/Android/Sdk | |
| 3 | +NDKPREFIX=$(SDKPREFIX)/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin | |
| 4 | +JAVA_HOME=/usr | |
| 5 | + | |
| 6 | +PTHREAD=-pthread | |
| 7 | +AR=$(NDKPREFIX)/i686-linux-android-ar | |
| 8 | +AS=$(NDKPREFIX)/i686-linux-android-as | |
| 9 | +RANLIB=$(NDKPREFIX)/i686-linux-android-ranlib | |
| 10 | +STRIP=$(NDKPREFIX)/i686-linux-android-strip | |
| 11 | +CC=$(NDKPREFIX)/i686-linux-android21-clang | |
| 12 | +CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -Dmain=dt_main -fPIC | |
| 13 | +O=o | |
| 14 | +OS=posix | |
| 15 | +GUI=android | |
| 16 | +LDADD=-ggdb -lm -shared -llog -landroid | |
| 17 | +LDFLAGS=$(PTHREAD) | |
| 18 | +TARG=lib/x86/libdrawterm.so | |
| 19 | +AUDIO=none | |
| 20 | + | |
| 21 | +all: default | |
| 22 | + | |
| 23 | +libmachdep.a: | |
| 24 | + arch=386; \ | |
| 25 | + (cd posix-$$arch && make) | |
| 26 | + | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Android | |
| 2 | +SDKPREFIX=$(HOME)/Android/Sdk | |
| 3 | +NDKPREFIX=$(SDKPREFIX)/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin | |
| 4 | +JAVA_HOME=/usr | |
| 5 | + | |
| 6 | +PTHREAD=-pthread | |
| 7 | +AR=$(NDKPREFIX)/x86_64-linux-android-ar | |
| 8 | +AS=$(NDKPREFIX)/x86_64-linux-android-as | |
| 9 | +RANLIB=$(NDKPREFIX)/x86_64-linux-android-ranlib | |
| 10 | +STRIP=$(NDKPREFIX)/x86_64-linux-android-strip | |
| 11 | +CC=$(NDKPREFIX)/x86_64-linux-android21-clang | |
| 12 | +CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -Dmain=dt_main -fPIC | |
| 13 | +O=o | |
| 14 | +OS=posix | |
| 15 | +GUI=android | |
| 16 | +LDADD=-ggdb -lm -shared -llog -landroid | |
| 17 | +LDFLAGS=$(PTHREAD) | |
| 18 | +TARG=lib/x86_64/libdrawterm.so | |
| 19 | +AUDIO=none | |
| 20 | + | |
| 21 | +all: default | |
| 22 | + | |
| 23 | +libmachdep.a: | |
| 24 | + arch=amd64; \ | |
| 25 | + (cd posix-$$arch && make) | |
| 26 | + | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Android | |
| 2 | +SDKPREFIX=$(HOME)/Android/Sdk | |
| 3 | +NDKPREFIX=$(SDKPREFIX)/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin | |
| 4 | +JAVA_HOME=/usr | |
| 5 | + | |
| 6 | +PTHREAD=-pthread | |
| 7 | +AR=$(NDKPREFIX)/arm-linux-androideabi-ar | |
| 8 | +AS=$(NDKPREFIX)/arm-linux-androideabi-as | |
| 9 | +RANLIB=$(NDKPREFIX)/arm-linux-androideabi-ranlib | |
| 10 | +STRIP=$(NDKPREFIX)/arm-linux-androideabi-strip | |
| 11 | +CC=$(NDKPREFIX)/armv7a-linux-androideabi21-clang | |
| 12 | +CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -Dmain=dt_main -fPIC | |
| 13 | +O=o | |
| 14 | +OS=posix | |
| 15 | +GUI=android | |
| 16 | +LDADD=-ggdb -lm -shared -llog -landroid | |
| 17 | +LDFLAGS=$(PTHREAD) | |
| 18 | +TARG=lib/armeabi-v7a/libdrawterm.so | |
| 19 | +AUDIO=none | |
| 20 | + | |
| 21 | +all: default | |
| 22 | + | |
| 23 | +libmachdep.a: | |
| 24 | + arch=arm; \ | |
| 25 | + (cd posix-$$arch && make) | |
| 26 | + | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +# Android | |
| 2 | +SDKPREFIX=$(HOME)/Android/Sdk | |
| 3 | +NDKPREFIX=$(SDKPREFIX)/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin | |
| 4 | +JAVA_HOME=/usr | |
| 5 | + | |
| 6 | +PTHREAD=-pthread | |
| 7 | +AR=$(NDKPREFIX)/aarch64-linux-android-ar | |
| 8 | +AS=$(NDKPREFIX)/aarch64-linux-android-as | |
| 9 | +RANLIB=$(NDKPREFIX)/aarch64-linux-android-ranlib | |
| 10 | +STRIP=$(NDKPREFIX)/aarch64-linux-android-strip | |
| 11 | +CC=$(NDKPREFIX)/aarch64-linux-android21-clang | |
| 12 | +CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -Dmain=dt_main -fPIC | |
| 13 | +O=o | |
| 14 | +OS=posix | |
| 15 | +GUI=android | |
| 16 | +LDADD=-ggdb -lm -shared -llog -landroid | |
| 17 | +LDFLAGS=$(PTHREAD) | |
| 18 | +TARG=lib/arm64-v8a/libdrawterm.so | |
| 19 | +AUDIO=none | |
| 20 | + | |
| 21 | +all: default | |
| 22 | + | |
| 23 | +libmachdep.a: | |
| 24 | + arch=arm64; \ | |
| 25 | + (cd posix-$$arch && make) | |
| 26 | + | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +# Unix | |
| 2 | +#PTHREAD= # for Mac | |
| 3 | +PTHREAD=-pthread | |
| 4 | +AR=ar | |
| 5 | +AS=as | |
| 6 | +RANLIB=ranlib | |
| 7 | +CC=gcc | |
| 8 | +CFLAGS=-Wall -Wno-missing-braces -ggdb -I$(ROOT) -I$(ROOT)/include -I$(ROOT)/kern -c -D_THREAD_SAFE $(PTHREAD) -O2 | |
| 9 | +O=o | |
| 10 | +OS=posix | |
| 11 | +GUI=fbdev | |
| 12 | +LDADD=-ggdb -lm -lasound | |
| 13 | +LDFLAGS=$(PTHREAD) | |
| 14 | +TARG=drawterm | |
| 15 | +# AUDIO=none | |
| 16 | +AUDIO=alsa | |
| 17 | + | |
| 18 | +all: default | |
| 19 | + | |
| 20 | +libmachdep.a: | |
| 21 | + arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/; s/x86_64/amd64/; s/armv[567].*/arm/; s/aarch64/arm64/'`; \ | |
| 22 | + (cd posix-$$arch && make) | |
| @@ -18,6 +18,17 @@ To build on Mac OS X with X11 (xquartz), run CONF=osx-x11 make. · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | To build on Mac OS X with Cocoa, run CONF=osx-cocoa make and "cp drawterm gui-cocoa/drawterm.app/". |
| 20 | 20 | |
| 21 | +To build for Android, make sure Make.android* and gui-android/Makefile are correct for your build and target systems, then run make -f Make.android | |
| 22 | + | |
| 23 | +USAGE | |
| 24 | +------- | |
| 25 | +On Android the five checkboxes at the top represent the three mouse buttons and mousewheel, determining which "buttons" are clicked. The "kb" button toggles the soft keyboard. | |
| 26 | + | |
| 27 | + | |
| 28 | +CAVEATS | |
| 29 | +-------- | |
| 30 | +Be aware that right now on Android the login details are saved as a plaintext string if saved, and there is no secstore support. | |
| 31 | + | |
| 21 | 32 | |
| 22 | 33 | BINARIES |
| 23 | 34 | --------- |
| @@ -0,0 +1,30 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + package="org.echoline.drawterm"> | |
| 4 | + | |
| 5 | + <supports-screens android:largeScreens="true" | |
| 6 | + android:normalScreens="true" android:smallScreens="true" | |
| 7 | + android:anyDensity="true" /> | |
| 8 | + | |
| 9 | + <application | |
| 10 | + android:allowBackup="true" | |
| 11 | + android:icon="@mipmap/ic_launcher" | |
| 12 | + android:label="@string/app_name" | |
| 13 | + android:supportsRtl="true" | |
| 14 | + android:theme="@style/AppTheme"> | |
| 15 | + <activity | |
| 16 | + android:name=".MainActivity" | |
| 17 | + android:label="@string/app_name" | |
| 18 | + android:windowSoftInputMode="stateUnchanged|adjustNothing"> | |
| 19 | + <intent-filter> | |
| 20 | + <action android:name="android.intent.action.MAIN" /> | |
| 21 | + <category android:name="android.intent.category.LAUNCHER" /> | |
| 22 | + </intent-filter> | |
| 23 | + </activity> | |
| 24 | + </application> | |
| 25 | + <uses-permission android:name="android.permission.INTERNET"/> | |
| 26 | + <!--<uses-permission android:name="android.permission.SET_DEBUG_APP"/>--> | |
| 27 | + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |
| 28 | + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |
| 29 | + <uses-permission android:name="android.permission.CAMERA"/> | |
| 30 | +</manifest> | |
| @@ -0,0 +1,23 @@ | ||
| 1 | +ROOT=.. | |
| 2 | +include ../Make.config | |
| 3 | +LIB=libgui.a | |
| 4 | + | |
| 5 | +OFILES=\ | |
| 6 | + cpp/android.$O\ | |
| 7 | + cpp/native-lib.$O\ | |
| 8 | + cpp/devandroid.$O\ | |
| 9 | + | |
| 10 | +default: $(LIB) gen/org/echoline/drawterm/R.java bin/classes.dex | |
| 11 | +$(LIB): $(OFILES) | |
| 12 | + $(AR) r $(LIB) $(OFILES) | |
| 13 | + $(RANLIB) $(LIB) | |
| 14 | + | |
| 15 | +gen/org/echoline/drawterm/R.java: $(shell find res/ -type f) | |
| 16 | + $(SDKPREFIX)/build-tools/30.0.3/aapt package -f -m -M AndroidManifest.xml -I $(SDKPREFIX)/platforms/android-21/android.jar -S res/ -J gen | |
| 17 | + | |
| 18 | +bin/classes.dex: obj/org/echoline/drawterm/MainActivity.class obj/org/echoline/drawterm/DrawTermThread.class obj/org/echoline/drawterm/MySurfaceView.class | |
| 19 | + $(SDKPREFIX)/build-tools/30.0.3/dx --dex --verbose --output=$@ obj/ | |
| 20 | + | |
| 21 | +obj/org/echoline/drawterm/%.class: java/org/echoline/drawterm/%.java | |
| 22 | + $(JAVA_HOME)/bin/javac -d obj/ -classpath $(SDKPREFIX)/platforms/android-21/android.jar -sourcepath java java/org/echoline/drawterm/$*.java gen/org/echoline/drawterm/R.java | |
| 23 | + | |
| @@ -0,0 +1,230 @@ | ||
| 1 | +#include <jni.h> | |
| 2 | +#include <android/native_window.h> | |
| 3 | +#include <android/log.h> | |
| 4 | + | |
| 5 | +#include "u.h" | |
| 6 | +#include "lib.h" | |
| 7 | +#include "dat.h" | |
| 8 | +#include "fns.h" | |
| 9 | + | |
| 10 | +#include <draw.h> | |
| 11 | +#include <memdraw.h> | |
| 12 | +#include <keyboard.h> | |
| 13 | +#include <cursor.h> | |
| 14 | +#include "screen.h" | |
| 15 | + | |
| 16 | +Memimage *gscreen = nil; | |
| 17 | +extern int screenWidth; | |
| 18 | +extern int screenHeight; | |
| 19 | +extern ANativeWindow *window; | |
| 20 | +extern jobject mainActivityObj; | |
| 21 | +extern JavaVM *jvm; | |
| 22 | + | |
| 23 | +char* | |
| 24 | +clipread(void) | |
| 25 | +{ | |
| 26 | + char *ret; | |
| 27 | + const char *s; | |
| 28 | + JNIEnv *env; | |
| 29 | + jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL); | |
| 30 | + if (rs != JNI_OK) { | |
| 31 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "AttachCurrentThread returned error: %d", rs); | |
| 32 | + return strdup(""); | |
| 33 | + } | |
| 34 | + jclass clazz = (*env)->GetObjectClass(env, mainActivityObj); | |
| 35 | + jmethodID methodID = (*env)->GetMethodID(env, clazz, "getClipBoard", "()Ljava/lang/String;"); | |
| 36 | + jstring str = (jstring)(*env)->CallObjectMethod(env, mainActivityObj, methodID); | |
| 37 | + s = (*env)->GetStringUTFChars(env, str, NULL); | |
| 38 | + ret = strdup(s); | |
| 39 | + (*env)->ReleaseStringUTFChars(env, str, s); | |
| 40 | + (*jvm)->DetachCurrentThread(jvm); | |
| 41 | + return ret; | |
| 42 | +} | |
| 43 | + | |
| 44 | +int | |
| 45 | +clipwrite(char *buf) | |
| 46 | +{ | |
| 47 | + JNIEnv *env; | |
| 48 | + jint rs = (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6); | |
| 49 | + if(rs != JNI_OK) { | |
| 50 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "GetEnv returned error: %d", rs); | |
| 51 | + return 0; | |
| 52 | + } | |
| 53 | + jclass clazz = (*env)->GetObjectClass(env, mainActivityObj); | |
| 54 | + jmethodID methodID = (*env)->GetMethodID(env, clazz, "setClipBoard", "(Ljava/lang/String;)V"); | |
| 55 | + jstring str = (*env)->NewStringUTF(env, buf); | |
| 56 | + (*env)->CallVoidMethod(env, mainActivityObj, methodID, str); | |
| 57 | + return 0; | |
| 58 | +} | |
| 59 | + | |
| 60 | +void | |
| 61 | +show_notification(char *buf) | |
| 62 | +{ | |
| 63 | + JNIEnv *env; | |
| 64 | + jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL); | |
| 65 | + if(rs != JNI_OK) { | |
| 66 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "AttachCurrentThread returned error: %d", rs); | |
| 67 | + return; | |
| 68 | + } | |
| 69 | + jclass clazz = (*env)->GetObjectClass(env, mainActivityObj); | |
| 70 | + jmethodID methodID = (*env)->GetMethodID(env, clazz, "showNotification", "(Ljava/lang/String;)V"); | |
| 71 | + jstring str = (*env)->NewStringUTF(env, buf); | |
| 72 | + (*env)->CallVoidMethod(env, mainActivityObj, methodID, str); | |
| 73 | + (*jvm)->DetachCurrentThread(jvm); | |
| 74 | + return; | |
| 75 | +} | |
| 76 | + | |
| 77 | +int | |
| 78 | +num_cameras() | |
| 79 | +{ | |
| 80 | + JNIEnv *env; | |
| 81 | + int n; | |
| 82 | + jint rs = (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6); | |
| 83 | + if(rs != JNI_OK) { | |
| 84 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "GetEnv returned error: %d", rs); | |
| 85 | + return 0; | |
| 86 | + } | |
| 87 | + jclass clazz = (*env)->GetObjectClass(env, mainActivityObj); | |
| 88 | + jmethodID methodID = (*env)->GetMethodID(env, clazz, "numCameras", "()I"); | |
| 89 | + n = (*env)->CallIntMethod(env, mainActivityObj, methodID); | |
| 90 | + return n; | |
| 91 | +} | |
| 92 | + | |
| 93 | +void | |
| 94 | +take_picture(int id) | |
| 95 | +{ | |
| 96 | + JNIEnv *env; | |
| 97 | + jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL); | |
| 98 | + if(rs != JNI_OK) { | |
| 99 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "AttachCurrentThread returned error: %d", rs); | |
| 100 | + return; | |
| 101 | + } | |
| 102 | + jclass clazz = (*env)->GetObjectClass(env, mainActivityObj); | |
| 103 | + jmethodID methodID = (*env)->GetMethodID(env, clazz, "takePicture", "(I)V"); | |
| 104 | + (*env)->CallVoidMethod(env, mainActivityObj, methodID, id); | |
| 105 | + (*jvm)->DetachCurrentThread(jvm); | |
| 106 | + return; | |
| 107 | +} | |
| 108 | + | |
| 109 | +void | |
| 110 | +setcolor(ulong i, ulong r, ulong g, ulong b) | |
| 111 | +{ | |
| 112 | + return; | |
| 113 | +} | |
| 114 | + | |
| 115 | +void | |
| 116 | +getcolor(ulong v, ulong *r, ulong *g, ulong *b) | |
| 117 | +{ | |
| 118 | + *r = (v>>16)&0xFF; | |
| 119 | + *g = (v>>8)&0xFF; | |
| 120 | + *b = v&0xFF; | |
| 121 | +} | |
| 122 | + | |
| 123 | +void | |
| 124 | +flushmemscreen(Rectangle r) | |
| 125 | +{ | |
| 126 | + ANativeWindow_Buffer buffer; | |
| 127 | + uint8_t *pixels; | |
| 128 | + int x, y, o, b; | |
| 129 | + ARect bounds; | |
| 130 | + | |
| 131 | + if (window == NULL) | |
| 132 | + return; | |
| 133 | + | |
| 134 | + memset(&buffer, 0, sizeof(buffer)); | |
| 135 | + | |
| 136 | + bounds.left = r.min.x; | |
| 137 | + bounds.top = r.min.y; | |
| 138 | + bounds.right = r.max.x; | |
| 139 | + bounds.bottom = r.max.y; | |
| 140 | + | |
| 141 | + if (ANativeWindow_lock(window, &buffer, &bounds) != 0) { | |
| 142 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "Unable to lock window buffer"); | |
| 143 | + return; | |
| 144 | + } | |
| 145 | + | |
| 146 | + r.min.x = bounds.left; | |
| 147 | + r.min.y = bounds.top; | |
| 148 | + r.max.x = bounds.right; | |
| 149 | + r.max.y = bounds.bottom; | |
| 150 | + | |
| 151 | + pixels = (uint8_t*)buffer.bits; | |
| 152 | + for (y = r.min.y; y < r.max.y; y++) | |
| 153 | + for (x = r.min.x; x < r.max.x; x++) { | |
| 154 | + o = (y * screenWidth + x) * 4; | |
| 155 | + b = (y * buffer.stride + x) * 4; | |
| 156 | + pixels[b+3] = 0xFF; | |
| 157 | + pixels[b+2] = gscreen->data->bdata[o+0]; | |
| 158 | + pixels[b+1] = gscreen->data->bdata[o+1]; | |
| 159 | + pixels[b+0] = gscreen->data->bdata[o+2]; | |
| 160 | + } | |
| 161 | + | |
| 162 | + if (ANativeWindow_unlockAndPost(window) != 0) { | |
| 163 | + __android_log_print(ANDROID_LOG_WARN, "drawterm", "Unable to unlock and post window buffer"); | |
| 164 | + } | |
| 165 | + return; | |
| 166 | +} | |
| 167 | + | |
| 168 | +void | |
| 169 | +screeninit(void) | |
| 170 | +{ | |
| 171 | + Rectangle r = Rect(0,0,screenWidth,screenHeight); | |
| 172 | + memimageinit(); | |
| 173 | + screensize(r, XRGB32); | |
| 174 | + if (gscreen == nil) | |
| 175 | + panic("screensize failed"); | |
| 176 | + gscreen->clipr = r; | |
| 177 | + terminit(); | |
| 178 | + qlock(&drawlock); | |
| 179 | + flushmemscreen(r); | |
| 180 | + qunlock(&drawlock); | |
| 181 | + return; | |
| 182 | +} | |
| 183 | + | |
| 184 | +void | |
| 185 | +screensize(Rectangle r, ulong chan) | |
| 186 | +{ | |
| 187 | + Memimage *mi; | |
| 188 | + | |
| 189 | + mi = allocmemimage(r, chan); | |
| 190 | + if (mi == nil) | |
| 191 | + return; | |
| 192 | + | |
| 193 | + if (gscreen != nil) | |
| 194 | + freememimage(gscreen); | |
| 195 | + | |
| 196 | + gscreen = mi; | |
| 197 | + gscreen->clipr = ZR; | |
| 198 | +} | |
| 199 | + | |
| 200 | +Memdata* | |
| 201 | +attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen) | |
| 202 | +{ | |
| 203 | + *r = gscreen->clipr; | |
| 204 | + *depth = gscreen->depth; | |
| 205 | + *chan = gscreen->chan; | |
| 206 | + *width = gscreen->width; | |
| 207 | + *softscreen = 1; | |
| 208 | + | |
| 209 | + gscreen->data->ref++; | |
| 210 | + return gscreen->data; | |
| 211 | +} | |
| 212 | + | |
| 213 | +void | |
| 214 | +setcursor(void) | |
| 215 | +{ | |
| 216 | + return; | |
| 217 | +} | |
| 218 | + | |
| 219 | +void | |
| 220 | +mouseset(Point xy) | |
| 221 | +{ | |
| 222 | + return; | |
| 223 | +} | |
| 224 | + | |
| 225 | +void | |
| 226 | +guimain(void) | |
| 227 | +{ | |
| 228 | + cpubody(); | |
| 229 | +} | |
| 230 | + | |
| @@ -0,0 +1,248 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include <android/log.h> | |
| 8 | +#include <android/sensor.h> | |
| 9 | + | |
| 10 | +void show_notification(char *buf); | |
| 11 | +void take_picture(int id); | |
| 12 | +int num_cameras(); | |
| 13 | + | |
| 14 | +int Ncameras = 0; | |
| 15 | + | |
| 16 | +uchar *cambuf = nil; | |
| 17 | +int camlen; | |
| 18 | + | |
| 19 | +ASensorManager *sensorManager = NULL; | |
| 20 | + | |
| 21 | +enum | |
| 22 | +{ | |
| 23 | + Qdir = 0, | |
| 24 | + Qcam = 1, | |
| 25 | + Qaccel = 2, | |
| 26 | + Qcompass = 4, | |
| 27 | + Qnotification = 6, | |
| 28 | +}; | |
| 29 | +#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) | |
| 30 | + | |
| 31 | +static void androidinit(void); | |
| 32 | + | |
| 33 | +static void | |
| 34 | +androidinit(void) | |
| 35 | +{ | |
| 36 | + sensorManager = ASensorManager_getInstance(); | |
| 37 | + | |
| 38 | + Ncameras = num_cameras(); | |
| 39 | +} | |
| 40 | + | |
| 41 | +static Chan* | |
| 42 | +androidattach(char *param) | |
| 43 | +{ | |
| 44 | + Chan *c; | |
| 45 | + | |
| 46 | + c = devattach('N', param); | |
| 47 | + c->qid.path = QID(0, 0, Qdir); | |
| 48 | + c->qid.type = QTDIR; | |
| 49 | + c->qid.vers = 0; | |
| 50 | + | |
| 51 | + return c; | |
| 52 | +} | |
| 53 | + | |
| 54 | +static int | |
| 55 | +androidgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp) | |
| 56 | +{ | |
| 57 | + Qid q; | |
| 58 | + | |
| 59 | + if (s == DEVDOTDOT) { | |
| 60 | + mkqid(&q, Qdir, 0, QTDIR); | |
| 61 | + devdir(c, q, "#N", 0, eve, 0555, dp); | |
| 62 | + return 1; | |
| 63 | + } | |
| 64 | + if (s < Ncameras) { | |
| 65 | + sprintf(up->genbuf, "cam%d.jpg", s); | |
| 66 | + mkqid(&q, (s << 16) | Qcam, 0, QTFILE); | |
| 67 | + devdir(c, q, up->genbuf, 0, eve, 0444, dp); | |
| 68 | + return 1; | |
| 69 | + } | |
| 70 | + if (s == Ncameras) { | |
| 71 | + sprintf(up->genbuf, "accel"); | |
| 72 | + mkqid(&q, Qaccel, 0, QTFILE); | |
| 73 | + devdir(c, q, up->genbuf, 0, eve, 0444, dp); | |
| 74 | + return 1; | |
| 75 | + } | |
| 76 | + if (s == (Ncameras+1)) { | |
| 77 | + sprintf(up->genbuf, "compass"); | |
| 78 | + mkqid(&q, Qcompass, 0, QTFILE); | |
| 79 | + devdir(c, q, up->genbuf, 0, eve, 0444, dp); | |
| 80 | + return 1; | |
| 81 | + } | |
| 82 | + if (s == (Ncameras+2)) { | |
| 83 | + sprintf(up->genbuf, "notification"); | |
| 84 | + mkqid(&q, Qnotification, 0, QTFILE); | |
| 85 | + devdir(c, q, up->genbuf, 0, eve, 0222, dp); | |
| 86 | + return 1; | |
| 87 | + } | |
| 88 | + return -1; | |
| 89 | +} | |
| 90 | + | |
| 91 | +static Walkqid* | |
| 92 | +androidwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 93 | +{ | |
| 94 | + return devwalk(c, nc, name, nname, 0, 0, androidgen); | |
| 95 | +} | |
| 96 | + | |
| 97 | +static int | |
| 98 | +androidstat(Chan *c, uchar *db, int n) | |
| 99 | +{ | |
| 100 | + return devstat(c, db, n, 0, 0, androidgen); | |
| 101 | +} | |
| 102 | + | |
| 103 | +static Chan* | |
| 104 | +androidopen(Chan *c, int omode) | |
| 105 | +{ | |
| 106 | + p9_uvlong s; | |
| 107 | + | |
| 108 | + c = devopen(c, omode, 0, 0, androidgen); | |
| 109 | + | |
| 110 | + if (c->qid.path & Qcam) { | |
| 111 | + s = c->qid.path >> 16; | |
| 112 | + take_picture(s); | |
| 113 | + } | |
| 114 | + c->mode = openmode(omode); | |
| 115 | + c->flag |= COPEN; | |
| 116 | + c->offset = 0; | |
| 117 | + c->iounit = 8192; | |
| 118 | + | |
| 119 | + return c; | |
| 120 | +} | |
| 121 | + | |
| 122 | +static void | |
| 123 | +androidclose(Chan *c) | |
| 124 | +{ | |
| 125 | + if (c->qid.path & Qcam && cambuf != nil) { | |
| 126 | + free(cambuf); | |
| 127 | + cambuf = nil; | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | |
| 131 | +static long | |
| 132 | +androidread(Chan *c, void *v, long n, vlong off) | |
| 133 | +{ | |
| 134 | + char *a = v; | |
| 135 | + long l; | |
| 136 | + const ASensor *sensor; | |
| 137 | + ASensorEventQueue *queue = NULL; | |
| 138 | + ASensorEvent data; | |
| 139 | + | |
| 140 | + switch((ulong)c->qid.path & 0xF) { | |
| 141 | + default: | |
| 142 | + error(Eperm); | |
| 143 | + return -1; | |
| 144 | + | |
| 145 | + case Qcam: | |
| 146 | + while(cambuf == nil) | |
| 147 | + usleep(10 * 1000); | |
| 148 | + | |
| 149 | + l = camlen - off; | |
| 150 | + if (l > n) | |
| 151 | + l = n; | |
| 152 | + | |
| 153 | + if (l > 0) | |
| 154 | + memcpy(a, cambuf + off, l); | |
| 155 | + | |
| 156 | + return l; | |
| 157 | + case Qaccel: | |
| 158 | + queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL); | |
| 159 | + if (queue == NULL) | |
| 160 | + return 0; | |
| 161 | + sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER); | |
| 162 | + if (sensor == NULL) { | |
| 163 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 164 | + return 0; | |
| 165 | + } | |
| 166 | + if (ASensorEventQueue_enableSensor(queue, sensor)) { | |
| 167 | + ASensorEventQueue_disableSensor(queue, sensor); | |
| 168 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 169 | + return 0; | |
| 170 | + } | |
| 171 | + l = 0; | |
| 172 | + if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) { | |
| 173 | + if (ASensorEventQueue_getEvents(queue, &data, 1)) { | |
| 174 | + l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z); | |
| 175 | + } | |
| 176 | + } | |
| 177 | + ASensorEventQueue_disableSensor(queue, sensor); | |
| 178 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 179 | + return l; | |
| 180 | + case Qcompass: | |
| 181 | + queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL); | |
| 182 | + if (queue == NULL) | |
| 183 | + return 0; | |
| 184 | + sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD); | |
| 185 | + if (sensor == NULL) { | |
| 186 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 187 | + return 0; | |
| 188 | + } | |
| 189 | + if (ASensorEventQueue_enableSensor(queue, sensor)) { | |
| 190 | + ASensorEventQueue_disableSensor(queue, sensor); | |
| 191 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 192 | + return 0; | |
| 193 | + } | |
| 194 | + l = 0; | |
| 195 | + if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) { | |
| 196 | + if (ASensorEventQueue_getEvents(queue, &data, 1)) { | |
| 197 | + l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z); | |
| 198 | + } | |
| 199 | + } | |
| 200 | + ASensorEventQueue_disableSensor(queue, sensor); | |
| 201 | + ASensorManager_destroyEventQueue(sensorManager, queue); | |
| 202 | + return l; | |
| 203 | + case Qdir: | |
| 204 | + return devdirread(c, a, n, 0, 0, androidgen); | |
| 205 | + } | |
| 206 | +} | |
| 207 | + | |
| 208 | +static long | |
| 209 | +androidwrite(Chan *c, void *vp, long n, vlong off) | |
| 210 | +{ | |
| 211 | + char *a = vp; | |
| 212 | + char *str; | |
| 213 | + | |
| 214 | + switch((ulong)c->qid.path) { | |
| 215 | + case Qnotification: | |
| 216 | + str = malloc(n+1); | |
| 217 | + memcpy(str, a, n); | |
| 218 | + str[n] = '\0'; | |
| 219 | + show_notification(str); | |
| 220 | + free(str); | |
| 221 | + return n; | |
| 222 | + default: | |
| 223 | + error(Eperm); | |
| 224 | + break; | |
| 225 | + } | |
| 226 | + return -1; | |
| 227 | +} | |
| 228 | + | |
| 229 | +Dev androiddevtab = { | |
| 230 | + 'N', | |
| 231 | + "android", | |
| 232 | + | |
| 233 | + devreset, | |
| 234 | + androidinit, | |
| 235 | + devshutdown, | |
| 236 | + androidattach, | |
| 237 | + androidwalk, | |
| 238 | + androidstat, | |
| 239 | + androidopen, | |
| 240 | + devcreate, | |
| 241 | + androidclose, | |
| 242 | + androidread, | |
| 243 | + devbread, | |
| 244 | + androidwrite, | |
| 245 | + devbwrite, | |
| 246 | + devremove, | |
| 247 | + devwstat, | |
| 248 | +}; | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +#include <jni.h> | |
| 2 | +#include <android/native_window.h> | |
| 3 | +#include <android/native_window_jni.h> | |
| 4 | +#include <android/log.h> | |
| 5 | +#include "u.h" | |
| 6 | +#include "lib.h" | |
| 7 | +#include "dat.h" | |
| 8 | +#include "fns.h" | |
| 9 | +#include "error.h" | |
| 10 | +#include <draw.h> | |
| 11 | +#include <string.h> | |
| 12 | +#include <keyboard.h> | |
| 13 | + | |
| 14 | +void absmousetrack(int, int, int, ulong); | |
| 15 | +ulong ticks(void); | |
| 16 | +int dt_main(int, char**); | |
| 17 | +int screenWidth; | |
| 18 | +int screenHeight; | |
| 19 | +Point mousept = {0, 0}; | |
| 20 | +int buttons = 0; | |
| 21 | +float ws = 1; | |
| 22 | +float hs = 1; | |
| 23 | +extern char *snarfbuf; | |
| 24 | +int mPaused = 0; | |
| 25 | +ANativeWindow *window = NULL; | |
| 26 | +jobject mainActivityObj; | |
| 27 | +JavaVM *jvm; | |
| 28 | +void flushmemscreen(Rectangle r); | |
| 29 | +extern uchar *cambuf; | |
| 30 | +extern int camlen; | |
| 31 | + | |
| 32 | +JNIEXPORT void JNICALL | |
| 33 | +Java_org_echoline_drawterm_MainActivity_setObject( | |
| 34 | + JNIEnv *env, | |
| 35 | + jobject obj) { | |
| 36 | + mainActivityObj = (*env)->NewGlobalRef(env, obj); | |
| 37 | + jint rs = (*env)->GetJavaVM(env, &jvm); | |
| 38 | + assert(rs == JNI_OK); | |
| 39 | +} | |
| 40 | + | |
| 41 | +JNIEXPORT void JNICALL | |
| 42 | +Java_org_echoline_drawterm_MainActivity_keyDown( | |
| 43 | + JNIEnv *env, | |
| 44 | + jobject obj, | |
| 45 | + jint c) { | |
| 46 | + kbdkey(c, 1); | |
| 47 | +} | |
| 48 | + | |
| 49 | +JNIEXPORT void JNICALL | |
| 50 | +Java_org_echoline_drawterm_MainActivity_keyUp( | |
| 51 | + JNIEnv *env, | |
| 52 | + jobject obj, | |
| 53 | + jint c) { | |
| 54 | + kbdkey(c, 0); | |
| 55 | +} | |
| 56 | + | |
| 57 | +JNIEXPORT void JNICALL | |
| 58 | +Java_org_echoline_drawterm_MainActivity_setPass( | |
| 59 | + JNIEnv *env, | |
| 60 | + jobject obj, | |
| 61 | + jstring str) { | |
| 62 | + setenv("PASS", (char*)(*env)->GetStringUTFChars(env, str, 0), 1); | |
| 63 | +} | |
| 64 | + | |
| 65 | +JNIEXPORT void JNICALL | |
| 66 | +Java_org_echoline_drawterm_MainActivity_setWidth( | |
| 67 | + JNIEnv *env, | |
| 68 | + jobject obj, | |
| 69 | + jint width) { | |
| 70 | + screenWidth = width; | |
| 71 | +} | |
| 72 | + | |
| 73 | +JNIEXPORT void JNICALL | |
| 74 | +Java_org_echoline_drawterm_MainActivity_setHeight( | |
| 75 | + JNIEnv *env, | |
| 76 | + jobject obj, | |
| 77 | + jint height) { | |
| 78 | + screenHeight = height; | |
| 79 | +} | |
| 80 | + | |
| 81 | +JNIEXPORT void JNICALL | |
| 82 | +Java_org_echoline_drawterm_MainActivity_setWidthScale( | |
| 83 | + JNIEnv *env, | |
| 84 | + jobject obj, | |
| 85 | + jfloat s) { | |
| 86 | + ws = s; | |
| 87 | +} | |
| 88 | + | |
| 89 | +JNIEXPORT void JNICALL | |
| 90 | +Java_org_echoline_drawterm_MainActivity_setHeightScale( | |
| 91 | + JNIEnv *env, | |
| 92 | + jobject obj, | |
| 93 | + jfloat s) { | |
| 94 | + hs = s; | |
| 95 | +} | |
| 96 | + | |
| 97 | +JNIEXPORT jint JNICALL | |
| 98 | +Java_org_echoline_drawterm_MainActivity_dtmain( | |
| 99 | + JNIEnv *env, | |
| 100 | + jobject obj, | |
| 101 | + jobjectArray argv) { | |
| 102 | + int i, ret; | |
| 103 | + char **args = (char **) malloc(((*env)->GetArrayLength(env, argv)+1) * sizeof(char *)); | |
| 104 | + | |
| 105 | + for (i = 0; i < (*env)->GetArrayLength(env, argv); i++) { | |
| 106 | + jobject str = (jobject) (*env)->GetObjectArrayElement(env, argv, i); | |
| 107 | + args[i] = strdup((char*)(*env)->GetStringUTFChars(env, (jstring)str, 0)); | |
| 108 | + } | |
| 109 | + args[(*env)->GetArrayLength(env, argv)] = NULL; | |
| 110 | + | |
| 111 | + ret = dt_main(i, args); | |
| 112 | + | |
| 113 | + for (i = 0; args[i] != NULL; i++) { | |
| 114 | + free(args[i]); | |
| 115 | + } | |
| 116 | + free(args); | |
| 117 | + | |
| 118 | + return ret; | |
| 119 | +} | |
| 120 | + | |
| 121 | +JNIEXPORT void JNICALL | |
| 122 | +Java_org_echoline_drawterm_MainActivity_setMouse( | |
| 123 | + JNIEnv *env, | |
| 124 | + jobject obj, | |
| 125 | + jintArray args) { | |
| 126 | + jboolean isCopy; | |
| 127 | + jint *data; | |
| 128 | + if ((*env)->GetArrayLength(env, args) < 3) | |
| 129 | + return; | |
| 130 | + data = (*env)->GetIntArrayElements(env, args, &isCopy); | |
| 131 | + mousept.x = (int)(data[0] / ws); | |
| 132 | + mousept.y = (int)(data[1] / hs); | |
| 133 | + buttons = data[2]; | |
| 134 | + (*env)->ReleaseIntArrayElements(env, args, data, 0); | |
| 135 | + absmousetrack(mousept.x, mousept.y, buttons, ticks()); | |
| 136 | +} | |
| 137 | + | |
| 138 | +JNIEXPORT void JNICALL | |
| 139 | +Java_org_echoline_drawterm_MainActivity_setDTSurface( | |
| 140 | + JNIEnv* jenv, | |
| 141 | + jobject obj, | |
| 142 | + jobject surface) { | |
| 143 | + if (surface != NULL) { | |
| 144 | + window = ANativeWindow_fromSurface(jenv, surface); | |
| 145 | + ANativeWindow_setBuffersGeometry(window, screenWidth, screenHeight, | |
| 146 | + AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM); | |
| 147 | + flushmemscreen(Rect(0, 0, screenWidth, screenHeight)); | |
| 148 | + } else if (window != NULL) { | |
| 149 | + ANativeWindow_release(window); | |
| 150 | + window = NULL; | |
| 151 | + } | |
| 152 | +} | |
| 153 | + | |
| 154 | +JNIEXPORT void JNICALL | |
| 155 | +Java_org_echoline_drawterm_MainActivity_exitDT( | |
| 156 | + JNIEnv* jenv, | |
| 157 | + jobject obj) { | |
| 158 | + exit(0); | |
| 159 | +} | |
| 160 | + | |
| 161 | +JNIEXPORT void JNICALL | |
| 162 | +Java_org_echoline_drawterm_MainActivity_sendPicture( | |
| 163 | + JNIEnv* env, | |
| 164 | + jobject obj, | |
| 165 | + jbyteArray array) { | |
| 166 | + jint len = (*env)->GetArrayLength(env, array); | |
| 167 | + jbyte *bytes = (*env)->GetByteArrayElements(env, array, NULL); | |
| 168 | + camlen = len; | |
| 169 | + cambuf = malloc(camlen); | |
| 170 | + memcpy(cambuf, bytes, camlen); | |
| 171 | + (*env)->ReleaseByteArrayElements(env, array, bytes, 0); | |
| 172 | +} | |
| 173 | + | |
| @@ -0,0 +1,32 @@ | ||
| 1 | +package org.echoline.drawterm; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Created by eli on 12/4/17. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +public class DrawTermThread extends Thread { | |
| 8 | + private MainActivity m; | |
| 9 | + private String p; | |
| 10 | + private String []args; | |
| 11 | + | |
| 12 | + public DrawTermThread(String []args, String p, MainActivity m) { | |
| 13 | + this.m = m; | |
| 14 | + this.p = p; | |
| 15 | + this.args = args; | |
| 16 | + } | |
| 17 | + | |
| 18 | + @Override | |
| 19 | + public void run() { | |
| 20 | + if (p != null && !p.equals("")) | |
| 21 | + m.setPass(p); | |
| 22 | + m.dtmain(args); | |
| 23 | + m.runOnUiThread(new Runnable() { | |
| 24 | + @Override | |
| 25 | + public void run() { | |
| 26 | + m.exitDT(); | |
| 27 | + m.setContentView(R.layout.server_main); | |
| 28 | + m.populateServers(m); | |
| 29 | + } | |
| 30 | + }); | |
| 31 | + } | |
| 32 | +} | |
| @@ -0,0 +1,437 @@ | ||
| 1 | +package org.echoline.drawterm; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.content.SharedPreferences; | |
| 5 | +import android.content.pm.ActivityInfo; | |
| 6 | +import android.content.res.Resources; | |
| 7 | +import android.graphics.Point; | |
| 8 | +import android.os.Bundle; | |
| 9 | +import android.os.Environment; | |
| 10 | + | |
| 11 | +import android.app.Activity; | |
| 12 | + | |
| 13 | +import android.app.Notification; | |
| 14 | +import android.app.NotificationManager; | |
| 15 | + | |
| 16 | +import android.util.DisplayMetrics; | |
| 17 | +import android.util.Log; | |
| 18 | +import android.view.Display; | |
| 19 | +import android.view.MotionEvent; | |
| 20 | +import android.view.View; | |
| 21 | +import android.view.Menu; | |
| 22 | +import android.view.MenuItem; | |
| 23 | +import android.view.WindowManager; | |
| 24 | +import android.view.Surface; | |
| 25 | +import android.view.inputmethod.InputMethodManager; | |
| 26 | +import android.view.KeyEvent; | |
| 27 | +import android.widget.ArrayAdapter; | |
| 28 | +import android.widget.Button; | |
| 29 | +import android.widget.EditText; | |
| 30 | +import android.widget.LinearLayout; | |
| 31 | +import android.widget.ListView; | |
| 32 | +import android.widget.TextView; | |
| 33 | +import android.content.ClipData; | |
| 34 | +import android.content.ClipboardManager; | |
| 35 | +import android.hardware.camera2.CameraManager; | |
| 36 | +import android.hardware.camera2.CameraAccessException; | |
| 37 | +import android.hardware.camera2.CameraDevice; | |
| 38 | +import android.hardware.camera2.CaptureRequest; | |
| 39 | +import android.hardware.camera2.CameraMetadata; | |
| 40 | +import android.hardware.camera2.CameraCaptureSession; | |
| 41 | +import android.hardware.camera2.TotalCaptureResult; | |
| 42 | +import android.media.Image; | |
| 43 | +import android.media.ImageReader; | |
| 44 | +import android.graphics.ImageFormat; | |
| 45 | +import android.os.Handler; | |
| 46 | +import android.os.HandlerThread; | |
| 47 | + | |
| 48 | +import java.io.File; | |
| 49 | +import java.util.Map; | |
| 50 | +import java.nio.ByteBuffer; | |
| 51 | +import java.util.List; | |
| 52 | +import java.util.ArrayList; | |
| 53 | + | |
| 54 | +public class MainActivity extends Activity { | |
| 55 | + private Map<String, ?> map; | |
| 56 | + private MainActivity mainActivity; | |
| 57 | + private boolean dtrunning = false; | |
| 58 | + private DrawTermThread dthread; | |
| 59 | + private int notificationId; | |
| 60 | + private CameraDevice cameraDevice = null; | |
| 61 | + private byte []jpegBytes; | |
| 62 | + | |
| 63 | + static { | |
| 64 | + System.loadLibrary("drawterm"); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public void showNotification(String text) { | |
| 68 | + Notification.Builder builder = new Notification.Builder(this) | |
| 69 | + .setDefaults(Notification.DEFAULT_SOUND) | |
| 70 | + .setSmallIcon(R.drawable.ic_small) | |
| 71 | + .setContentText(text) | |
| 72 | + .setStyle(new Notification.BigTextStyle().bigText(text)) | |
| 73 | + .setPriority(Notification.PRIORITY_DEFAULT); | |
| 74 | + | |
| 75 | + ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(notificationId, builder.build()); | |
| 76 | + notificationId++; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public int numCameras() { | |
| 80 | + try { | |
| 81 | + return ((CameraManager)getSystemService(Context.CAMERA_SERVICE)).getCameraIdList().length; | |
| 82 | + } catch (CameraAccessException e) { | |
| 83 | + Log.w("drawterm", e.toString()); | |
| 84 | + return 0; | |
| 85 | + } | |
| 86 | + } | |
| 87 | + | |
| 88 | + public void takePicture(int id) { | |
| 89 | + try { | |
| 90 | + HandlerThread mBackgroundThread = new HandlerThread("Camera Background"); | |
| 91 | + mBackgroundThread.start(); | |
| 92 | + Handler mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); | |
| 93 | + CameraManager manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE); | |
| 94 | + String []cameraIdList = manager.getCameraIdList(); | |
| 95 | + manager.openCamera(cameraIdList[id], new CameraDevice.StateCallback() { | |
| 96 | + public void onOpened(CameraDevice device) { | |
| 97 | + cameraDevice = device; | |
| 98 | + } | |
| 99 | + public void onDisconnected(CameraDevice device) { | |
| 100 | + if (cameraDevice != null) | |
| 101 | + cameraDevice.close(); | |
| 102 | + cameraDevice = null; | |
| 103 | + } | |
| 104 | + public void onError(CameraDevice device, int error) { | |
| 105 | + if (cameraDevice != null) | |
| 106 | + cameraDevice.close(); | |
| 107 | + cameraDevice = null; | |
| 108 | + } | |
| 109 | + }, mBackgroundHandler); | |
| 110 | + ImageReader reader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1); | |
| 111 | + CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); | |
| 112 | + captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); | |
| 113 | + captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); | |
| 114 | + captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON); | |
| 115 | + captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getWindowManager().getDefaultDisplay().getRotation()); | |
| 116 | + captureBuilder.addTarget(reader.getSurface()); | |
| 117 | + reader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { | |
| 118 | + public void onImageAvailable(ImageReader reader) { | |
| 119 | + Image image = null; | |
| 120 | + try { | |
| 121 | + image = reader.acquireLatestImage(); | |
| 122 | + ByteBuffer buffer = image.getPlanes()[0].getBuffer(); | |
| 123 | + jpegBytes = new byte[buffer.capacity()]; | |
| 124 | + buffer.get(jpegBytes); | |
| 125 | + } catch (Exception e) { | |
| 126 | + Log.w("drawterm", e.toString()); | |
| 127 | + } finally { | |
| 128 | + if (image != null) { | |
| 129 | + image.close(); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + } | |
| 133 | + }, mBackgroundHandler); | |
| 134 | + List<Surface> outputSurfaces = new ArrayList<Surface>(1); | |
| 135 | + outputSurfaces.add(reader.getSurface()); | |
| 136 | + cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { | |
| 137 | + public void onConfigured(CameraCaptureSession session) { | |
| 138 | + try { | |
| 139 | + List<CaptureRequest> captureRequests = new ArrayList<CaptureRequest>(10); | |
| 140 | + for (int i = 0; i < 10; i++) | |
| 141 | + captureRequests.add(captureBuilder.build()); | |
| 142 | + session.captureBurst(captureRequests, new CameraCaptureSession.CaptureCallback() { | |
| 143 | + public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) { | |
| 144 | + try { | |
| 145 | + sendPicture(jpegBytes); | |
| 146 | + mBackgroundThread.quitSafely(); | |
| 147 | + mBackgroundThread.join(); | |
| 148 | + } catch (Exception e) { | |
| 149 | + Log.w("drawterm", e.toString()); | |
| 150 | + } | |
| 151 | + } | |
| 152 | + }, mBackgroundHandler); | |
| 153 | + } catch (CameraAccessException e) { | |
| 154 | + e.printStackTrace(); | |
| 155 | + } | |
| 156 | + } | |
| 157 | + public void onConfigureFailed(CameraCaptureSession session) { | |
| 158 | + } | |
| 159 | + }, mBackgroundHandler); | |
| 160 | + } catch (Exception e) { | |
| 161 | + e.printStackTrace(); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + public void serverView(View v) { | |
| 166 | + setContentView(R.layout.server_main); | |
| 167 | + serverButtons(); | |
| 168 | + | |
| 169 | + String s = (String)map.get(((TextView)v).getText().toString()); | |
| 170 | + String []a = s.split("\007"); | |
| 171 | + | |
| 172 | + ((EditText)findViewById(R.id.cpuServer)).setText((String)a[0]); | |
| 173 | + ((EditText)findViewById(R.id.authServer)).setText((String)a[1]); | |
| 174 | + ((EditText)findViewById(R.id.userName)).setText((String)a[2]); | |
| 175 | + if (a.length > 3) | |
| 176 | + ((EditText)findViewById(R.id.passWord)).setText((String)a[3]); | |
| 177 | + } | |
| 178 | + | |
| 179 | + public void populateServers(Context context) { | |
| 180 | + ListView ll = (ListView)findViewById(R.id.servers); | |
| 181 | + ArrayAdapter<String> la = new ArrayAdapter<String>(this, R.layout.item_main); | |
| 182 | + SharedPreferences settings = getSharedPreferences("DrawtermPrefs", 0); | |
| 183 | + map = (Map<String, ?>)settings.getAll(); | |
| 184 | + String key; | |
| 185 | + Object []keys = map.keySet().toArray(); | |
| 186 | + for (int i = 0; i < keys.length; i++) { | |
| 187 | + key = (String)keys[i]; | |
| 188 | + la.add(key); | |
| 189 | + } | |
| 190 | + ll.setAdapter(la); | |
| 191 | + | |
| 192 | + setDTSurface(null); | |
| 193 | + dtrunning = false; | |
| 194 | + } | |
| 195 | + | |
| 196 | + public void runDrawterm(String []args, String pass) { | |
| 197 | + Resources res = getResources(); | |
| 198 | + DisplayMetrics dm = res.getDisplayMetrics(); | |
| 199 | + | |
| 200 | + int wp = dm.widthPixels; | |
| 201 | + int hp = dm.heightPixels; | |
| 202 | + | |
| 203 | + setContentView(R.layout.drawterm_main); | |
| 204 | + | |
| 205 | + Button kbutton = (Button)findViewById(R.id.keyboardToggle); | |
| 206 | + kbutton.setOnClickListener(new View.OnClickListener() { | |
| 207 | + @Override | |
| 208 | + public void onClick(final View view) { | |
| 209 | + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); | |
| 210 | + imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); | |
| 211 | + } | |
| 212 | + }); | |
| 213 | + | |
| 214 | + int rid = res.getIdentifier("navigation_bar_height", "dimen", "android"); | |
| 215 | + if (rid > 0) { | |
| 216 | + hp -= res.getDimensionPixelSize(rid); | |
| 217 | + } | |
| 218 | + LinearLayout ll = (LinearLayout)findViewById(R.id.dtButtons); | |
| 219 | + hp -= ll.getHeight(); | |
| 220 | + | |
| 221 | + int w = (int)(wp * (160.0/dm.xdpi)); | |
| 222 | + int h = (int)(hp * (160.0/dm.ydpi)); | |
| 223 | + float ws = (float)wp/w; | |
| 224 | + float hs = (float)hp/h; | |
| 225 | + // only scale up | |
| 226 | + if (ws < 1) { | |
| 227 | + ws = 1; | |
| 228 | + w = wp; | |
| 229 | + } | |
| 230 | + if (hs < 1) { | |
| 231 | + hs = 1; | |
| 232 | + h = hp; | |
| 233 | + } | |
| 234 | + | |
| 235 | + MySurfaceView mView = new MySurfaceView(mainActivity, w, h, ws, hs); | |
| 236 | + mView.getHolder().setFixedSize(w, h); | |
| 237 | + | |
| 238 | + LinearLayout l = (LinearLayout)findViewById(R.id.dlayout); | |
| 239 | + l.addView(mView, 1, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); | |
| 240 | + | |
| 241 | + dthread = new DrawTermThread(args, pass, mainActivity); | |
| 242 | + dthread.start(); | |
| 243 | + | |
| 244 | + dtrunning = true; | |
| 245 | + } | |
| 246 | + | |
| 247 | + public void serverButtons() { | |
| 248 | + Button button = (Button)findViewById(R.id.save); | |
| 249 | + button.setOnClickListener(new View.OnClickListener() { | |
| 250 | + @Override | |
| 251 | + public void onClick(View v) { | |
| 252 | + String cpu = ((EditText)findViewById(R.id.cpuServer)).getText().toString(); | |
| 253 | + String auth = ((EditText)findViewById(R.id.authServer)).getText().toString(); | |
| 254 | + String user = ((EditText)findViewById(R.id.userName)).getText().toString(); | |
| 255 | + String pass = ((EditText)findViewById(R.id.passWord)).getText().toString(); | |
| 256 | + | |
| 257 | + SharedPreferences settings = getSharedPreferences("DrawtermPrefs", 0); | |
| 258 | + SharedPreferences.Editor editor = settings.edit(); | |
| 259 | + editor.putString(user + "@" + cpu + " (auth=" + auth + ")", cpu + "\007" + auth + "\007" + user + "\007" + pass); | |
| 260 | + editor.commit(); | |
| 261 | + } | |
| 262 | + }); | |
| 263 | + | |
| 264 | + button = (Button) findViewById(R.id.connect); | |
| 265 | + button.setOnClickListener(new View.OnClickListener() { | |
| 266 | + @Override | |
| 267 | + public void onClick(final View view) { | |
| 268 | + String cpu = ((EditText)findViewById(R.id.cpuServer)).getText().toString(); | |
| 269 | + String auth = ((EditText)findViewById(R.id.authServer)).getText().toString(); | |
| 270 | + String user = ((EditText)findViewById(R.id.userName)).getText().toString(); | |
| 271 | + String pass = ((EditText)findViewById(R.id.passWord)).getText().toString(); | |
| 272 | + | |
| 273 | + String args[] = {"drawterm", "-p", "-h", cpu, "-a", auth, "-u", user}; | |
| 274 | + runDrawterm(args, pass); | |
| 275 | + } | |
| 276 | + }); | |
| 277 | + } | |
| 278 | + | |
| 279 | + @Override | |
| 280 | + protected void onCreate(Bundle savedInstanceState) { | |
| 281 | + super.onCreate(savedInstanceState); | |
| 282 | + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); | |
| 283 | + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | |
| 284 | + | |
| 285 | + mainActivity = this; | |
| 286 | + setObject(); | |
| 287 | + setContentView(R.layout.activity_main); | |
| 288 | + populateServers(this); | |
| 289 | + | |
| 290 | + View fab = findViewById(R.id.fab); | |
| 291 | + fab.setOnClickListener(new View.OnClickListener() { | |
| 292 | + @Override | |
| 293 | + public void onClick(View v) { | |
| 294 | + setContentView(R.layout.server_main); | |
| 295 | + serverButtons(); | |
| 296 | + } | |
| 297 | + }); | |
| 298 | + } | |
| 299 | + | |
| 300 | + @Override | |
| 301 | + public boolean dispatchKeyEvent(KeyEvent event) | |
| 302 | + { | |
| 303 | + if (!dtrunning) { | |
| 304 | + return super.dispatchKeyEvent(event); | |
| 305 | + } | |
| 306 | + | |
| 307 | + int k = event.getUnicodeChar(); | |
| 308 | + if (k == 0) { | |
| 309 | + k = event.getDisplayLabel(); | |
| 310 | + if (k >= 'A' && k <= 'Z') | |
| 311 | + k |= 0x20; | |
| 312 | + } | |
| 313 | + String chars = event.getCharacters(); | |
| 314 | + if (k == 0 && chars != null) { | |
| 315 | + for (int i = 0; i < chars.length(); i++) { | |
| 316 | + k = chars.codePointAt(i); | |
| 317 | + keyDown(k); | |
| 318 | + keyUp(k); | |
| 319 | + } | |
| 320 | + return true; | |
| 321 | + } | |
| 322 | + | |
| 323 | + if (k == 0) switch (event.getKeyCode()) { | |
| 324 | + case KeyEvent.KEYCODE_DEL: | |
| 325 | + k = 0x0008; | |
| 326 | + break; | |
| 327 | + case KeyEvent.KEYCODE_FORWARD_DEL: | |
| 328 | + k = 0x007F; | |
| 329 | + break; | |
| 330 | + case KeyEvent.KEYCODE_ESCAPE: | |
| 331 | + k = 0x001B; | |
| 332 | + break; | |
| 333 | + case KeyEvent.KEYCODE_MOVE_HOME: | |
| 334 | + k = 0xF00D; | |
| 335 | + break; | |
| 336 | + case KeyEvent.KEYCODE_MOVE_END: | |
| 337 | + k = 0xF018; | |
| 338 | + break; | |
| 339 | + case KeyEvent.KEYCODE_PAGE_UP: | |
| 340 | + k = 0xF00F; | |
| 341 | + break; | |
| 342 | + case KeyEvent.KEYCODE_PAGE_DOWN: | |
| 343 | + k = 0xF013; | |
| 344 | + break; | |
| 345 | + case KeyEvent.KEYCODE_INSERT: | |
| 346 | + k = 0xF014; | |
| 347 | + break; | |
| 348 | + case KeyEvent.KEYCODE_SYSRQ: | |
| 349 | + k = 0xF010; | |
| 350 | + break; | |
| 351 | + case KeyEvent.KEYCODE_DPAD_UP: | |
| 352 | + k = 0xF00E; | |
| 353 | + break; | |
| 354 | + case KeyEvent.KEYCODE_DPAD_LEFT: | |
| 355 | + k = 0xF011; | |
| 356 | + break; | |
| 357 | + case KeyEvent.KEYCODE_DPAD_RIGHT: | |
| 358 | + k = 0xF012; | |
| 359 | + break; | |
| 360 | + case KeyEvent.KEYCODE_DPAD_DOWN: | |
| 361 | + k = 0xF800; | |
| 362 | + break; | |
| 363 | + } | |
| 364 | + | |
| 365 | + if (k == 0) | |
| 366 | + return true; | |
| 367 | + | |
| 368 | + if (event.isCtrlPressed()) { | |
| 369 | + keyDown(0xF017); | |
| 370 | + } | |
| 371 | + if (event.isAltPressed() && k < 128) { | |
| 372 | + keyDown(0xF015); | |
| 373 | + } | |
| 374 | + | |
| 375 | + if (event.getAction() == KeyEvent.ACTION_DOWN) { | |
| 376 | + keyDown(k); | |
| 377 | + } | |
| 378 | + else if (event.getAction() == KeyEvent.ACTION_UP) { | |
| 379 | + keyUp(k); | |
| 380 | + } | |
| 381 | + | |
| 382 | + if (event.isCtrlPressed()) { | |
| 383 | + keyUp(0xF017); | |
| 384 | + } | |
| 385 | + if (event.isAltPressed() && k < 128) { | |
| 386 | + keyUp(0xF015); | |
| 387 | + } | |
| 388 | + | |
| 389 | + return true; | |
| 390 | + } | |
| 391 | + | |
| 392 | + @Override | |
| 393 | + public void onBackPressed() | |
| 394 | + { | |
| 395 | + } | |
| 396 | + | |
| 397 | + @Override | |
| 398 | + public void onDestroy() | |
| 399 | + { | |
| 400 | + setDTSurface(null); | |
| 401 | + dtrunning = false; | |
| 402 | + exitDT(); | |
| 403 | + super.onDestroy(); | |
| 404 | + } | |
| 405 | + | |
| 406 | + public void setClipBoard(String str) { | |
| 407 | + ClipboardManager cm = (ClipboardManager)getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); | |
| 408 | + if (cm != null) { | |
| 409 | + ClipData cd = ClipData.newPlainText(null, str); | |
| 410 | + cm.setPrimaryClip(cd); | |
| 411 | + } | |
| 412 | + } | |
| 413 | + | |
| 414 | + public String getClipBoard() { | |
| 415 | + ClipboardManager cm = (ClipboardManager)getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); | |
| 416 | + if (cm != null) { | |
| 417 | + ClipData cd = cm.getPrimaryClip(); | |
| 418 | + if (cd != null) | |
| 419 | + return (String)(cd.getItemAt(0).coerceToText(mainActivity.getApplicationContext()).toString()); | |
| 420 | + } | |
| 421 | + return ""; | |
| 422 | + } | |
| 423 | + | |
| 424 | + public native void dtmain(Object[] args); | |
| 425 | + public native void setPass(String arg); | |
| 426 | + public native void setWidth(int arg); | |
| 427 | + public native void setHeight(int arg); | |
| 428 | + public native void setWidthScale(float arg); | |
| 429 | + public native void setHeightScale(float arg); | |
| 430 | + public native void setDTSurface(Surface surface); | |
| 431 | + public native void setMouse(int[] args); | |
| 432 | + public native void setObject(); | |
| 433 | + public native void keyDown(int c); | |
| 434 | + public native void keyUp(int c); | |
| 435 | + public native void exitDT(); | |
| 436 | + public native void sendPicture(byte[] array); | |
| 437 | +} | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +package org.echoline.drawterm; | |
| 2 | + | |
| 3 | +import android.util.Log; | |
| 4 | + | |
| 5 | +import android.content.Context; | |
| 6 | +import android.graphics.Bitmap; | |
| 7 | +import android.os.SystemClock; | |
| 8 | +import android.view.MotionEvent; | |
| 9 | +import android.view.SurfaceView; | |
| 10 | +import android.view.SurfaceHolder; | |
| 11 | +import android.view.View; | |
| 12 | +import android.widget.CheckBox; | |
| 13 | +import android.widget.EditText; | |
| 14 | + | |
| 15 | +import java.nio.ByteBuffer; | |
| 16 | +import java.nio.IntBuffer; | |
| 17 | +import java.security.spec.ECField; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * Created by eli on 12/3/17. | |
| 21 | + */ | |
| 22 | +public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { | |
| 23 | + private int screenWidth, screenHeight; | |
| 24 | + private MainActivity mainActivity; | |
| 25 | + private float ws, hs; | |
| 26 | + | |
| 27 | + public MySurfaceView(Context context, int w, int h, float ws, float hs) { | |
| 28 | + super(context); | |
| 29 | + screenHeight = h; | |
| 30 | + screenWidth = w; | |
| 31 | + this.ws = ws; | |
| 32 | + this.hs = hs; | |
| 33 | + mainActivity = (MainActivity)context; | |
| 34 | + mainActivity.setWidth(screenWidth); | |
| 35 | + mainActivity.setHeight(screenHeight); | |
| 36 | + mainActivity.setWidthScale(ws); | |
| 37 | + mainActivity.setHeightScale(hs); | |
| 38 | + setWillNotDraw(true); | |
| 39 | + | |
| 40 | + getHolder().addCallback(this); | |
| 41 | + | |
| 42 | + setOnTouchListener(new View.OnTouchListener() { | |
| 43 | + private int[] mouse = new int[3]; | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + public boolean onTouch(View v, MotionEvent event) { | |
| 47 | + CheckBox left = (CheckBox)mainActivity.findViewById(R.id.mouseLeft); | |
| 48 | + CheckBox middle = (CheckBox)mainActivity.findViewById(R.id.mouseMiddle); | |
| 49 | + CheckBox right = (CheckBox)mainActivity.findViewById(R.id.mouseRight); | |
| 50 | + CheckBox up = (CheckBox)mainActivity.findViewById(R.id.mouseUp); | |
| 51 | + CheckBox down = (CheckBox)mainActivity.findViewById(R.id.mouseDown); | |
| 52 | + int buttons = (left.isChecked()? 1: 0) | | |
| 53 | + (middle.isChecked()? 2: 0) | | |
| 54 | + (right.isChecked()? 4: 0) | | |
| 55 | + (up.isChecked()? 8: 0) | | |
| 56 | + (down.isChecked()? 16: 0); | |
| 57 | + if (event.getAction() == MotionEvent.ACTION_DOWN) { | |
| 58 | + mouse[0] = Math.round(event.getX()); | |
| 59 | + mouse[1] = Math.round(event.getY()); | |
| 60 | + mouse[2] = buttons; | |
| 61 | + mainActivity.setMouse(mouse); | |
| 62 | + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { | |
| 63 | + mouse[0] = Math.round(event.getX()); | |
| 64 | + mouse[1] = Math.round(event.getY()); | |
| 65 | + mouse[2] = buttons; | |
| 66 | + mainActivity.setMouse(mouse); | |
| 67 | + } else if (event.getAction() == MotionEvent.ACTION_UP) { | |
| 68 | + mouse[0] = Math.round(event.getX()); | |
| 69 | + mouse[1] = Math.round(event.getY()); | |
| 70 | + mouse[2] = 0; | |
| 71 | + mainActivity.setMouse(mouse); | |
| 72 | + } | |
| 73 | + return true; | |
| 74 | + } | |
| 75 | + }); | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Override | |
| 79 | + public void surfaceCreated(SurfaceHolder holder) { | |
| 80 | + mainActivity.setDTSurface(holder.getSurface()); | |
| 81 | + } | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public void surfaceChanged(SurfaceHolder holder, int w, int h, int format) { | |
| 85 | + } | |
| 86 | + | |
| 87 | + @Override | |
| 88 | + public void surfaceDestroyed(SurfaceHolder holder) { | |
| 89 | + mainActivity.setDTSurface(null); | |
| 90 | + } | |
| 91 | +} | |
| @@ -0,0 +1,24 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<android.widget.FrameLayout | |
| 3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
| 4 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
| 5 | + xmlns:tools="http://schemas.android.com/tools" | |
| 6 | + android:layout_width="match_parent" | |
| 7 | + android:layout_height="match_parent" | |
| 8 | + tools:context="org.echoline.drawterm.MainActivity"> | |
| 9 | + | |
| 10 | + <include layout="@layout/content_main" /> | |
| 11 | + | |
| 12 | + <LinearLayout | |
| 13 | + android:layout_width="wrap_content" | |
| 14 | + android:layout_height="wrap_content" | |
| 15 | + android:layout_gravity="bottom|end"> | |
| 16 | + | |
| 17 | + <Button | |
| 18 | + android:id="@+id/fab" | |
| 19 | + android:text="add server" | |
| 20 | + android:layout_width="wrap_content" | |
| 21 | + android:layout_height="wrap_content"/> | |
| 22 | + </LinearLayout> | |
| 23 | + | |
| 24 | +</android.widget.FrameLayout> | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<android.widget.FrameLayout | |
| 3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
| 4 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
| 5 | + xmlns:tools="http://schemas.android.com/tools" | |
| 6 | + android:layout_width="match_parent" | |
| 7 | + android:layout_height="match_parent" | |
| 8 | + tools:context="org.echoline.drawterm.MainActivity" | |
| 9 | + tools:showIn="@layout/activity_main"> | |
| 10 | + <ListView | |
| 11 | + android:id="@+id/servers" | |
| 12 | + android:layout_width="match_parent" | |
| 13 | + android:layout_height="match_parent" | |
| 14 | + android:orientation="vertical"> | |
| 15 | + </ListView> | |
| 16 | +</android.widget.FrameLayout> | |
| @@ -0,0 +1,44 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:tools="http://schemas.android.com/tools" | |
| 4 | + android:id="@+id/dlayout" | |
| 5 | + android:layout_width="match_parent" | |
| 6 | + android:layout_height="match_parent" | |
| 7 | + android:orientation="vertical" | |
| 8 | + tools:context="org.echoline.drawterm.MainActivity"> | |
| 9 | + | |
| 10 | + <LinearLayout | |
| 11 | + android:layout_width="match_parent" | |
| 12 | + android:layout_height="wrap_content" | |
| 13 | + android:layout_gravity="bottom" | |
| 14 | + android:gravity="center_horizontal" | |
| 15 | + android:orientation="horizontal" | |
| 16 | + android:id="@+id/dtButtons"> | |
| 17 | + | |
| 18 | + <CheckBox | |
| 19 | + android:id="@+id/mouseLeft" | |
| 20 | + android:layout_width="wrap_content" | |
| 21 | + android:layout_height="match_parent" /> | |
| 22 | + <CheckBox | |
| 23 | + android:id="@+id/mouseMiddle" | |
| 24 | + android:layout_width="wrap_content" | |
| 25 | + android:layout_height="match_parent" /> | |
| 26 | + <CheckBox | |
| 27 | + android:id="@+id/mouseRight" | |
| 28 | + android:layout_width="wrap_content" | |
| 29 | + android:layout_height="match_parent" /> | |
| 30 | + <CheckBox | |
| 31 | + android:id="@+id/mouseUp" | |
| 32 | + android:layout_width="wrap_content" | |
| 33 | + android:layout_height="match_parent" /> | |
| 34 | + <CheckBox | |
| 35 | + android:id="@+id/mouseDown" | |
| 36 | + android:layout_width="wrap_content" | |
| 37 | + android:layout_height="match_parent" /> | |
| 38 | + <Button | |
| 39 | + android:id="@+id/keyboardToggle" | |
| 40 | + android:text="kb" | |
| 41 | + android:layout_width="wrap_content" | |
| 42 | + android:layout_height="wrap_content" /> | |
| 43 | + </LinearLayout> | |
| 44 | +</LinearLayout> | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<TextView xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:layout_width="match_parent" android:layout_height="match_parent" | |
| 4 | + android:padding="10dp" | |
| 5 | + android:textSize="16sp" | |
| 6 | + android:onClick="serverView"> | |
| 7 | +</TextView> | |
| 8 | + | |
| @@ -0,0 +1,56 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<android.widget.FrameLayout | |
| 3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
| 4 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
| 5 | + xmlns:tools="http://schemas.android.com/tools" | |
| 6 | + android:layout_width="match_parent" | |
| 7 | + android:layout_height="match_parent" | |
| 8 | + tools:context="org.echoline.drawterm.MainActivity"> | |
| 9 | + | |
| 10 | + <LinearLayout | |
| 11 | + android:layout_height="match_parent" | |
| 12 | + android:layout_width="match_parent" | |
| 13 | + android:orientation="vertical"> | |
| 14 | + | |
| 15 | + <EditText | |
| 16 | + android:id="@+id/cpuServer" | |
| 17 | + android:layout_width="match_parent" | |
| 18 | + android:layout_height="wrap_content" | |
| 19 | + android:ems="10" | |
| 20 | + android:hint="CPU" /> | |
| 21 | + <EditText | |
| 22 | + android:id="@+id/authServer" | |
| 23 | + android:layout_width="match_parent" | |
| 24 | + android:layout_height="wrap_content" | |
| 25 | + android:ems="10" | |
| 26 | + android:hint="Auth" /> | |
| 27 | + <EditText | |
| 28 | + android:id="@+id/userName" | |
| 29 | + android:layout_width="match_parent" | |
| 30 | + android:layout_height="wrap_content" | |
| 31 | + android:ems="10" | |
| 32 | + android:hint="Username" /> | |
| 33 | + | |
| 34 | + <EditText | |
| 35 | + android:id="@+id/passWord" | |
| 36 | + android:layout_width="match_parent" | |
| 37 | + android:layout_height="wrap_content" | |
| 38 | + android:ems="10" | |
| 39 | + android:password="true" | |
| 40 | + android:hint="Password"/> | |
| 41 | + | |
| 42 | + <Button | |
| 43 | + android:id="@+id/save" | |
| 44 | + android:layout_width="match_parent" | |
| 45 | + android:layout_height="wrap_content" | |
| 46 | + android:text="Save" /> | |
| 47 | + | |
| 48 | + <Button | |
| 49 | + android:id="@+id/connect" | |
| 50 | + android:layout_width="match_parent" | |
| 51 | + android:layout_height="wrap_content" | |
| 52 | + android:text="Connect" /> | |
| 53 | + | |
| 54 | + </LinearLayout> | |
| 55 | + | |
| 56 | +</android.widget.FrameLayout> | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<resources> | |
| 3 | + <color name="colorPrimary">#3F51B5</color> | |
| 4 | + <color name="colorPrimaryDark">#303F9F</color> | |
| 5 | + <color name="colorAccent">#3FB551</color> | |
| 6 | +</resources> | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +<resources> | |
| 2 | + <string name="app_name">Drawterm</string> | |
| 3 | +</resources> | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +<resources> | |
| 2 | + | |
| 3 | + <!-- Base application theme. --> | |
| 4 | + <style name="AppTheme" parent="android:Theme.NoTitleBar"> | |
| 5 | + <!-- Customize your theme here. --> | |
| 6 | + </style> | |
| 7 | + | |
| 8 | +</resources> | |
| @@ -0,0 +1,12 @@ | ||
| 1 | +ROOT=.. | |
| 2 | +include ../Make.config | |
| 3 | +LIB=libgui.a | |
| 4 | + | |
| 5 | +OFILES=\ | |
| 6 | + fbdev.$O\ | |
| 7 | + | |
| 8 | +default: $(LIB) | |
| 9 | +$(LIB): $(OFILES) | |
| 10 | + $(AR) r $(LIB) $(OFILES) | |
| 11 | + $(RANLIB) $(LIB) | |
| 12 | + | |
| @@ -0,0 +1,673 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include <draw.h> | |
| 8 | +#include <memdraw.h> | |
| 9 | +#include <keyboard.h> | |
| 10 | +#include <cursor.h> | |
| 11 | +#include "screen.h" | |
| 12 | + | |
| 13 | +#undef long | |
| 14 | +#undef ulong | |
| 15 | + | |
| 16 | +#include <linux/fb.h> | |
| 17 | +#include <linux/input.h> | |
| 18 | + | |
| 19 | +uchar* fbp; | |
| 20 | +Memimage* screenimage; | |
| 21 | +Memimage* backbuf; | |
| 22 | +Rectangle screenr; | |
| 23 | +char* snarfbuf; | |
| 24 | +struct fb_fix_screeninfo finfo; | |
| 25 | +struct fb_var_screeninfo vinfo; | |
| 26 | +int *eventfds = NULL; | |
| 27 | +int neventfds; | |
| 28 | +Point mousexy; | |
| 29 | +char shift_state; | |
| 30 | +int ttyfd; | |
| 31 | +char* tty; | |
| 32 | +char hidden; | |
| 33 | +int devicesfd; | |
| 34 | +ulong chan; | |
| 35 | +int depth; | |
| 36 | + | |
| 37 | +#include <sys/ioctl.h> | |
| 38 | +#include <sys/mman.h> | |
| 39 | +#include <limits.h> | |
| 40 | + | |
| 41 | +#include <fcntl.h> | |
| 42 | +#include <termios.h> | |
| 43 | +#include <poll.h> | |
| 44 | +#include <sys/ioctl.h> | |
| 45 | +#include <linux/keyboard.h> | |
| 46 | +#include <signal.h> | |
| 47 | + | |
| 48 | +#include <termios.h> | |
| 49 | + | |
| 50 | +#define ulong p9_ulong | |
| 51 | + | |
| 52 | +int code2key[] = { | |
| 53 | + Kesc, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\x08', | |
| 54 | + '\x09', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', | |
| 55 | + Kctl, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', Kshift, | |
| 56 | + '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', Kshift, '*', Kalt, | |
| 57 | + ' ', Kcaps, KF|1, KF|2, KF|3, KF|4, KF|5, KF|6, KF|7, KF|8, KF|9, KF|10, | |
| 58 | + Knum, Kscroll, | |
| 59 | + '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.', | |
| 60 | +}; | |
| 61 | + | |
| 62 | +int code2key_shift[] = { | |
| 63 | + Kesc, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\x08', | |
| 64 | + '\x09', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', | |
| 65 | + Kctl, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', '~', Kshift, | |
| 66 | + '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', Kshift, '*', Kalt, | |
| 67 | + ' ', Kcaps, KF|1, KF|2, KF|3, KF|4, KF|5, KF|6, KF|7, KF|8, KF|9, KF|10, | |
| 68 | + Knum, Kscroll, | |
| 69 | + '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.', | |
| 70 | +}; | |
| 71 | + | |
| 72 | +Memimage *gscreen; | |
| 73 | +char *snarfbuf = nil; | |
| 74 | + | |
| 75 | +int onevent(struct input_event*); | |
| 76 | +void termctl(uint32_t o, int or); | |
| 77 | +void ctrlc(int sig); | |
| 78 | + | |
| 79 | +void | |
| 80 | +_fbput(Memimage *m, Rectangle r) { | |
| 81 | + int y; | |
| 82 | + | |
| 83 | + for (y = r.min.y; y < r.max.y; y++){ | |
| 84 | + long loc = y * finfo.line_length + r.min.x * depth; | |
| 85 | + void *ptr = m->data->bdata + y * m->width * 4 + r.min.x * depth; | |
| 86 | + | |
| 87 | + memcpy(fbp + loc, ptr, Dx(r) * depth); | |
| 88 | + } | |
| 89 | +} | |
| 90 | + | |
| 91 | +Memimage* | |
| 92 | +fbattach(int fbdevidx) | |
| 93 | +{ | |
| 94 | + Rectangle r; | |
| 95 | + char devname[64]; | |
| 96 | + size_t size; | |
| 97 | + int fd; | |
| 98 | + | |
| 99 | + /* | |
| 100 | + * Connect to /dev/fb0 | |
| 101 | + */ | |
| 102 | + snprintf(devname, sizeof(devname) - 1, "/dev/fb%d", fbdevidx); | |
| 103 | + if ((fd = open(devname, O_RDWR)) < 0) | |
| 104 | + goto err; | |
| 105 | + | |
| 106 | + if (ioctl(fd, FBIOGET_VSCREENINFO, &(vinfo)) < 0) | |
| 107 | + goto err; | |
| 108 | + | |
| 109 | + switch (vinfo.bits_per_pixel) { | |
| 110 | + case 32: | |
| 111 | + chan = XRGB32; | |
| 112 | + depth = 4; | |
| 113 | + break; | |
| 114 | + case 16: | |
| 115 | + chan = RGB16; | |
| 116 | + depth = 2; | |
| 117 | + break; | |
| 118 | + default: | |
| 119 | + goto err; | |
| 120 | + } | |
| 121 | + | |
| 122 | + if (ioctl(fd, FBIOGET_FSCREENINFO, &(finfo)) < 0) | |
| 123 | + goto err; | |
| 124 | + | |
| 125 | + size = vinfo.yres_virtual * finfo.line_length; | |
| 126 | + if ((fbp = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) < 0) | |
| 127 | + goto err; | |
| 128 | + /* | |
| 129 | + * Figure out underlying screen format. | |
| 130 | + */ | |
| 131 | + r = Rect(0, 0, vinfo.xres_virtual, vinfo.yres_virtual); | |
| 132 | + | |
| 133 | + screenr = r; | |
| 134 | + | |
| 135 | + screenimage = allocmemimage(r, chan); | |
| 136 | + backbuf = allocmemimage(r, chan); | |
| 137 | + return backbuf; | |
| 138 | + | |
| 139 | +err: | |
| 140 | + return nil; | |
| 141 | +} | |
| 142 | + | |
| 143 | +int | |
| 144 | +eventattach() | |
| 145 | +{ | |
| 146 | + char eventfile[PATH_MAX] = ""; | |
| 147 | + char line[PATH_MAX]; | |
| 148 | + FILE *devices; | |
| 149 | + char *ptr; | |
| 150 | + | |
| 151 | + neventfds = 0; | |
| 152 | + devices = fopen("/proc/bus/input/devices", "r"); | |
| 153 | + if (devices == NULL) | |
| 154 | + return -1; | |
| 155 | + while (fgets(line, sizeof(line)-1, devices) != NULL) | |
| 156 | + if (line[0] == 'H') { | |
| 157 | + ptr = strstr(line, "event"); | |
| 158 | + if (ptr == NULL) | |
| 159 | + continue; | |
| 160 | + ptr[strcspn(ptr, " \r\n")] = '\0'; | |
| 161 | + snprintf(eventfile, sizeof(eventfile)-1, "/dev/input/%s", ptr); | |
| 162 | + neventfds++; | |
| 163 | + eventfds = realloc(eventfds, neventfds * sizeof(int)); | |
| 164 | + eventfds[neventfds-1] = open(eventfile, O_RDONLY); | |
| 165 | + if (eventfds[neventfds-1] < 0) | |
| 166 | + neventfds--; | |
| 167 | + } | |
| 168 | + fclose(devices); | |
| 169 | + | |
| 170 | + if (neventfds == 0) | |
| 171 | + return -1; | |
| 172 | + return 1; | |
| 173 | +} | |
| 174 | + | |
| 175 | +void | |
| 176 | +flushmemscreen(Rectangle r) | |
| 177 | +{ | |
| 178 | + int x, y, i; | |
| 179 | + Point p; | |
| 180 | + long fbloc; | |
| 181 | + int x2, y2; | |
| 182 | + | |
| 183 | + if (rectclip(&r, screenimage->r) == 0) | |
| 184 | + return; | |
| 185 | + if (Dx(r) == 0 || Dy(r) == 0) | |
| 186 | + return; | |
| 187 | + | |
| 188 | + assert(!canqlock(&drawlock)); | |
| 189 | + | |
| 190 | + memimagedraw(screenimage, r, backbuf, r.min, nil, r.min, S); | |
| 191 | + | |
| 192 | + if (hidden != 0) | |
| 193 | + return; | |
| 194 | + | |
| 195 | + p = mousexy; | |
| 196 | + | |
| 197 | + // draw cursor | |
| 198 | + for (x = 0; x < 16; x++) { | |
| 199 | + x2 = x + cursor.offset.x; | |
| 200 | + | |
| 201 | + if ((p.x + x2) < 0) | |
| 202 | + continue; | |
| 203 | + | |
| 204 | + if ((p.x + x2) >= screenimage->r.max.x) | |
| 205 | + break; | |
| 206 | + | |
| 207 | + for (y = 0; y < 16; y++) { | |
| 208 | + y2 = y + cursor.offset.y; | |
| 209 | + | |
| 210 | + if ((p.y + y2) < 0) | |
| 211 | + continue; | |
| 212 | + | |
| 213 | + if ((p.y + y2) >= screenimage->r.max.y) | |
| 214 | + break; | |
| 215 | + | |
| 216 | + i = y * 2 + x / 8; | |
| 217 | + fbloc = ((p.y+y2) * screenimage->r.max.x + (p.x+x2)) * depth; | |
| 218 | + | |
| 219 | + if (cursor.clr[i] & (128 >> (x % 8))) { | |
| 220 | + switch (depth) { | |
| 221 | + case 2: | |
| 222 | + *((uint16_t*)(screenimage->data->bdata + fbloc)) = 0xFFFF; | |
| 223 | + break; | |
| 224 | + case 4: | |
| 225 | + *((uint32_t*)(screenimage->data->bdata + fbloc)) = 0xFFFFFFFF; | |
| 226 | + break; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + | |
| 230 | + if (cursor.set[i] & (128 >> (x % 8))) { | |
| 231 | + switch (depth) { | |
| 232 | + case 2: | |
| 233 | + *((uint16_t*)(screenimage->data->bdata + fbloc)) = 0x0000; | |
| 234 | + break; | |
| 235 | + case 4: | |
| 236 | + *((uint32_t*)(screenimage->data->bdata + fbloc)) = 0xFF000000; | |
| 237 | + break; | |
| 238 | + } | |
| 239 | + } | |
| 240 | + } | |
| 241 | + } | |
| 242 | + | |
| 243 | + _fbput(screenimage, r); | |
| 244 | +} | |
| 245 | + | |
| 246 | +static void | |
| 247 | +fbproc(void *v) | |
| 248 | +{ | |
| 249 | + struct input_event data; | |
| 250 | + char buf[32]; | |
| 251 | + struct pollfd *pfd; | |
| 252 | + int r; | |
| 253 | + int ioctlarg; | |
| 254 | + | |
| 255 | + pfd = calloc(3, sizeof(struct pollfd)); | |
| 256 | + pfd[0].fd = ttyfd; // for virtual console switches | |
| 257 | + pfd[0].events = POLLPRI; | |
| 258 | + pfd[1].fd = 0; // stdin goes to nowhere | |
| 259 | + pfd[1].events = POLLIN; | |
| 260 | + pfd[2].fd = open("/proc/bus/input/devices", O_RDONLY); // input hotplug | |
| 261 | + if (pfd[2].fd < 0) | |
| 262 | + panic("cannot open /proc/bus/input/devices: %r"); | |
| 263 | + pfd[2].events = POLLIN; | |
| 264 | + | |
| 265 | +TOP: | |
| 266 | + while(read(pfd[2].fd, buf, 31) > 0); | |
| 267 | + | |
| 268 | + pfd = realloc(pfd, sizeof(struct pollfd) * (neventfds + 3)); | |
| 269 | + for (r = 0; r < neventfds; r++) { | |
| 270 | + pfd[r+3].fd = eventfds[r]; | |
| 271 | + pfd[r+3].events = POLLIN; | |
| 272 | + } | |
| 273 | + | |
| 274 | + for(;;) { | |
| 275 | + shift_state = 6; | |
| 276 | + if (ioctl(0, TIOCLINUX, &shift_state) < 0) | |
| 277 | + panic("ioctl TIOCLINUX 6: %r"); | |
| 278 | + | |
| 279 | + r = poll(pfd, 3+neventfds, -1); | |
| 280 | + if (r < 0) | |
| 281 | + oserror(); | |
| 282 | + if (pfd[0].revents & POLLPRI) { | |
| 283 | + if ((r = read(ttyfd, buf, 31)) <= 0) | |
| 284 | + panic("ttyfd read: %r"); | |
| 285 | + buf[r] = '\0'; | |
| 286 | + if (strcmp(buf, tty) == 0) { | |
| 287 | + hidden = 0; | |
| 288 | + printf("\e[?25l"); | |
| 289 | + fflush(stdout); | |
| 290 | + qlock(&drawlock); | |
| 291 | + flushmemscreen(gscreen->clipr); | |
| 292 | + qunlock(&drawlock); | |
| 293 | + } | |
| 294 | + else | |
| 295 | + hidden = 1; | |
| 296 | + close(ttyfd); | |
| 297 | + ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY); | |
| 298 | + if (ttyfd < 0) | |
| 299 | + panic("cannot open tty active fd: %r"); | |
| 300 | + pfd[0].fd = ttyfd; | |
| 301 | + read(ttyfd, buf, 0); | |
| 302 | + } | |
| 303 | + if (pfd[1].revents & POLLIN) | |
| 304 | + read(pfd[1].fd, buf, 31); | |
| 305 | + if (pfd[2].revents & POLLIN) { | |
| 306 | + for (r = 0; r < neventfds; r++) | |
| 307 | + close(eventfds[r]); | |
| 308 | + if(eventattach() < 0) { | |
| 309 | + panic("cannot open event files: %r"); | |
| 310 | + } | |
| 311 | + goto TOP; | |
| 312 | + } | |
| 313 | + for (r = 0; r < neventfds; r++) | |
| 314 | + if (pfd[r+3].revents & POLLIN) { | |
| 315 | + if (read(pfd[r+3].fd, &data, sizeof(data)) != sizeof(data)) | |
| 316 | + panic("eventfd read: %r"); | |
| 317 | + if (onevent(&data) == 0) { | |
| 318 | + ioctlarg = 15; | |
| 319 | + if (ioctl(0, TIOCLINUX, &ioctlarg) != 0) { | |
| 320 | + ioctlarg = 4; | |
| 321 | + ioctl(0, TIOCLINUX, &ioctlarg); | |
| 322 | + qlock(&drawlock); | |
| 323 | + flushmemscreen(gscreen->clipr); | |
| 324 | + qunlock(&drawlock); | |
| 325 | + } else { | |
| 326 | + write(1, "\033[9;30]", 7); | |
| 327 | + } | |
| 328 | + } | |
| 329 | + } | |
| 330 | + } | |
| 331 | + | |
| 332 | + printf("\e[?25h"); | |
| 333 | + fflush(stdout); | |
| 334 | + termctl(ECHO, 1); | |
| 335 | + free(pfd); | |
| 336 | +} | |
| 337 | + | |
| 338 | +void | |
| 339 | +screensize(Rectangle r, ulong chan) | |
| 340 | +{ | |
| 341 | + gscreen = backbuf; | |
| 342 | + gscreen->clipr = ZR; | |
| 343 | +} | |
| 344 | + | |
| 345 | +void | |
| 346 | +screeninit(void) | |
| 347 | +{ | |
| 348 | + int r; | |
| 349 | + char buf[1]; | |
| 350 | + | |
| 351 | + // set up terminal | |
| 352 | + printf("\e[?25l"); | |
| 353 | + fflush(stdout); | |
| 354 | + termctl(~(ICANON|ECHO), 0); | |
| 355 | + signal(SIGINT, ctrlc); | |
| 356 | + | |
| 357 | + memimageinit(); | |
| 358 | + | |
| 359 | + // tty switching | |
| 360 | + ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY); | |
| 361 | + if (ttyfd >= 0) { | |
| 362 | + tty = malloc(32); | |
| 363 | + r = read(ttyfd, tty, 31); | |
| 364 | + if (r >= 0) | |
| 365 | + tty[r] = '\0'; | |
| 366 | + else | |
| 367 | + tty[0] = '\0'; | |
| 368 | + close(ttyfd); | |
| 369 | + ttyfd = open("/sys/class/tty/tty0/active", O_RDONLY); | |
| 370 | + } | |
| 371 | + if (ttyfd < 0) | |
| 372 | + panic("cannot open tty active fd: %r"); | |
| 373 | + read(ttyfd, buf, 0); | |
| 374 | + hidden = 0; | |
| 375 | + | |
| 376 | + if(fbattach(0) == nil) { | |
| 377 | + panic("cannot open framebuffer: %r"); | |
| 378 | + } | |
| 379 | + | |
| 380 | + if(eventattach() < 0) { | |
| 381 | + panic("cannot open event files: %r"); | |
| 382 | + } | |
| 383 | + | |
| 384 | + screensize(screenr, chan); | |
| 385 | + if (gscreen == nil) | |
| 386 | + panic("screensize failed"); | |
| 387 | + | |
| 388 | + gscreen->clipr = screenr; | |
| 389 | + kproc("fbdev", fbproc, nil); | |
| 390 | + | |
| 391 | + terminit(); | |
| 392 | + | |
| 393 | + qlock(&drawlock); | |
| 394 | + flushmemscreen(gscreen->clipr); | |
| 395 | + qunlock(&drawlock); | |
| 396 | +} | |
| 397 | + | |
| 398 | +Memdata* | |
| 399 | +attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen) | |
| 400 | +{ | |
| 401 | + *r = gscreen->clipr; | |
| 402 | + *chan = gscreen->chan; | |
| 403 | + *depth = gscreen->depth; | |
| 404 | + *width = gscreen->width; | |
| 405 | + *softscreen = 1; | |
| 406 | + | |
| 407 | + gscreen->data->ref++; | |
| 408 | + return gscreen->data; | |
| 409 | +} | |
| 410 | + | |
| 411 | +void | |
| 412 | +getcolor(ulong i, ulong *r, ulong *g, ulong *b) | |
| 413 | +{ | |
| 414 | + ulong v; | |
| 415 | + | |
| 416 | + v = cmap2rgb(i); | |
| 417 | + *r = (v>>16)&0xFF; | |
| 418 | + *g = (v>>8)&0xFF; | |
| 419 | + *b = v&0xFF; | |
| 420 | +} | |
| 421 | + | |
| 422 | +void | |
| 423 | +setcolor(ulong i, ulong r, ulong g, ulong b) | |
| 424 | +{ | |
| 425 | + /* no-op */ | |
| 426 | + return; | |
| 427 | +} | |
| 428 | + | |
| 429 | +char* | |
| 430 | +clipread(void) | |
| 431 | +{ | |
| 432 | + if(snarfbuf) | |
| 433 | + return strdup(snarfbuf); | |
| 434 | + return nil; | |
| 435 | +} | |
| 436 | + | |
| 437 | +int | |
| 438 | +clipwrite(char *buf) | |
| 439 | +{ | |
| 440 | + if(snarfbuf) | |
| 441 | + free(snarfbuf); | |
| 442 | + snarfbuf = strdup(buf); | |
| 443 | + return 0; | |
| 444 | +} | |
| 445 | + | |
| 446 | +void | |
| 447 | +guimain(void) | |
| 448 | +{ | |
| 449 | + cpubody(); | |
| 450 | +} | |
| 451 | + | |
| 452 | +void | |
| 453 | +termctl(uint32_t o, int or) | |
| 454 | +{ | |
| 455 | + struct termios t; | |
| 456 | + | |
| 457 | + tcgetattr(0, &t); | |
| 458 | + if (or) | |
| 459 | + t.c_lflag |= o; | |
| 460 | + else | |
| 461 | + t.c_lflag &= o; | |
| 462 | + tcsetattr(0, TCSANOW, &t); | |
| 463 | +} | |
| 464 | + | |
| 465 | +void | |
| 466 | +ctrlc(int sig) { | |
| 467 | +} | |
| 468 | + | |
| 469 | +int | |
| 470 | +onevent(struct input_event *data) | |
| 471 | +{ | |
| 472 | + Rectangle old, new; | |
| 473 | + ulong msec; | |
| 474 | + static int buttons; | |
| 475 | + static Point coord; | |
| 476 | + static char touched; | |
| 477 | + static Point startmousept; | |
| 478 | + static Point startpt; | |
| 479 | + int key; | |
| 480 | + static ulong lastmsec = 0; | |
| 481 | + | |
| 482 | + if (hidden != 0) | |
| 483 | + return -1; | |
| 484 | + | |
| 485 | + msec = ticks(); | |
| 486 | + | |
| 487 | + old.min = mousexy; | |
| 488 | + old.max = addpt(old.min, Pt(16, 16)); | |
| 489 | + | |
| 490 | + buttons &= ~0x18; | |
| 491 | + | |
| 492 | + switch(data->type) { | |
| 493 | + case 3: | |
| 494 | + switch(data->code) { | |
| 495 | + case 0: | |
| 496 | + coord.x = data->value; | |
| 497 | + break; | |
| 498 | + case 1: | |
| 499 | + coord.y = data->value; | |
| 500 | + break; | |
| 501 | + case 0x18: | |
| 502 | + case 0x1c: | |
| 503 | + if (data->value == 0) | |
| 504 | + touched = 0; | |
| 505 | + else if (data->value > 24) { | |
| 506 | + touched = 1; | |
| 507 | + startmousept = coord; | |
| 508 | + startpt = mousexy; | |
| 509 | + } | |
| 510 | + break; | |
| 511 | + default: | |
| 512 | + return -1; | |
| 513 | + } | |
| 514 | + if (touched) | |
| 515 | + mousexy = addpt(startpt, divpt(subpt(coord, startmousept), 4)); | |
| 516 | + break; | |
| 517 | + case 2: | |
| 518 | + switch(data->code) { | |
| 519 | + case 0: | |
| 520 | + mousexy.x += data->value; | |
| 521 | + break; | |
| 522 | + case 1: | |
| 523 | + mousexy.y += data->value; | |
| 524 | + break; | |
| 525 | + case 8: | |
| 526 | + buttons |= data->value == 1? 8: 16; | |
| 527 | + break; | |
| 528 | + default: | |
| 529 | + return -1; | |
| 530 | + } | |
| 531 | + break; | |
| 532 | + case 1: | |
| 533 | + switch(data->code) { | |
| 534 | + case 0x110: | |
| 535 | + if (data->value == 1) | |
| 536 | + buttons |= 1; | |
| 537 | + else | |
| 538 | + buttons &= ~1; | |
| 539 | + break; | |
| 540 | + case 0x111: | |
| 541 | + if (data->value == 1) | |
| 542 | + buttons |= shift_state & (1 << KG_SHIFT)? 2: 4; | |
| 543 | + else | |
| 544 | + buttons &= ~(shift_state & (1 << KG_SHIFT)? 2: 4); | |
| 545 | + break; | |
| 546 | + case 0x112: | |
| 547 | + if (data->value == 1) | |
| 548 | + buttons |= 2; | |
| 549 | + else | |
| 550 | + buttons &= ~2; | |
| 551 | + break; | |
| 552 | + default: | |
| 553 | + if (hidden) | |
| 554 | + return 0; | |
| 555 | + if (data->code > 0 && data->code <= nelem(code2key)) { | |
| 556 | + if (shift_state & (1 << KG_SHIFT)) | |
| 557 | + key = code2key_shift[data->code-1]; | |
| 558 | + else | |
| 559 | + key = code2key[data->code-1]; | |
| 560 | + if (key == Kshift) | |
| 561 | + return -1; | |
| 562 | + kbdkey(key, data->value); | |
| 563 | + return 0; | |
| 564 | + } | |
| 565 | + switch(data->code) { | |
| 566 | + case 87: | |
| 567 | + kbdkey(KF|11, data->value); | |
| 568 | + break; | |
| 569 | + case 88: | |
| 570 | + kbdkey(KF|12, data->value); | |
| 571 | + break; | |
| 572 | + case 96: | |
| 573 | + kbdkey('\n', data->value); | |
| 574 | + break; | |
| 575 | + case 97: | |
| 576 | + kbdkey(Kctl, data->value); | |
| 577 | + break; | |
| 578 | + case 98: | |
| 579 | + kbdkey('/', data->value); | |
| 580 | + break; | |
| 581 | + case 100: | |
| 582 | + kbdkey(Kalt, data->value); | |
| 583 | + break; | |
| 584 | + case 102: | |
| 585 | + kbdkey(Khome, data->value); | |
| 586 | + break; | |
| 587 | + case 103: | |
| 588 | + kbdkey(Kup, data->value); | |
| 589 | + break; | |
| 590 | + case 104: | |
| 591 | + kbdkey(Kpgup, data->value); | |
| 592 | + break; | |
| 593 | + case 105: | |
| 594 | + kbdkey(Kleft, data->value); | |
| 595 | + break; | |
| 596 | + case 106: | |
| 597 | + kbdkey(Kright, data->value); | |
| 598 | + break; | |
| 599 | + case 107: | |
| 600 | + kbdkey(Kend, data->value); | |
| 601 | + break; | |
| 602 | + case 108: | |
| 603 | + kbdkey(Kdown, data->value); | |
| 604 | + break; | |
| 605 | + case 109: | |
| 606 | + kbdkey(Kpgdown, data->value); | |
| 607 | + break; | |
| 608 | + case 110: | |
| 609 | + kbdkey(Kins, data->value); | |
| 610 | + break; | |
| 611 | + case 111: | |
| 612 | + kbdkey(Kdel, data->value); | |
| 613 | + break; | |
| 614 | + } | |
| 615 | + return 0; | |
| 616 | + } | |
| 617 | + break; | |
| 618 | + default: | |
| 619 | + return -1; | |
| 620 | + } | |
| 621 | + | |
| 622 | + if (mousexy.x < screenimage->r.min.x) | |
| 623 | + mousexy.x = screenimage->r.min.x; | |
| 624 | + if (mousexy.y < screenimage->r.min.y) | |
| 625 | + mousexy.y = screenimage->r.min.y; | |
| 626 | + if (mousexy.x > screenimage->r.max.x) | |
| 627 | + mousexy.x = screenimage->r.max.x; | |
| 628 | + if (mousexy.y > screenimage->r.max.y) | |
| 629 | + mousexy.y = screenimage->r.max.y; | |
| 630 | + | |
| 631 | + new.min = mousexy; | |
| 632 | + new.max = addpt(new.min, Pt(16, 16)); // size of cursor bitmap | |
| 633 | + | |
| 634 | + combinerect(&new, old); | |
| 635 | + new.min = subpt(new.min, Pt(16, 16)); // to encompass any cursor->offset | |
| 636 | + | |
| 637 | + qlock(&drawlock); | |
| 638 | + flushmemscreen(new); | |
| 639 | + qunlock(&drawlock); | |
| 640 | + | |
| 641 | + if ((msec - lastmsec) < 10) | |
| 642 | + if (data->type != 1) | |
| 643 | + return 0; | |
| 644 | + | |
| 645 | + lastmsec = msec; | |
| 646 | + | |
| 647 | + absmousetrack(mousexy.x, mousexy.y, buttons, msec); | |
| 648 | + | |
| 649 | + return 0; | |
| 650 | +} | |
| 651 | + | |
| 652 | +void | |
| 653 | +mouseset(Point p) | |
| 654 | +{ | |
| 655 | + qlock(&drawlock); | |
| 656 | + mousexy = p; | |
| 657 | + flushmemscreen(screenr); | |
| 658 | + qunlock(&drawlock); | |
| 659 | +} | |
| 660 | + | |
| 661 | +void | |
| 662 | +setcursor(void) | |
| 663 | +{ | |
| 664 | + qlock(&drawlock); | |
| 665 | + flushmemscreen(screenr); | |
| 666 | + qunlock(&drawlock); | |
| 667 | +} | |
| 668 | + | |
| 669 | +void | |
| 670 | +titlewrite(char* buf) | |
| 671 | +{ | |
| 672 | +} | |
| 673 | + | |
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * ALSA | |
| 3 | + */ | |
| 4 | +#include <alsa/asoundlib.h> | |
| 5 | +#include "u.h" | |
| 6 | +#include "lib.h" | |
| 7 | +#include "dat.h" | |
| 8 | +#include "fns.h" | |
| 9 | +#include "error.h" | |
| 10 | +#include "devaudio.h" | |
| 11 | + | |
| 12 | +enum | |
| 13 | +{ | |
| 14 | + Channels = 2, | |
| 15 | + Rate = 44100, | |
| 16 | + Bits = 16, | |
| 17 | +}; | |
| 18 | + | |
| 19 | +static snd_pcm_t *playback; | |
| 20 | +static snd_pcm_t *capture; | |
| 21 | +static int speed = Rate; | |
| 22 | + | |
| 23 | +/* maybe this should return -1 instead of sysfatal */ | |
| 24 | +void | |
| 25 | +audiodevopen(void) | |
| 26 | +{ | |
| 27 | + if(snd_pcm_open(&playback, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) | |
| 28 | + error("snd_pcm_open playback"); | |
| 29 | + | |
| 30 | + if(snd_pcm_set_params(playback, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 2, speed, 1, 500000) < 0) | |
| 31 | + error("snd_pcm_set_params playback"); | |
| 32 | + | |
| 33 | + if(snd_pcm_prepare(playback) < 0) | |
| 34 | + error("snd_pcm_prepare playback"); | |
| 35 | + | |
| 36 | + if(snd_pcm_open(&capture, "default", SND_PCM_STREAM_CAPTURE, 0) < 0) | |
| 37 | + error("snd_pcm_open capture"); | |
| 38 | + | |
| 39 | + if(snd_pcm_set_params(capture, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 2, speed, 1, 500000) < 0) | |
| 40 | + error("snd_pcm_set_params capture"); | |
| 41 | + | |
| 42 | + if(snd_pcm_prepare(capture) < 0) | |
| 43 | + error("snd_pcm_prepare capture"); | |
| 44 | +} | |
| 45 | + | |
| 46 | +void | |
| 47 | +audiodevclose(void) | |
| 48 | +{ | |
| 49 | + snd_pcm_drain(playback); | |
| 50 | + snd_pcm_close(playback); | |
| 51 | + | |
| 52 | + snd_pcm_close(capture); | |
| 53 | +} | |
| 54 | + | |
| 55 | +void | |
| 56 | +audiodevsetvol(int what, int left, int right) | |
| 57 | +{ | |
| 58 | + if(what == Vspeed){ | |
| 59 | + speed = left; | |
| 60 | + return; | |
| 61 | + } | |
| 62 | +} | |
| 63 | + | |
| 64 | +void | |
| 65 | +audiodevgetvol(int what, int *left, int *right) | |
| 66 | +{ | |
| 67 | + if(what == Vspeed){ | |
| 68 | + *left = *right = speed; | |
| 69 | + return; | |
| 70 | + } | |
| 71 | + | |
| 72 | + *left = *right = 100; | |
| 73 | +} | |
| 74 | + | |
| 75 | +int | |
| 76 | +audiodevwrite(void *v, int n) | |
| 77 | +{ | |
| 78 | + snd_pcm_sframes_t frames; | |
| 79 | + int tot, m; | |
| 80 | + | |
| 81 | + for(tot = 0; tot < n; tot += m){ | |
| 82 | + do { | |
| 83 | + frames = snd_pcm_writei(playback, v+tot, (n-tot)/4); | |
| 84 | + } while(frames == -EAGAIN); | |
| 85 | + if (frames < 0) | |
| 86 | + frames = snd_pcm_recover(playback, frames, 0); | |
| 87 | + if (frames < 0) | |
| 88 | + error((char*)snd_strerror(frames)); | |
| 89 | + m = frames*4; | |
| 90 | + } | |
| 91 | + | |
| 92 | + return tot; | |
| 93 | +} | |
| 94 | + | |
| 95 | +int | |
| 96 | +audiodevread(void *v, int n) | |
| 97 | +{ | |
| 98 | + snd_pcm_sframes_t frames; | |
| 99 | + | |
| 100 | + do { | |
| 101 | + frames = snd_pcm_readi(capture, v, n/4); | |
| 102 | + } while(frames == -EAGAIN); | |
| 103 | + | |
| 104 | + if (frames < 0) | |
| 105 | + error((char*)snd_strerror(frames)); | |
| 106 | + | |
| 107 | + return frames*4; | |
| 108 | +} | |
| @@ -54,6 +54,7 @@ main(int argc, char **argv) · 53 unmodified lines | ||
| 54 | 54 | if(bind("#U", "/root", MREPL) < 0) |
| 55 | 55 | panic("bind #U: %r"); |
| 56 | 56 | bind("#A", "/dev", MAFTER); |
| 57 | + bind("#N", "/dev", MAFTER); | |
| 57 | 58 | bind("#C", "/", MAFTER); |
| 58 | 59 | |
| 59 | 60 | if(open("/dev/cons", OREAD) != 0) |