1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 /*
23 Contributed by Brandon Schaefer, <brandon.schaefer@canonical.com>
24 */
25
26 #include "../../SDL_internal.h"
27
28 #if SDL_VIDEO_DRIVER_MIR
29
30 #include "../../events/SDL_events_c.h"
31 #include "../../events/SDL_keyboard_c.h"
32 #include "../../events/SDL_touch_c.h"
33 #include "../../events/scancodes_xfree86.h"
34
35 #include "SDL_mirevents.h"
36 #include "SDL_mirwindow.h"
37
38 #include <xkbcommon/xkbcommon.h>
39
40 #include "SDL_mirdyn.h"
41
42 static void
HandleKeyText(int32_t key_code)43 HandleKeyText(int32_t key_code)
44 {
45 char text[8];
46 int size = 0;
47
48 size = MIR_xkb_keysym_to_utf8(key_code, text, sizeof text);
49
50 if (size > 0) {
51 text[size] = '\0';
52 SDL_SendKeyboardText(text);
53 }
54 }
55
56 /* FIXME
57 Mir still needs to implement its IM API, for now we assume
58 a single key press produces a character.
59 */
60 static void
HandleKeyEvent(MirKeyboardEvent const * key_event,SDL_Window * window)61 HandleKeyEvent(MirKeyboardEvent const* key_event, SDL_Window* window)
62 {
63 xkb_keysym_t key_code;
64 Uint8 key_state;
65 int event_scancode;
66 uint32_t sdl_scancode = SDL_SCANCODE_UNKNOWN;
67
68 MirKeyboardAction action = MIR_mir_keyboard_event_action(key_event);
69
70 key_state = SDL_PRESSED;
71 key_code = MIR_mir_keyboard_event_key_code(key_event);
72 event_scancode = MIR_mir_keyboard_event_scan_code(key_event);
73
74 if (action == mir_keyboard_action_up)
75 key_state = SDL_RELEASED;
76
77 if (event_scancode < SDL_arraysize(xfree86_scancode_table2))
78 sdl_scancode = xfree86_scancode_table2[event_scancode];
79
80 if (sdl_scancode != SDL_SCANCODE_UNKNOWN)
81 SDL_SendKeyboardKey(key_state, sdl_scancode);
82
83 if (key_state == SDL_PRESSED)
84 HandleKeyText(key_code);
85 }
86
87 static void
HandleMouseButton(SDL_Window * sdl_window,Uint8 state,MirPointerEvent const * pointer)88 HandleMouseButton(SDL_Window* sdl_window, Uint8 state, MirPointerEvent const* pointer)
89 {
90 uint32_t sdl_button = SDL_BUTTON_LEFT;
91 MirPointerButton button_state = mir_pointer_button_primary;
92
93 static uint32_t old_button_states = 0;
94 uint32_t new_button_states = MIR_mir_pointer_event_buttons(pointer);
95
96 // XOR on our old button states vs our new states to get the newley pressed/released button
97 button_state = new_button_states ^ old_button_states;
98
99 switch (button_state) {
100 case mir_pointer_button_primary:
101 sdl_button = SDL_BUTTON_LEFT;
102 break;
103 case mir_pointer_button_secondary:
104 sdl_button = SDL_BUTTON_RIGHT;
105 break;
106 case mir_pointer_button_tertiary:
107 sdl_button = SDL_BUTTON_MIDDLE;
108 break;
109 case mir_pointer_button_forward:
110 sdl_button = SDL_BUTTON_X1;
111 break;
112 case mir_pointer_button_back:
113 sdl_button = SDL_BUTTON_X2;
114 break;
115 default:
116 break;
117 }
118
119 old_button_states = new_button_states;
120
121 SDL_SendMouseButton(sdl_window, 0, state, sdl_button);
122 }
123
124 static void
HandleMouseMotion(SDL_Window * sdl_window,int x,int y)125 HandleMouseMotion(SDL_Window* sdl_window, int x, int y)
126 {
127 SDL_Mouse* mouse = SDL_GetMouse();
128 SDL_SendMouseMotion(sdl_window, 0, mouse->relative_mode, x, y);
129 }
130
131 static void
HandleTouchPress(int device_id,int source_id,SDL_bool down,float x,float y,float pressure)132 HandleTouchPress(int device_id, int source_id, SDL_bool down, float x, float y, float pressure)
133 {
134 SDL_SendTouch(device_id, source_id, down, x, y, pressure);
135 }
136
137 static void
HandleTouchMotion(int device_id,int source_id,float x,float y,float pressure)138 HandleTouchMotion(int device_id, int source_id, float x, float y, float pressure)
139 {
140 SDL_SendTouchMotion(device_id, source_id, x, y, pressure);
141 }
142
143 static void
HandleMouseScroll(SDL_Window * sdl_window,int hscroll,int vscroll)144 HandleMouseScroll(SDL_Window* sdl_window, int hscroll, int vscroll)
145 {
146 SDL_SendMouseWheel(sdl_window, 0, hscroll, vscroll, SDL_MOUSEWHEEL_NORMAL);
147 }
148
149 static void
AddTouchDevice(int device_id)150 AddTouchDevice(int device_id)
151 {
152 if (SDL_AddTouch(device_id, "") < 0)
153 SDL_SetError("Error: can't add touch %s, %d", __FILE__, __LINE__);
154 }
155
156 static void
HandleTouchEvent(MirTouchEvent const * touch,int device_id,SDL_Window * sdl_window)157 HandleTouchEvent(MirTouchEvent const* touch, int device_id, SDL_Window* sdl_window)
158 {
159 int i, point_count;
160 point_count = MIR_mir_touch_event_point_count(touch);
161
162 AddTouchDevice(device_id);
163
164 for (i = 0; i < point_count; i++) {
165 int id = MIR_mir_touch_event_id(touch, i);
166
167 int width = sdl_window->w;
168 int height = sdl_window->h;
169
170 float x = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_x);
171 float y = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_y);
172
173 float n_x = x / width;
174 float n_y = y / height;
175
176 float pressure = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_pressure);
177
178 switch (MIR_mir_touch_event_action(touch, i)) {
179 case mir_touch_action_up:
180 HandleTouchPress(device_id, id, SDL_FALSE, n_x, n_y, pressure);
181 break;
182 case mir_touch_action_down:
183 HandleTouchPress(device_id, id, SDL_TRUE, n_x, n_y, pressure);
184 break;
185 case mir_touch_action_change:
186 HandleTouchMotion(device_id, id, n_x, n_y, pressure);
187 break;
188 case mir_touch_actions:
189 break;
190 }
191 }
192 }
193
194 static void
HandleMouseEvent(MirPointerEvent const * pointer,SDL_Window * sdl_window)195 HandleMouseEvent(MirPointerEvent const* pointer, SDL_Window* sdl_window)
196 {
197 SDL_SetMouseFocus(sdl_window);
198
199 switch (MIR_mir_pointer_event_action(pointer)) {
200 case mir_pointer_action_button_down:
201 HandleMouseButton(sdl_window, SDL_PRESSED, pointer);
202 break;
203 case mir_pointer_action_button_up:
204 HandleMouseButton(sdl_window, SDL_RELEASED, pointer);
205 break;
206 case mir_pointer_action_motion: {
207 int x, y;
208 int hscroll, vscroll;
209 SDL_Mouse* mouse = SDL_GetMouse();
210 x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_x);
211 y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_y);
212
213 if (mouse) {
214 if (mouse->relative_mode) {
215 int relative_x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_x);
216 int relative_y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_y);
217 HandleMouseMotion(sdl_window, relative_x, relative_y);
218 }
219 else if (mouse->x != x || mouse->y != y) {
220 HandleMouseMotion(sdl_window, x, y);
221 }
222 }
223
224 hscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_hscroll);
225 vscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_vscroll);
226 if (vscroll != 0 || hscroll != 0)
227 HandleMouseScroll(sdl_window, hscroll, vscroll);
228 }
229 break;
230 case mir_pointer_action_leave:
231 SDL_SetMouseFocus(NULL);
232 break;
233 case mir_pointer_action_enter:
234 default:
235 break;
236 }
237 }
238
239 static void
MIR_HandleInput(MirInputEvent const * input_event,SDL_Window * window)240 MIR_HandleInput(MirInputEvent const* input_event, SDL_Window* window)
241 {
242 switch (MIR_mir_input_event_get_type(input_event)) {
243 case (mir_input_event_type_key):
244 HandleKeyEvent(MIR_mir_input_event_get_keyboard_event(input_event), window);
245 break;
246 case (mir_input_event_type_pointer):
247 HandleMouseEvent(MIR_mir_input_event_get_pointer_event(input_event), window);
248 break;
249 case (mir_input_event_type_touch):
250 HandleTouchEvent(MIR_mir_input_event_get_touch_event(input_event),
251 MIR_mir_input_event_get_device_id(input_event),
252 window);
253 break;
254 default:
255 break;
256 }
257 }
258
259 static void
MIR_HandleResize(MirResizeEvent const * resize_event,SDL_Window * window)260 MIR_HandleResize(MirResizeEvent const* resize_event, SDL_Window* window)
261 {
262 int new_w = MIR_mir_resize_event_get_width (resize_event);
263 int new_h = MIR_mir_resize_event_get_height(resize_event);
264
265 int old_w = window->w;
266 int old_h = window->h;
267
268 if (new_w != old_w || new_h != old_h)
269 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, new_w, new_h);
270 }
271
272 static void
MIR_HandleSurface(MirSurfaceEvent const * surface_event,SDL_Window * window)273 MIR_HandleSurface(MirSurfaceEvent const* surface_event, SDL_Window* window)
274 {
275 MirSurfaceAttrib attrib = MIR_mir_surface_event_get_attribute(surface_event);
276 int value = MIR_mir_surface_event_get_attribute_value(surface_event);
277
278 if (attrib == mir_surface_attrib_focus) {
279 if (value == mir_surface_focused) {
280 SDL_SetKeyboardFocus(window);
281 }
282 else if (value == mir_surface_unfocused) {
283 SDL_SetKeyboardFocus(NULL);
284 }
285 }
286 }
287
288 void
MIR_HandleEvent(MirSurface * surface,MirEvent const * ev,void * context)289 MIR_HandleEvent(MirSurface* surface, MirEvent const* ev, void* context)
290 {
291 MirEventType event_type = MIR_mir_event_get_type(ev);
292 SDL_Window* window = (SDL_Window*)context;
293
294 if (window) {
295 switch (event_type) {
296 case (mir_event_type_input):
297 MIR_HandleInput(MIR_mir_event_get_input_event(ev), window);
298 break;
299 case (mir_event_type_resize):
300 MIR_HandleResize(MIR_mir_event_get_resize_event(ev), window);
301 break;
302 case (mir_event_type_surface):
303 MIR_HandleSurface(MIR_mir_event_get_surface_event(ev), window);
304 break;
305 default:
306 break;
307 }
308 }
309 }
310
311 #endif /* SDL_VIDEO_DRIVER_MIR */
312
313 /* vi: set ts=4 sw=4 expandtab: */
314