lib/github: handles github files
[nit.git] / lib / mnit_android / android_app.nit
1 # This file is part of NIT (http://www.nitlanguage.org).
2 #
3 # Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Impements the services of `mnit:app` using the API from the Android ndk
18 module android_app is
19 android_manifest_activity """
20 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
21 android:configChanges="orientation|keyboardHidden"
22 android:screenOrientation="portrait""""
23 end
24
25 import mnit
26 import android
27 import mnit::opengles1
28
29 in "C header" `{
30 #include <jni.h>
31 #include <errno.h>
32 #include <android/log.h>
33 #include <android_native_app_glue.h>
34
35 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
36 #ifdef DEBUG
37 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
38 #else
39 #define LOGI(...) (void)0
40 #endif
41 `}
42
43 in "C" `{
44 #include <EGL/egl.h>
45 #include <GLES/gl.h>
46 #define GL_GLEXT_PROTOTYPES 1
47 #include <GLES/glext.h>
48 #include <errno.h>
49
50 extern EGLDisplay mnit_display;
51 extern EGLSurface mnit_surface;
52 extern EGLContext mnit_context;
53 extern EGLConfig mnit_config;
54 extern int32_t mnit_width;
55 extern int32_t mnit_height;
56 extern float mnit_zoom;
57
58 //int mnit_orientation_changed;
59 float mnit_zoom;
60
61 /* Handle inputs from the Android platform and sort them before
62 sending them in the Nit App */
63 static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
64 App nit_app = app->userData;
65 LOGI("handle input %i", (int)pthread_self());
66 if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
67 LOGI("key");
68 return App_extern_input_key(nit_app, event);
69 }
70 else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
71 LOGI("motion");
72 return App_extern_input_motion(nit_app, event);
73 }
74
75 return 0;
76 }
77 `}
78
79
80 extern class InnerAndroidMotionEvent in "C" `{AInputEvent *`}
81 super Pointer
82 private fun pointers_count: Int is extern `{
83 return AMotionEvent_getPointerCount(recv);
84 `}
85 private fun just_went_down: Bool is extern `{
86 return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
87 `}
88 private fun edge: Int is extern `{
89 return AMotionEvent_getEdgeFlags(recv);
90 `}
91 private fun index_down_pointer: Int is extern `{
92 int a = AMotionEvent_getAction(recv);
93 if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
94 return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
95 else return -1;
96 `}
97
98 private fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
99 end
100
101 extern class AMotionEventAction `{ int32_t `}
102 protected fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
103 fun is_down: Bool do return action == 0
104 fun is_up: Bool do return action == 1
105 fun is_move: Bool do return action == 2
106 fun is_cancel: Bool do return action == 3
107 fun is_outside: Bool do return action == 4
108 fun is_pointer_down: Bool do return action == 5
109 fun is_pointer_up: Bool do return action == 6
110 end
111
112 interface AndroidInputEvent
113 super InputEvent
114 end
115
116 class AndroidMotionEvent
117 super AndroidInputEvent
118 super MotionEvent
119
120 private init(ie: InnerAndroidMotionEvent) do inner_event = ie
121 private var inner_event: InnerAndroidMotionEvent
122
123 private var pointers_cache: nullable Array[AndroidPointerEvent] = null
124 fun pointers: Array[AndroidPointerEvent]
125 do
126 if pointers_cache != null then
127 return pointers_cache.as(not null)
128 else
129 var pointers = new Array[AndroidPointerEvent]
130 var pointers_count = inner_event.pointers_count
131 for i in [0 .. pointers_count [do
132 var pointer_event = new AndroidPointerEvent(self, i)
133 pointers.add(pointer_event)
134 end
135 pointers_cache = pointers
136 return pointers
137 end
138 end
139
140 redef fun just_went_down: Bool do return inner_event.just_went_down
141 fun edge: Int do return inner_event.edge
142
143 redef fun down_pointer: nullable AndroidPointerEvent
144 do
145 var i = inner_event.index_down_pointer
146 if i > 0 then
147 return pointers[i]
148 else
149 return null
150 end
151 end
152 end
153
154 class AndroidPointerEvent
155 super PointerEvent
156 super AndroidInputEvent
157
158 protected var motion_event: AndroidMotionEvent
159 protected var pointer_id: Int
160
161 redef fun x: Float do return extern_x(motion_event.inner_event, pointer_id)
162 private fun extern_x(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
163 return ((int) AMotionEvent_getX(motion_event, pointer_id));
164 `}
165
166 redef fun y: Float do return extern_y(motion_event.inner_event, pointer_id)
167 private fun extern_y(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
168 return ((int) AMotionEvent_getY(motion_event, pointer_id));
169 `}
170
171 fun pressure: Float do return extern_pressure(motion_event.inner_event, pointer_id)
172 private fun extern_pressure(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
173 return AMotionEvent_getPressure(motion_event, pointer_id);
174 `}
175
176 redef fun pressed
177 do
178 var action = motion_event.inner_event.action
179 return action.is_down or action.is_move
180 end
181
182 redef fun depressed do return not pressed
183 end
184
185 extern class AndroidKeyEvent in "C" `{AInputEvent *`}
186 super KeyEvent
187 super AndroidInputEvent
188
189 fun action: Int is extern `{
190 return AKeyEvent_getAction(recv);
191 `}
192 redef fun is_down: Bool do return action == 0
193 redef fun is_up: Bool do return action == 1
194
195 fun key_code: Int is extern `{
196 return AKeyEvent_getKeyCode(recv);
197 `}
198
199 redef fun to_c `{
200 int code = AKeyEvent_getKeyCode(recv);
201 if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
202 return '0'+code-AKEYCODE_0;
203 if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
204 return 'a'+code-AKEYCODE_A;
205 return 0;
206 `}
207
208 fun is_back_key: Bool do return key_code == 4
209 fun is_menu_key: Bool do return key_code == 82
210 fun is_search_key: Bool do return key_code == 84
211
212 fun is_volume_up: Bool do return key_code == 24
213 fun is_volume_down: Bool do return key_code == 25
214 end
215
216 redef class App
217 redef type D: Opengles1Display
218
219 redef fun init_window
220 do
221 set_as_input_handler native_app_glue
222 display = new Opengles1Display
223
224 super
225 end
226
227 private fun set_as_input_handler(app_glue: NativeAppGlue) import extern_input_key, extern_input_motion `{
228 app_glue->onInputEvent = mnit_handle_input;
229 `}
230
231 redef fun full_frame do if not paused then super
232
233 # these are used as a callback from native to type incoming events
234 private fun extern_input_key(event: AndroidKeyEvent): Bool
235 do
236 return input(event)
237 end
238 private fun extern_input_motion(event: InnerAndroidMotionEvent): Bool
239 do
240 var ie = new AndroidMotionEvent(event)
241 var handled = input(ie)
242
243 if not handled then
244 for pe in ie.pointers do
245 input(pe)
246 end
247 end
248
249 return handled
250 end
251
252 redef fun generate_input do poll_looper 0
253 end