android: extract Android input events from `mnit_android`
[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_extern_input_key(nit_app, event);
44 }
45 else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
46 LOGI("motion");
47 return App_extern_input_motion(nit_app, event);
48 }
49
50 return 0;
51 }
52 `}
53
54
55 extern class InnerAndroidMotionEvent in "C" `{AInputEvent *`}
56 super Pointer
57 private fun pointers_count: Int is extern `{
58 return AMotionEvent_getPointerCount(recv);
59 `}
60 private fun just_went_down: Bool is extern `{
61 return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
62 `}
63 private fun edge: Int is extern `{
64 return AMotionEvent_getEdgeFlags(recv);
65 `}
66 private fun index_down_pointer: Int is extern `{
67 int a = AMotionEvent_getAction(recv);
68 if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
69 return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
70 else return -1;
71 `}
72
73 private fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
74 end
75
76 extern class AMotionEventAction `{ int32_t `}
77 protected fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
78 fun is_down: Bool do return action == 0
79 fun is_up: Bool do return action == 1
80 fun is_move: Bool do return action == 2
81 fun is_cancel: Bool do return action == 3
82 fun is_outside: Bool do return action == 4
83 fun is_pointer_down: Bool do return action == 5
84 fun is_pointer_up: Bool do return action == 6
85 end
86
87 interface AndroidInputEvent
88 super InputEvent
89 end
90
91 class AndroidMotionEvent
92 super AndroidInputEvent
93 super MotionEvent
94
95 private init(ie: InnerAndroidMotionEvent) do inner_event = ie
96 private var inner_event: InnerAndroidMotionEvent
97
98 private var pointers_cache: nullable Array[AndroidPointerEvent] = null
99 fun pointers: Array[AndroidPointerEvent]
100 do
101 if pointers_cache != null then
102 return pointers_cache.as(not null)
103 else
104 var pointers = new Array[AndroidPointerEvent]
105 var pointers_count = inner_event.pointers_count
106 for i in [0 .. pointers_count [do
107 var pointer_event = new AndroidPointerEvent(self, i)
108 pointers.add(pointer_event)
109 end
110 pointers_cache = pointers
111 return pointers
112 end
113 end
114
115 redef fun just_went_down: Bool do return inner_event.just_went_down
116 fun edge: Int do return inner_event.edge
117
118 redef fun down_pointer: nullable AndroidPointerEvent
119 do
120 var i = inner_event.index_down_pointer
121 if i > 0 then
122 return pointers[i]
123 else
124 return null
125 end
126 end
127 end
128
129 class AndroidPointerEvent
130 super PointerEvent
131 super AndroidInputEvent
132
133 protected var motion_event: AndroidMotionEvent
134 protected var pointer_id: Int
135
136 redef fun x: Float do return extern_x(motion_event.inner_event, pointer_id)
137 private fun extern_x(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
138 return AMotionEvent_getX(motion_event, pointer_id);
139 `}
140
141 redef fun y: Float do return extern_y(motion_event.inner_event, pointer_id)
142 private fun extern_y(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
143 return AMotionEvent_getY(motion_event, pointer_id);
144 `}
145
146 fun pressure: Float do return extern_pressure(motion_event.inner_event, pointer_id)
147 private fun extern_pressure(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
148 return AMotionEvent_getPressure(motion_event, pointer_id);
149 `}
150
151 redef fun pressed
152 do
153 var action = motion_event.inner_event.action
154 return action.is_down or action.is_move
155 end
156
157 redef fun depressed do return not pressed
158 end
159
160 extern class AndroidKeyEvent in "C" `{AInputEvent *`}
161 super KeyEvent
162 super AndroidInputEvent
163
164 fun action: Int is extern `{
165 return AKeyEvent_getAction(recv);
166 `}
167 redef fun is_down: Bool do return action == 0
168 redef fun is_up: Bool do return action == 1
169
170 fun key_code: Int is extern `{
171 return AKeyEvent_getKeyCode(recv);
172 `}
173
174 redef fun to_c `{
175 int code = AKeyEvent_getKeyCode(recv);
176 if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
177 return '0'+code-AKEYCODE_0;
178 if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
179 return 'a'+code-AKEYCODE_A;
180 return 0;
181 `}
182
183 fun is_back_key: Bool do return key_code == 4
184 fun is_menu_key: Bool do return key_code == 82
185 fun is_search_key: Bool do return key_code == 84
186
187 fun is_volume_up: Bool do return key_code == 24
188 fun is_volume_down: Bool do return key_code == 25
189 end
190
191 redef class App
192
193 redef fun init_window
194 do
195 set_as_input_handler native_app_glue
196 super
197 end
198
199 private fun set_as_input_handler(app_glue: NativeAppGlue) import extern_input_key, extern_input_motion `{
200 app_glue->onInputEvent = mnit_handle_input;
201 `}
202
203 # these are used as a callback from native to type incoming events
204 private fun extern_input_key(event: AndroidKeyEvent): Bool is abstract
205
206 private fun extern_input_motion(event: InnerAndroidMotionEvent): Bool is abstract
207 end