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 | To build on Mac OS X with Cocoa, run CONF=osx-cocoa make and "cp drawterm gui-cocoa/drawterm.app/". | 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 | BINARIES | 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 | if(bind("#U", "/root", MREPL) < 0) | 54 | if(bind("#U", "/root", MREPL) < 0) |
| 55 | panic("bind #U: %r"); | 55 | panic("bind #U: %r"); |
| 56 | bind("#A", "/dev", MAFTER); | 56 | bind("#A", "/dev", MAFTER); |
| 57 | bind("#N", "/dev", MAFTER); | ||
| 57 | bind("#C", "/", MAFTER); | 58 | bind("#C", "/", MAFTER); |
| 58 | 59 | ||
| 59 | if(open("/dev/cons", OREAD) != 0) | 60 | if(open("/dev/cons", OREAD) != 0) |