lib/android: intro `AndroidPointerEvent::is_move`
[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
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 # Did this motion event just started?
61 fun just_went_down: Bool `{
62 return (AMotionEvent_getAction(self) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
63 `}
64
65 fun edge: Int `{
66 return AMotionEvent_getEdgeFlags(self);
67 `}
68
69 # Get the non-primary pointer id that just went down (returns -1 or > 0)
70 fun index_down_pointer: Int `{
71 int a = AMotionEvent_getAction(self);
72 if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
73 return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
74 else return -1;
75 `}
76
77 fun action: AMotionEventAction `{ return AMotionEvent_getAction(self); `}
78 end
79
80 private extern class AMotionEventAction `{ int32_t `}
81 fun action: Int `{ return self & AMOTION_EVENT_ACTION_MASK; `}
82
83 # Pointer index concerned by this action
84 #
85 # Require: `is_pointer_down or is_pointer_up`
86 fun pointer_index: Int `{
87 return (self & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
88 `}
89
90 fun is_down: Bool do return action == 0
91 fun is_up: Bool do return action == 1
92 fun is_move: Bool do return action == 2
93 fun is_cancel: Bool do return action == 3
94 fun is_outside: Bool do return action == 4
95 fun is_pointer_down: Bool do return action == 5
96 fun is_pointer_up: Bool do return action == 6
97 end
98
99 # An input event on Android
100 interface AndroidInputEvent
101 super InputEvent
102 end
103
104 # A motion event concerning a single or more `pointers`
105 class AndroidMotionEvent
106 super AndroidInputEvent
107 super MotionEvent
108
109 private var native: NativeAndroidMotionEvent
110
111 # Pointers (or fingers) composing this motion event
112 var pointers: Array[AndroidPointerEvent] is lazy do
113 return [for i in native.pointers_count.times do new AndroidPointerEvent(self, i)]
114 end
115
116 # The pointer (or finger) causing this event
117 var acting_pointer: AndroidPointerEvent is lazy do
118 var action = native.action
119 var index = 0
120
121 if action.is_pointer_down or action.is_pointer_up then
122 index = native.action.pointer_index
123 end
124
125 return new AndroidPointerEvent(self, index)
126 end
127
128 redef fun just_went_down do return native.just_went_down
129
130 # Was the top edge of the screen intersected by this event?
131 fun touch_to_edge: Bool do return native.edge == 1
132
133 # Was the bottom edge of the screen intersected by this event?
134 fun touch_bottom_edge: Bool do return native.edge == 2
135
136 # Was the left edge of the screen intersected by this event?
137 fun touch_left_edge: Bool do return native.edge == 4
138
139 # Was the right edge of the screen intersected by this event?
140 fun touch_right_edge: Bool do return native.edge == 8
141
142 redef fun down_pointer: nullable AndroidPointerEvent
143 do
144 if just_went_down then
145 # The primary pointer went down
146 return pointers[0]
147 end
148
149 var i = native.index_down_pointer
150 if i > 0 then
151 # A secondary pointer went down
152 return pointers[i]
153 else
154 return null
155 end
156 end
157 end
158
159 # A pointer event
160 class AndroidPointerEvent
161 super PointerEvent
162 super AndroidInputEvent
163
164 private var motion_event: AndroidMotionEvent
165
166 private var pointer_index: Int
167
168 redef fun x do return native_x(motion_event.native, pointer_index)
169
170 private fun native_x(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
171 return AMotionEvent_getX(motion_event, pointer_index);
172 `}
173
174 redef fun y do return native_y(motion_event.native, pointer_index)
175
176 private fun native_y(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
177 return AMotionEvent_getY(motion_event, pointer_index);
178 `}
179
180 # Pressure applied by this pointer
181 fun pressure: Float do return native_pressure(motion_event.native, pointer_index)
182
183 private fun native_pressure(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Float `{
184 return AMotionEvent_getPressure(motion_event, pointer_index);
185 `}
186
187 redef fun pressed
188 do
189 var action = motion_event.native.action
190 return action.is_down or action.is_move or action.is_pointer_down
191 end
192
193 # Is this a move event?
194 fun is_move: Bool do return motion_event.acting_pointer == self and
195 motion_event.native.action.is_move
196
197 redef fun depressed do return not pressed
198
199 # Does this pointer just began touching the screen?
200 fun just_went_down: Bool
201 do
202 return motion_event.down_pointer == self
203 end
204
205 # Unique id of this pointer since the beginning of the gesture
206 fun pointer_id: Int do return native_pointer_id(motion_event.native, pointer_index)
207
208 private fun native_pointer_id(motion_event: NativeAndroidMotionEvent, pointer_index: Int): Int `{
209 return AMotionEvent_getPointerId(motion_event, pointer_index);
210 `}
211 end
212
213 # An hardware key event
214 extern class AndroidKeyEvent `{AInputEvent *`}
215 super KeyEvent
216 super AndroidInputEvent
217
218 private fun action: Int `{ return AKeyEvent_getAction(self); `}
219
220 redef fun is_down do return action == 0
221 redef fun is_up do return action == 1
222
223 # Hardware code of the key raising this event
224 fun key_code: Int `{ return AKeyEvent_getKeyCode(self); `}
225
226 redef fun to_c `{
227 int code = AKeyEvent_getKeyCode(self);
228 if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
229 return '0'+code-AKEYCODE_0;
230 if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
231 return 'a'+code-AKEYCODE_A;
232 return 0;
233 `}
234
235 redef fun name do return key_code.to_s
236
237 # Was this event raised by the back key?
238 fun is_back_key: Bool do return key_code == 4
239
240 # Was this event raised by the menu key?
241 fun is_menu_key: Bool do return key_code == 82
242
243 # Was this event raised by the search key?
244 fun is_search_key: Bool do return key_code == 84
245
246 # Was this event raised by the volume up key?
247 fun is_volume_up: Bool do return key_code == 24
248
249 # Was this event raised by the volume down key?
250 fun is_volume_down: Bool do return key_code == 25
251 end
252
253 redef class App
254
255 redef fun init_window
256 do
257 set_as_input_handler native_app_glue
258 super
259 end
260
261 private fun set_as_input_handler(app_glue: NativeAppGlue)
262 import native_input_key, native_input_motion `{
263 app_glue->onInputEvent = mnit_handle_input;
264 `}
265
266 # these are used as a callback from native to type incoming events
267 private fun native_input_key(event: AndroidKeyEvent): Bool is abstract
268
269 private fun native_input_motion(event: NativeAndroidMotionEvent): Bool is abstract
270 end