History

Merging echoline's android and fbdev forks

Lorenzo Bivens committed 5 years ago

Commit 96209041 parent a130d4427 files · +2398 −0Browse files

Unified · Split

27 files
  1. Make.android +38 −0
  2. Make.android-386 +26 −0
  3. Make.android-amd64 +26 −0
  4. Make.android-arm +26 −0
  5. Make.android-arm64 +26 −0
  6. Make.fbdev +22 −0
  7. README +11 −0
  8. gui-android/AndroidManifest.xml +30 −0
  9. gui-android/Makefile +23 −0
  10. gui-android/cpp/android.c +230 −0
  11. gui-android/cpp/devandroid.c +248 −0
  12. gui-android/cpp/native-lib.c +173 −0
  13. gui-android/java/org/echoline/drawterm/DrawTermThread.java +32 −0
  14. gui-android/java/org/echoline/drawterm/MainActivity.java +437 −0
  15. gui-android/java/org/echoline/drawterm/MySurfaceView.java +91 −0
  16. gui-android/res/layout/activity_main.xml +24 −0
  17. gui-android/res/layout/content_main.xml +16 −0
  18. gui-android/res/layout/drawterm_main.xml +44 −0
  19. gui-android/res/layout/item_main.xml +8 −0
  20. gui-android/res/layout/server_main.xml +56 −0
  21. gui-android/res/values/colors.xml +6 −0
  22. gui-android/res/values/strings.xml +3 −0
  23. gui-android/res/values/styles.xml +8 −0
  24. gui-fbdev/Makefile +12 −0
  25. gui-fbdev/fbdev.c +673 −0
  26. kern/devaudio-alsa.c +108 −0
  27. main.c +1 −0
Make.android+38−0
@@ -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
Make.android-386+26−0
@@ -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+
Make.android-amd64+26−0
@@ -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+
Make.android-arm+26−0
@@ -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+
Make.android-arm64+26−0
@@ -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+
Make.fbdev+22−0
@@ -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)
README+11−0
@@ -18,6 +18,17 @@ To build on Mac OS X with X11 (xquartz), run CONF=osx-x11 make. · 17 unmodified lines
1818
1919 To build on Mac OS X with Cocoa, run CONF=osx-cocoa make and "cp drawterm gui-cocoa/drawterm.app/".
2020
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+
2132
2233 BINARIES
2334 ---------
gui-android/AndroidManifest.xml+30−0
@@ -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>
gui-android/Makefile+23−0
@@ -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+
gui-android/cpp/android.c+230−0
@@ -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+
gui-android/cpp/devandroid.c+248−0
@@ -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+};
gui-android/cpp/native-lib.c+173−0
@@ -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+
gui-android/java/org/echoline/drawterm/DrawTermThread.java+32−0
@@ -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+}
gui-android/java/org/echoline/drawterm/MainActivity.java+437−0
@@ -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+}
gui-android/java/org/echoline/drawterm/MySurfaceView.java+91−0
@@ -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+}
gui-android/res/layout/activity_main.xml+24−0
@@ -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>
gui-android/res/layout/content_main.xml+16−0
@@ -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>
gui-android/res/layout/drawterm_main.xml+44−0
@@ -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>
gui-android/res/layout/item_main.xml+8−0
@@ -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+
gui-android/res/layout/server_main.xml+56−0
@@ -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>
gui-android/res/values/colors.xml+6−0
@@ -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>
gui-android/res/values/strings.xml+3−0
@@ -0,0 +1,3 @@
1+<resources>
2+ <string name="app_name">Drawterm</string>
3+</resources>
gui-android/res/values/styles.xml+8−0
@@ -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>
gui-fbdev/Makefile+12−0
@@ -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+
gui-fbdev/fbdev.c+673−0
@@ -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+
kern/devaudio-alsa.c+108−0
@@ -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+}
main.c+1−0
@@ -54,6 +54,7 @@ main(int argc, char **argv) · 53 unmodified lines
5454 if(bind("#U", "/root", MREPL) < 0)
5555 panic("bind #U: %r");
5656 bind("#A", "/dev", MAFTER);
57+ bind("#N", "/dev", MAFTER);
5758 bind("#C", "/", MAFTER);
5859
5960 if(open("/dev/cons", OREAD) != 0)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t