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