3 namespace gui::drivers;
15 #include <sys/prctl.h>
17 #include <android/configuration.h>
18 #include <android/looper.h>
19 #include <android/native_activity.h>
20 #include <android/sensor.h>
21 #include <android/log.h>
22 #include <android/window.h>
28 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "ecere-app", __VA_ARGS__))
29 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "ecere-app", __VA_ARGS__))
30 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "ecere-app", __VA_ARGS__))
32 #define LOGV(...) ((void)0)
34 #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "ecere-app", __VA_ARGS__))
37 // *** NATIVE APP GLUE ********
38 enum LooperID { main = 1, input = 2, user = 3 };
39 enum AppCommand : byte
41 error = 0, inputChanged, initWindow, termWindow, windowResized, windowRedrawNeeded,
42 contentRectChanged, gainedFocus, lostFocus,
43 configChanged, lowMemory, start, resume, saveState, pause, stop, destroy
46 class AndroidPollSource
51 virtual void any_object::process();
54 class AndroidAppGlue : Thread
57 virtual void onAppCmd(AppCommand cmd);
58 virtual int onInputEvent(AInputEvent* event);
61 ANativeActivity* activity;
62 AConfiguration* config;
67 AInputQueue* inputQueue;
68 ANativeWindow* window;
70 AppCommand activityState;
71 bool destroyRequested;
78 int msgread, msgwrite;
82 config = AConfiguration_new();
83 AConfiguration_fromAssetManager(config, activity->assetManager);
87 looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
88 ALooper_addFd(looper, msgread, LooperID::main, ALOOPER_EVENT_INPUT, null, cmdPollSource);
106 AInputQueue_detachLooper(inputQueue);
107 AConfiguration_delete(config);
113 AndroidPollSource cmdPollSource
119 AppCommand cmd = read_cmd();
125 AndroidPollSource inputPollSource
131 AInputEvent* event = null;
132 if(AInputQueue_getEvent(inputQueue, &event) >= 0)
135 LOGV("New input event: type=%d\n", AInputEvent_getType(event));
136 if(AInputQueue_preDispatchEvent(inputQueue, event))
138 /*handled = */onInputEvent(event);
139 //AInputQueue_finishEvent(inputQueue, event, handled);
142 LOGE("Failure reading next input event: %s\n", strerror(errno));
149 AInputQueue* pendingInputQueue;
150 ANativeWindow* pendingWindow;
151 ARect pendingContentRect;
153 void free_saved_state()
163 AppCommand read_cmd()
166 if(read(msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
173 LOGE("No data on command pipe!");
177 void print_cur_config()
179 char lang[2], country[2];
180 AConfiguration_getLanguage(config, lang);
181 AConfiguration_getCountry(config, country);
183 LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
184 "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
185 "modetype=%d modenight=%d",
186 AConfiguration_getMcc(config),
187 AConfiguration_getMnc(config),
188 lang[0], lang[1], country[0], country[1],
189 AConfiguration_getOrientation(config),
190 AConfiguration_getTouchscreen(config),
191 AConfiguration_getDensity(config),
192 AConfiguration_getKeyboard(config),
193 AConfiguration_getNavigation(config),
194 AConfiguration_getKeysHidden(config),
195 AConfiguration_getNavHidden(config),
196 AConfiguration_getSdkVersion(config),
197 AConfiguration_getScreenSize(config),
198 AConfiguration_getScreenLong(config),
199 AConfiguration_getUiModeType(config),
200 AConfiguration_getUiModeNight(config));
203 void pre_exec_cmd(AppCommand cmd)
205 //PrintLn("pre_exec_cmd: ", cmd);
211 AInputQueue_detachLooper(inputQueue);
212 inputQueue = pendingInputQueue;
214 AInputQueue_attachLooper(inputQueue, looper, LooperID::input, null, inputPollSource);
220 window = pendingWindow;
237 AConfiguration_fromAssetManager(config, activity->assetManager);
241 destroyRequested = true;
246 void post_exec_cmd(AppCommand cmd)
248 //PrintLn("post_exec_cmd: ", cmd);
269 void write_cmd(AppCommand cmd)
271 if(write(msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd))
272 LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
275 void set_input(AInputQueue* inputQueue)
278 pendingInputQueue = inputQueue;
279 write_cmd(inputChanged);
280 while(inputQueue != pendingInputQueue)
285 void set_window(ANativeWindow* window)
289 write_cmd(termWindow);
290 pendingWindow = window;
292 write_cmd(initWindow);
293 while(window != pendingWindow)
298 void set_activity_state(AppCommand cmd)
302 while(activityState != cmd)
318 void setSavedState(void * state, uint size)
325 savedState = malloc(size);
326 savedStateSize = size;
327 memcpy(savedState, state, size);
337 LOGE("could not create pipe: %s", strerror(errno));
338 msgread = msgpipe[0];
339 msgwrite = msgpipe[1];
343 // Wait for thread to start.
345 while(!running) cond.Wait(mutex);
351 static void onDestroy(ANativeActivity* activity)
353 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
354 LOGI("Destroy: %p\n", activity);
357 delete androidActivity;
358 delete __androidCurrentModule;
362 static void onStart(ANativeActivity* activity)
364 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
365 LOGI("Start: %p\n", activity);
366 app.set_activity_state(start);
369 static void onResume(ANativeActivity* activity)
371 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
372 LOGI("Resume: %p\n", activity);
373 app.set_activity_state(resume);
376 static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
378 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
379 void* savedState = null;
380 LOGI("SaveInstanceState: %p\n", activity);
382 app.stateSaved = false;
383 app.write_cmd(saveState);
384 while(!app.stateSaved)
385 app.cond.Wait(app.mutex);
388 savedState = app.savedState;
389 *outLen = app.savedStateSize;
390 app.savedState = null;
391 app.savedStateSize = 0;
397 static void onPause(ANativeActivity* activity)
399 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
400 LOGI("Pause: %p\n", activity);
401 app.set_activity_state(pause);
404 static void onStop(ANativeActivity* activity)
406 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
407 LOGI("Stop: %p\n", activity);
408 app.set_activity_state(stop);
411 static void onConfigurationChanged(ANativeActivity* activity)
413 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
414 LOGI("ConfigurationChanged: %p\n", activity);
415 app.write_cmd(configChanged);
418 static void onLowMemory(ANativeActivity* activity)
420 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
421 LOGI("LowMemory: %p\n", activity);
422 app.write_cmd(lowMemory);
425 static void onWindowFocusChanged(ANativeActivity* activity, int focused)
427 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
428 LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
429 app.write_cmd(focused ? gainedFocus : lostFocus);
432 static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
434 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
435 LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
436 app.set_window(window);
439 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
441 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
442 LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
444 app.set_window(null);
447 static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
449 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
450 LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
451 app.set_input(queue);
454 static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
456 AndroidAppGlue app = (AndroidAppGlue)activity->instance;
457 LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
458 app.inputQueue = null;
462 default dllexport void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
467 // Determine our package name
468 JNIEnv* env=activity->env;
475 // *** Reinitialize static global variables ***
477 guiApplicationInitialized = false;
479 desktopW = 0; desktopH = 0;
480 clipBoardData = null;
482 __androidCurrentModule = null;
484 prctl(PR_SET_DUMPABLE, 1);
486 LOGI("Creating: %p\n", activity);
488 //(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);
489 clazz = (*env)->GetObjectClass(env, activity->clazz);
490 methodID = (*env)->GetMethodID(env, clazz, "getPackageName", "()Ljava/lang/String;");
491 result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
492 str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
493 // (*activity->vm)->DetachCurrentThread(activity->vm);
494 moduleName = strstr(str, "com.ecere.");
495 if(moduleName) moduleName += 10;
496 androidArgv[0] = moduleName;
498 // Create a base Application class
499 __androidCurrentModule = __ecere_COM_Initialize(true, 1, androidArgv);
501 eModule_Load(__androidCurrentModule, "ecere", publicAccess);
505 if(activity->internalDataPath) PrintLn("internalDataPath is ", activity->internalDataPath);
506 if(activity->externalDataPath) PrintLn("externalDataPath is ", activity->externalDataPath);
509 PrintLn("cwd is ", GetWorkingDir(tmp, sizeof(tmp)));
513 ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FULLSCREEN|AWINDOW_FLAG_KEEP_SCREEN_ON, 0 );
514 app = AndroidActivity { activity = activity, moduleName = moduleName };
516 app.setSavedState(savedState, (uint)savedStateSize);
517 activity->callbacks->onDestroy = onDestroy;
518 activity->callbacks->onStart = onStart;
519 activity->callbacks->onResume = onResume;
520 activity->callbacks->onSaveInstanceState = onSaveInstanceState;
521 activity->callbacks->onPause = onPause;
522 activity->callbacks->onStop = onStop;
523 activity->callbacks->onConfigurationChanged = onConfigurationChanged;
524 activity->callbacks->onLowMemory = onLowMemory;
525 activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
526 activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
527 activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
528 activity->callbacks->onInputQueueCreated = onInputQueueCreated;
529 activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
530 activity->instance = app;
534 // *** END OF NATIVE APP GLUE ******
537 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
538 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
539 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
540 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
541 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
542 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
543 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
544 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
545 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
546 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
547 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
548 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
549 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
550 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
553 static Module __androidCurrentModule;
554 static char * androidArgv[1];
556 static int desktopW, desktopH;
557 static char * clipBoardData;
558 static int mouseX, mouseY;
560 class AndroidInterface : Interface
562 class_property(name) = "Android";
564 // --- User Interface System ---
567 setlocale(LC_ALL, "en_US.UTF-8");
576 #define DBLCLICK_DELAY 300 // 0.3 second
577 #define DBLCLICK_DELTA 1
579 bool ProcessInput(bool processAll)
581 bool eventAvailable = false;
583 if(androidActivity.ident < 0)
584 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
586 if(gotInit && androidActivity.window)
588 int w = ANativeWindow_getWidth(androidActivity.window);
589 int h = ANativeWindow_getHeight(androidActivity.window);
590 if(desktopW != w || desktopH != h)
592 guiApp.SetDesktopPosition(0, 0, w, h, true);
595 guiApp.desktop.Update(null);
599 while(androidActivity.ident >= 0)
601 AndroidPollSource source = androidActivity.source;
603 androidActivity.source = null;
605 source.process(source.userData);
607 // If a sensor has data, process it now.
609 if(androidActivity.ident == user)
611 if(androidActivity.accelerometerSensor)
614 while (ASensorEventQueue_getEvents(androidActivity.sensorEventQueue, &event, 1) > 0)
615 LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x, event.acceleration.y, event.acceleration.z);
620 eventAvailable = true;
621 if(androidActivity.destroyRequested)
623 guiApp.desktop.Destroy(0);
624 eventAvailable = true;
625 androidActivity.ident = (LooperID)-1;
628 androidActivity.ident = (LooperID)ALooper_pollAll(0, null, &androidActivity.events, (void**)&androidActivity.source);
630 androidActivity.ident = (LooperID)-1;
632 return eventAvailable;
637 androidActivity.ident = (LooperID)ALooper_pollAll((int)(1000/18.2f), null, &androidActivity.events, (void**)&androidActivity.source);
638 // guiApp.WaitEvent();
641 void Lock(Window window)
646 void Unlock(Window window)
651 const char ** GraphicsDrivers(int * numDrivers)
653 static const char *graphicsDrivers[] = { "OpenGL" };
654 *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
655 return (const char **)graphicsDrivers;
658 void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
663 void EnsureFullScreen(bool *fullScreen)
668 bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
675 // --- Window Creation ---
676 void * CreateRootWindow(Window window)
678 return androidActivity.window;
681 void DestroyRootWindow(Window window)
686 // -- Window manipulation ---
688 void SetRootWindowCaption(Window window, const char * name)
693 void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
698 void OrderRootWindow(Window window, bool topMost)
703 void SetRootWindowColor(Window window)
708 void OffsetWindow(Window window, int * x, int * y)
713 void UpdateRootWindow(Window window)
715 if(!window.parent || !window.parent.display)
719 Box box = window.box;
720 box.left -= window.clientStart.x;
721 box.top -= window.clientStart.y;
722 box.right -= window.clientStart.x;
723 box.bottom -= window.clientStart.y;
724 // Logf("Update root window %s\n", window.name);
726 box.left += window.clientStart.x;
727 box.top += window.clientStart.y;
728 box.right += window.clientStart.x;
729 box.bottom += window.clientStart.y;
730 window.UpdateDirty(box);
736 void SetRootWindowState(Window window, WindowState state, bool visible)
740 void FlashRootWindow(Window window)
745 void ActivateRootWindow(Window window)
750 // --- Mouse-based window movement ---
752 void StartMoving(Window window, int x, int y, bool fromKeyBoard)
757 void StopMoving(Window window)
762 // -- Mouse manipulation ---
764 void GetMousePosition(int *x, int *y)
770 void SetMousePosition(int x, int y)
776 void SetMouseRange(Window window, Box box)
780 void SetMouseCapture(Window window)
784 // -- Mouse cursor ---
786 void SetMouseCursor(Window window, int cursor)
796 void SetCaret(int x, int y, int size)
798 Window caretOwner = guiApp.caretOwner;
799 Window window = caretOwner ? caretOwner.rootWindow : null;
800 if(window && window.windowData)
805 void ClearClipboard()
809 delete clipBoardData;
813 bool AllocateClipboard(ClipBoard clipBoard, uint size)
816 if((clipBoard.text = new0 byte[size]))
821 bool SaveClipboard(ClipBoard clipBoard)
827 delete clipBoardData;
829 clipBoardData = clipBoard.text;
830 clipBoard.text = null;
836 bool LoadClipboard(ClipBoard clipBoard)
840 // The data is inside this client...
843 clipBoard.text = new char[strlen(clipBoardData)+1];
844 strcpy(clipBoard.text, clipBoardData);
847 // The data is with another client...
854 void UnloadClipboard(ClipBoard clipBoard)
856 delete clipBoard.text;
859 // --- State based input ---
861 bool AcquireInput(Window window, bool state)
866 bool GetMouseState(MouseButtons * buttons, int * x, int * y)
874 bool GetJoystickState(int device, Joystick joystick)
880 bool GetKeyState(Key key)
882 bool keyState = false;
886 void SetTimerResolution(uint hertz)
888 // timerDelay = hertz ? (1000000 / hertz) : MAXINT;
891 bool SetIcon(Window window, BitmapResource resource)
896 if(bitmap.Load(resource.fileName, null, null))
912 static AndroidActivity androidActivity;
914 default const char * AndroidInterface_GetLibLocation(Application a)
916 static char loc[MAX_LOCATION];
917 // sprintf(loc, "/data/data/com.ecere.%s/lib/lib", a.argv[0]);
918 sprintf(loc, "/data/app/com.ecere.%s-1/lib/arm64/lib", a.argv[0]);
924 default float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
925 int32_t axis, size_t pointer_index);
928 static define AMETA_META_ON = 0x00010000;
929 static define AMETA_META_LEFT_ON = 0x00020000;
930 static define AMETA_META_RIGHT_ON = 0x00040000;
932 static Key keyCodeTable[] =
934 0, //AKEYCODE_UNKNOWN = 0,
935 0, //AKEYCODE_SOFT_LEFT = 1,
936 0, //AKEYCODE_SOFT_RIGHT = 2,
937 0, //AKEYCODE_HOME = 3,
938 0, //AKEYCODE_BACK = 4,
939 0, //AKEYCODE_CALL = 5,
940 0, //AKEYCODE_ENDCALL = 6,
941 k0, //AKEYCODE_0 = 7,
942 k1, //AKEYCODE_1 = 8,
943 k2, //AKEYCODE_2 = 9,
944 k3, //AKEYCODE_3 = 10,
945 k4, //AKEYCODE_4 = 11,
946 k5, //AKEYCODE_5 = 12,
947 k6, //AKEYCODE_6 = 13,
948 k7, //AKEYCODE_7 = 14,
949 k8, //AKEYCODE_8 = 15,
950 k9, //AKEYCODE_9 = 16,
951 keyPadStar, //AKEYCODE_STAR = 17,
952 Key { k3, shift = true }, //AKEYCODE_POUND = 18,
953 up, //AKEYCODE_DPAD_UP = 19,
954 down, //AKEYCODE_DPAD_DOWN = 20,
955 left, //AKEYCODE_DPAD_LEFT = 21,
956 right, //AKEYCODE_DPAD_RIGHT = 22,
957 keyPad5, //AKEYCODE_DPAD_CENTER = 23,
958 0, //AKEYCODE_VOLUME_UP = 24,
959 0, //AKEYCODE_VOLUME_DOWN = 25,
960 0, //AKEYCODE_POWER = 26,
961 0, //AKEYCODE_CAMERA = 27,
962 0, //AKEYCODE_CLEAR = 28,
963 a, //AKEYCODE_A = 29,
964 b, //AKEYCODE_B = 30,
965 c, //AKEYCODE_C = 31,
966 d, //AKEYCODE_D = 32,
967 e, //AKEYCODE_E = 33,
968 f, //AKEYCODE_F = 34,
969 g, //AKEYCODE_G = 35,
970 h, //AKEYCODE_H = 36,
971 i, //AKEYCODE_I = 37,
972 j, //AKEYCODE_J = 38,
973 k, //AKEYCODE_K = 39,
974 l, //AKEYCODE_L = 40,
975 m, //AKEYCODE_M = 41,
976 n, //AKEYCODE_N = 42,
977 o, //AKEYCODE_O = 43,
978 p, //AKEYCODE_P = 44,
979 q, //AKEYCODE_Q = 45,
980 r, //AKEYCODE_R = 46,
981 s, //AKEYCODE_S = 47,
982 t, //AKEYCODE_T = 48,
983 u, //AKEYCODE_U = 49,
984 v, //AKEYCODE_V = 50,
985 w, //AKEYCODE_W = 51,
986 x, //AKEYCODE_X = 52,
987 y, //AKEYCODE_Y = 53,
988 z, //AKEYCODE_Z = 54,
989 comma, //AKEYCODE_COMMA = 55,
990 period, //AKEYCODE_PERIOD = 56,
991 leftAlt, //AKEYCODE_ALT_LEFT = 57,
992 rightAlt, //AKEYCODE_ALT_RIGHT = 58,
993 leftShift, //AKEYCODE_SHIFT_LEFT = 59,
994 rightShift, //AKEYCODE_SHIFT_RIGHT = 60,
995 tab, //AKEYCODE_TAB = 61,
996 space, //AKEYCODE_SPACE = 62,
997 0, //AKEYCODE_SYM = 63,
998 0, //AKEYCODE_EXPLORER = 64,
999 0, //AKEYCODE_ENVELOPE = 65,
1000 enter, //AKEYCODE_ENTER = 66,
1001 backSpace, //AKEYCODE_DEL = 67,
1002 backQuote, //AKEYCODE_GRAVE = 68,
1003 minus, //AKEYCODE_MINUS = 69,
1004 plus, //AKEYCODE_EQUALS = 70,
1005 leftBracket, //AKEYCODE_LEFT_BRACKET = 71,
1006 rightBracket, //AKEYCODE_RIGHT_BRACKET = 72,
1007 backSlash, //AKEYCODE_BACKSLASH = 73,
1008 semicolon, //AKEYCODE_SEMICOLON = 74,
1009 quote, //AKEYCODE_APOSTROPHE = 75,
1010 slash, //AKEYCODE_SLASH = 76,
1011 Key { k2, shift = true }, //AKEYCODE_AT = 77,
1012 0, //AKEYCODE_NUM = 78, // Interpreted as an Alt
1013 0, //AKEYCODE_HEADSETHOOK = 79,
1014 0, //AKEYCODE_FOCUS = 80, // *Camera* focus
1015 keyPadPlus, //AKEYCODE_PLUS = 81,
1016 0, //AKEYCODE_MENU = 82,
1017 0, //AKEYCODE_NOTIFICATION = 83,
1018 0, //AKEYCODE_SEARCH = 84,
1019 0, //AKEYCODE_MEDIA_PLAY_PAUSE= 85,
1020 0, //AKEYCODE_MEDIA_STOP = 86,
1021 0, //AKEYCODE_MEDIA_NEXT = 87,
1022 0, //AKEYCODE_MEDIA_PREVIOUS = 88,
1023 0, //AKEYCODE_MEDIA_REWIND = 89,
1024 0, //AKEYCODE_MEDIA_FAST_FORWARD = 90,
1025 0, //AKEYCODE_MUTE = 91,
1026 0, //AKEYCODE_PAGE_UP = 92,
1027 0, //AKEYCODE_PAGE_DOWN = 93,
1028 0, //AKEYCODE_PICTSYMBOLS = 94,
1029 0, //AKEYCODE_SWITCH_CHARSET = 95,
1030 0, //AKEYCODE_BUTTON_A = 96,
1031 0, //AKEYCODE_BUTTON_B = 97,
1032 0, //AKEYCODE_BUTTON_C = 98,
1033 0, //AKEYCODE_BUTTON_X = 99,
1034 0, //AKEYCODE_BUTTON_Y = 100,
1035 0, //AKEYCODE_BUTTON_Z = 101,
1036 0, //AKEYCODE_BUTTON_L1 = 102,
1037 0, //AKEYCODE_BUTTON_R1 = 103,
1038 0, //AKEYCODE_BUTTON_L2 = 104,
1039 0, //AKEYCODE_BUTTON_R2 = 105,
1040 0, //AKEYCODE_BUTTON_THUMBL = 106,
1041 0, //AKEYCODE_BUTTON_THUMBR = 107,
1042 0, //AKEYCODE_BUTTON_START = 108,
1043 0, //AKEYCODE_BUTTON_SELECT = 109,
1044 0, //AKEYCODE_BUTTON_MODE = 110,
1045 escape, //AKEYCODE_BUTTON_ESCAPE = 111,
1046 del, //AKEYCODE_BUTTON_ESCAPE = 112,
1047 leftControl, // = 113
1048 rightControl, // = 114
1050 scrollLock, // = 116
1051 0, // = 117 KEYCODE_META_LEFT
1052 0, // = 118 KEYCODE_META_RIGHT
1053 0, // = 119 KEYCODE_FUNCTION
1054 printScreen, // = 120 KEYCODE_SYSRQ
1055 pauseBreak, // = 121
1061 // Why don't we have this in the NDK :(
1062 // default int32_t AKeyEvent_getUnichar(const AInputEvent* key_event);
1064 static Array<TouchPointerInfo> buildPointerInfo(AInputEvent * event)
1066 uint count = (uint)AMotionEvent_getPointerCount(event);
1067 Array<TouchPointerInfo> infos { size = count };
1069 for(i = 0; i < count; i++)
1071 infos[i].x = (int)AMotionEvent_getX(event, i);
1072 infos[i].y = (int)AMotionEvent_getY(event, i);
1073 infos[i].id = (int)AMotionEvent_getPointerId(event, i);
1074 infos[i].pressure = AMotionEvent_getPressure(event, i);
1075 infos[i].size = AMotionEvent_getSize(event, i);
1080 class AndroidActivity : AndroidAppGlue
1082 AndroidPollSource source;
1086 ASensorManager* sensorManager;
1087 const ASensor* accelerometerSensor;
1088 ASensorEventQueue* sensorEventQueue;
1092 int onInputEvent(AInputEvent* event)
1094 static Time lastTime = 0;
1095 Window window = guiApp.desktop;
1096 uint type = AInputEvent_getType(event);
1097 if(type == AINPUT_EVENT_TYPE_MOTION)
1099 uint actionAndIndex = AMotionEvent_getAction(event);
1100 //uint source = AInputEvent_getSource(event);
1101 uint action = actionAndIndex & AMOTION_EVENT_ACTION_MASK;
1102 //uint index = (actionAndIndex & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
1103 //uint flags = AMotionEvent_getFlags(event);
1104 uint meta = AMotionEvent_getMetaState(event);
1105 //uint edge = AMotionEvent_getEdgeFlags(event);
1106 //int64 downTime = AMotionEvent_getDownTime(event); // nanotime
1107 //int64 eventTime = AMotionEvent_getDownTime(event);
1109 Modifiers keyFlags = 0;
1110 int x = (int)AMotionEvent_getX(event, 0);
1111 int y = (int)AMotionEvent_getY(event, 0);
1112 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1113 bool alt = (meta & AMETA_ALT_ON) ? true : false;
1114 //bool sym = (meta & AMETA_SYM_ON) ? true : false;
1116 keyFlags.shift = shift;
1119 //PrintLn("Got a motion input event: ", action);
1121 if(action == 8) //AMOTION_EVENT_ACTION_SCROLL)
1122 axis = AMotionEvent_getAxisValue(event, 9, index); //AMOTION_EVENT_AXIS_VSCROLL);
1125 AInputQueue_finishEvent(inputQueue, event, 1);
1129 case 8: //AMOTION_EVENT_ACTION_SCROLL:
1130 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (axis < 0) ? wheelUp : wheelDown, 0);
1133 case AMOTION_EVENT_ACTION_DOWN:
1135 Time time = GetTime();
1137 if(Abs(x - mouseX) < 40 && Abs(y - mouseY) < 40 && time - lastTime < 0.3)
1138 if(!window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick, x, y, &keyFlags, false, true))
1141 mouseX = x, mouseY = y;
1143 window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown, x, y, &keyFlags, false, true);
1146 Array<TouchPointerInfo> infos = buildPointerInfo(event);
1147 window.MultiTouchMessage(down, infos, &keyFlags, false, true);
1152 case AMOTION_EVENT_ACTION_UP:
1153 mouseX = x, mouseY = y;
1154 if(window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp, x, y, &keyFlags, false, true))
1156 Array<TouchPointerInfo> infos = buildPointerInfo(event);
1157 window.MultiTouchMessage(up, infos, &keyFlags, false, true);
1161 case AMOTION_EVENT_ACTION_MOVE:
1162 mouseX = x, mouseY = y;
1163 if(window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, true))
1165 Array<TouchPointerInfo> infos = buildPointerInfo(event);
1166 window.MultiTouchMessage(move, infos, &keyFlags, false, true);
1170 case AMOTION_EVENT_ACTION_CANCEL: break;
1171 case AMOTION_EVENT_ACTION_OUTSIDE: break;
1172 case AMOTION_EVENT_ACTION_POINTER_DOWN:
1174 Array<TouchPointerInfo> infos = buildPointerInfo(event);
1175 window.MultiTouchMessage(pointerDown, infos, &keyFlags, false, true);
1179 case AMOTION_EVENT_ACTION_POINTER_UP:
1181 Array<TouchPointerInfo> infos = buildPointerInfo(event);
1182 window.MultiTouchMessage(pointerUp, infos, &keyFlags, false, true);
1189 else if(type == AINPUT_EVENT_TYPE_KEY)
1191 uint action = AKeyEvent_getAction(event);
1192 //uint flags = AKeyEvent_getFlags(event);
1193 uint keyCode = AKeyEvent_getKeyCode(event);
1194 uint meta = AKeyEvent_getMetaState(event);
1195 Key key = keyCodeTable[keyCode];
1196 bool shift = (meta & AMETA_SHIFT_ON) ? true : false;
1197 bool alt = (meta & AMETA_ALT_ON || meta & AMETA_ALT_LEFT_ON || meta & AMETA_ALT_RIGHT_ON) ? true : false;
1198 //bool metaMeta = (meta & AMETA_META_ON || meta & AMETA_META_LEFT_ON || meta & AMETA_META_RIGHT_ON) ? true : false;
1199 //bool sym = (meta & AMETA_SYM_ON) ? true : false;
1200 //unichar ch = AKeyEvent_getUnichar(event);
1206 AInputQueue_finishEvent(inputQueue, event, 1);
1208 // PrintLn("Got a key: action = ", action, ", flags = ", flags, ", keyCode = ", keyCode, ", meta = ", meta, ": key = ", (int)key);
1212 if(action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_MULTIPLE)
1214 /*if(key == wheelDown || key == wheelUp)
1215 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, key, ch);
1218 char c = Interface::TranslateKey(key.code, shift);
1220 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, key, ch);
1223 else if(action == AKEY_EVENT_ACTION_UP)
1224 window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, ch);
1229 AInputQueue_finishEvent(inputQueue, event, 0);
1233 void onAppCmd(AppCommand cmd)
1238 setSavedState(&state, sizeof(state));
1245 ANativeWindow_setBuffersGeometry(window, 0, 0, 0); //format);
1246 w = ANativeWindow_getWidth(window);
1247 h = ANativeWindow_getHeight(window);
1248 guiApp.Initialize(false);
1249 guiApp.desktop.windowHandle = window;
1250 guiApp.interfaceDriver = null;
1251 guiApp.SwitchMode(true, null, 0, 0, 0, null, false);
1253 if(desktopW != w || desktopH != h)
1255 guiApp.SetDesktopPosition(0, 0, w, h, true);
1259 guiApp.desktop.Update(null);
1263 guiApp.desktop.UnloadGraphics(false);
1266 guiApp.desktop.Update(null);
1267 guiApp.SetAppFocus(true);
1269 if(accelerometerSensor)
1271 ASensorEventQueue_enableSensor(sensorEventQueue, accelerometerSensor);
1272 ASensorEventQueue_setEventRate(sensorEventQueue, accelerometerSensor, (1000L/60)*1000);
1278 if(accelerometerSensor)
1279 ASensorEventQueue_disableSensor(sensorEventQueue, accelerometerSensor);
1281 guiApp.SetAppFocus(false);
1282 guiApp.desktop.Update(null);
1286 guiApp.desktop.UpdateDisplay();
1293 androidActivity = this;
1294 /* Let's have fun with sensors when we have an actual device to play with
1295 sensorManager = ASensorManager_getInstance();
1296 accelerometerSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
1297 sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LooperID::user, null, null);
1301 state = *(SavedState*)savedState;
1306 // Evolve the Application class into a GuiApplication
1307 eInstance_Evolve((Instance *)&__androidCurrentModule, class(GuiApplication));
1309 // Wait for the initWindow command:
1310 guiApp.interfaceDriver = class(AndroidInterface);
1313 // Can't call the GuiApplication here, because GuiApplication::Initialize() has not been called yet
1314 guiApp.interfaceDriver.Wait();
1315 guiApp.interfaceDriver.ProcessInput(true);
1318 // Invoke __ecereDll_Load() in lib[our package name].so
1319 app = eModule_Load(__androidCurrentModule, moduleName, publicAccess);
1323 // Find out if any GuiApplication class was defined in our module
1324 for(c = app.classes.first; c && !eClass_IsDerived(c, class(GuiApplication)); c = c.next);
1325 if(!c) c = class(GuiApplication);
1327 guiApp.lockMutex.Release(); // TOCHECK: Seems the evolve is losing our mutex lock here ?
1329 // Evolve the Application into it
1330 eInstance_Evolve((Instance *)&__androidCurrentModule, c);
1331 guiApp = (GuiApplication)__androidCurrentModule;
1334 const String skin = guiApp.skin;
1335 *&guiApp.currentSkin = null;
1336 guiApp.SelectSkin(skin);
1339 guiApp.lockMutex.Wait();
1342 ((void (*)(void *))(void *)__androidCurrentModule._vTbl[12])(__androidCurrentModule);
1345 if(!destroyRequested)
1346 ANativeActivity_finish(activity);
1347 while(!destroyRequested)
1349 guiApp.interfaceDriver.Wait();
1350 guiApp.interfaceDriver.ProcessInput(true);