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