lib/android: intro motion down_time
[nit.git] / lib / android / input_events.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 # Pointer and hardware key events
18 module input_events
19
20 import mnit::input
21 import android::game
22
23 in "C header" `{
24 #include <android/log.h>
25 #include <android_native_app_glue.h>
26
27 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
28 #ifdef DEBUG
29 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
30 #else
31 #define LOGI(...) (void)0
32 #endif
33 `}
34
35 in "C" `{
36 /* Handle inputs from the Android platform and sort them before
37 sending them in the Nit App */
38 static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
39 App nit_app = app->userData;
40 LOGI("handle input %i", (int)pthread_self());
41 if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
42 LOGI("key");
43 return App_native_input_key(nit_app, event);
44 }
45 else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
46 LOGI("motion");
47 return App_native_input_motion(nit_app, event);
48 }
49
50 return 0;
51 }
52 `}
53
54 private extern class NativeAndroidMotionEvent `{AInputEvent *`}
55
56 fun pointers_count: Int `{
57 return AMotionEvent_getPointerCount(self);
58 `}
59
60 fun edge: Int `{
61 return AMotionEvent_getEdgeFlags(self);
62 `}
63
64 # Get the non-primary pointer id that just went down (returns -1 or > 0)
65 fun index_down_pointer: Int `{
66 int a = AMotionEvent_getAction(self);
67 if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
68 return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
69 else return -1;
70 `}
71
72 fun action: AMotionEventAction `{ return AMotionEvent_getAction(self); `}
73
74 fun native_down_time: Int `{ return AMotionEvent_getDownTime(self); `}
75 end
76
77 private extern class AMotionEventAction `{ int32_t `}
78 fun action: Int `{ return self & AMOTION_EVENT_ACTION_MASK; `}
79
80 # Pointer index concerned by this action
81 #
82 # Require: `is_pointer_down or is_pointer_up`
83 fun pointer_index: Int `{
84 return (self & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
85 `}
86
87 fun is_down: Bool do return action == 0
88 fun is_up: Bool do return action == 1
89 fun is_move: Bool do return action == 2
90 fun is_cancel: Bool do return action == 3
91 fun is_outside: Bool do return action == 4
92 fun is_pointer_down: Bool do return action == 5
93 fun is_pointer_up: Bool do return action == 6
94 end
95
96 # An input event on Android
97 interface AndroidInputEvent
98 super InputEvent
99 end
100
101 # A motion event concerning a single or more `pointers`
102 class AndroidMotionEvent
103 super AndroidInputEvent
104 super MotionEvent
105
106 private var native: NativeAndroidMotionEvent
107
108 # Pointers (or fingers) composing this motion event
109 var pointers: Array[AndroidPointerEvent] is lazy do
110 return [for i in native.pointers_count.times do new AndroidPointerEvent(self, i)]
111 end
112
113 # The pointer (or finger) causing this event
114 var acting_pointer: AndroidPointerEvent is lazy do
115 var action = native.action
116 var index = 0
117
118 if action.is_pointer_down or action.is_pointer_up then
119 index = native.action.pointer_index
120 end
121
122 return new AndroidPointerEvent(self, index)
123 end
124
125 redef fun just_went_down do return native.action.is_down or native.action.is_pointer_down
126
127 # Was the top edge of the screen intersected by this event?
128 fun touch_to_edge: Bool do return native.edge == 1
129
130 # Was the bottom edge of the screen intersected by this event?
131 fun touch_bottom_edge: Bool do return native.edge == 2
132
133 # Was the left edge of the screen intersected by this event?
134 fun touch_left_edge: Bool do return native.edge == 4
135
136 # Was the right edge of the screen intersected by this event?
137 fun touch_right_edge: Bool do return native.edge == 8
138
139 redef fun down_pointer: nullable AndroidPointerEvent
140 do
141 if just_went_down then
142 # The primary pointer went down
143 return pointers[0]
144 end
145
146 var i = native.index_down_pointer
147 if i > 0 then
148 # A secondary pointer went down
149 return pointers[i]
150 else
151 return null
152 end
153 end
154
155 # Time when the user originally pressed down to start a stream of position events
156 #
157 # The return value is in the `java.lang.System.nanoTime()` time base.
158 fun down_time: Int do return native.native_down_time
159 end
160
161 # A pointer event
162 class AndroidPointerEvent
163 super PointerEvent
164 super AndroidInputEvent
165
166 private var motion_event: AndroidMotionEvent
167
168 private var pointer_index: Int
169
170 redef fun x do return native_x(motion_event.native, pointer_index)
171
172 private fun native_x(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
173 return AMotionEvent_getX(motion_event, pointer_index);
174 `}
175
176 redef fun y do return native_y(motion_event.native, pointer_index)
177
178 private fun native_y(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
179 return AMotionEvent_getY(motion_event, pointer_index);
180 `}
181
182 # Pressure applied by this pointer
183 fun pressure: Float do return native_pressure(motion_event.native, pointer_index)
184
185 private fun native_pressure(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
186 return AMotionEvent_getPressure(motion_event, pointer_index);
187 `}
188
189 redef fun pressed
190 do
191 var action = motion_event.native.action
192 return action.is_down or action.is_move or action.is_pointer_down
193 end
194
195 redef fun is_move do return motion_event.acting_pointer == self and
196 motion_event.native.action.is_move
197
198 # Does this pointer just began touching the screen?
199 fun just_went_down: Bool do return motion_event.acting_pointer == self and
200 motion_event.just_went_down
201
202 # Unique id of this pointer since the beginning of the gesture
203 fun pointer_id: Int do return native_pointer_id(motion_event.native, pointer_index)
204
205 private fun native_pointer_id(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Int `{
206 return AMotionEvent_getPointerId(motion_event, pointer_index);
207 `}
208 end
209
210 # An hardware key event
211 extern class AndroidKeyEvent `{AInputEvent *`}
212 super KeyEvent
213 super AndroidInputEvent
214
215 private fun action: Int `{ return AKeyEvent_getAction(self); `}
216
217 redef fun is_down do return action == 0
218 redef fun is_up do return action == 1
219
220 # Hardware code of the key raising this event
221 fun key_code: Int `{ return AKeyEvent_getKeyCode(self); `}
222
223 redef fun to_c
224 do
225 var i = native_to_c
226 if i == 0 then return null
227 return i.code_point
228 end
229
230 private fun native_to_c: Int `{
231 int code = AKeyEvent_getKeyCode(self);
232 if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
233 return '0'+code-AKEYCODE_0;
234 if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
235 return 'a'+code-AKEYCODE_A;
236 return 0;
237 `}
238
239 redef fun name do return key_code.to_s
240
241 # Was this event raised by the back key?
242 fun is_back_key: Bool do return key_code == 4
243
244 # Was this event raised by the menu key?
245 fun is_menu_key: Bool do return key_code == 82
246
247 # Was this event raised by the search key?
248 fun is_search_key: Bool do return key_code == 84
249
250 # Was this event raised by the volume up key?
251 fun is_volume_up: Bool do return key_code == 24
252
253 # Was this event raised by the volume down key?
254 fun is_volume_down: Bool do return key_code == 25
255 end
256
257 redef class App
258
259 redef fun init_window
260 do
261 set_as_input_handler native_app_glue
262 super
263 end
264
265 private fun set_as_input_handler(app_glue: NativeAppGlue)
266 import native_input_key, native_input_motion `{
267 app_glue->onInputEvent = mnit_handle_input;
268 `}
269
270 # these are used as a callback from native to type incoming events
271 private fun native_input_key(event: AndroidKeyEvent): Bool is abstract
272
273 private fun native_input_motion(event: NativeAndroidMotionEvent): Bool is abstract
274 end