1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <SDL2/SDL.h>
6 
7 #include <Eina.h>
8 #include <Ecore.h>
9 #include <ecore_private.h>
10 #include <Ecore_Input.h>
11 #include "Ecore_Sdl.h"
12 #include "Ecore_Sdl_Keys.h"
13 #include "ecore_sdl_private.h"
14 
15 int _ecore_sdl_log_dom = -1;
16 
17 typedef struct _Ecore_SDL_Pressed Ecore_SDL_Pressed;
18 struct _Ecore_SDL_Pressed
19 {
20    EINA_RBTREE;
21 
22    SDL_Keycode key;
23 };
24 
25 EAPI int ECORE_SDL_EVENT_GOT_FOCUS = 0;
26 EAPI int ECORE_SDL_EVENT_LOST_FOCUS = 0;
27 EAPI int ECORE_SDL_EVENT_RESIZE = 0;
28 EAPI int ECORE_SDL_EVENT_EXPOSE = 0;
29 
30 static int _ecore_sdl_init_count = 0;
31 static Eina_Rbtree *repeat = NULL;
32 
33 static Eina_Rbtree_Direction
_ecore_sdl_pressed_key(const Ecore_SDL_Pressed * left,const Ecore_SDL_Pressed * right,EINA_UNUSED void * data)34 _ecore_sdl_pressed_key(const Ecore_SDL_Pressed *left,
35                        const Ecore_SDL_Pressed *right,
36                        EINA_UNUSED void *data)
37 {
38    return left->key < right->key ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
39 }
40 
41 static int
_ecore_sdl_pressed_node(const Ecore_SDL_Pressed * node,const SDL_Keycode * key,EINA_UNUSED int length,EINA_UNUSED void * data)42 _ecore_sdl_pressed_node(const Ecore_SDL_Pressed *node,
43                         const SDL_Keycode *key,
44                         EINA_UNUSED int length,
45                         EINA_UNUSED void *data)
46 {
47    return node->key - *key;
48 }
49 
50 /**
51  * @defgroup Ecore_Sdl_Library_Group SDL Library Functions
52  * @ingroup Ecore
53  *
54  * Functions used to set up and shut down the Ecore_Sdl functions.
55  */
56 
57 /**
58  * Sets up the Ecore_Sdl library.
59  * @param   name device target name
60  * @return  @c 0 on failure.  Otherwise, the number of times the library has
61  *          been initialised without being shut down.
62  * @ingroup Ecore_SDL_Library_Group
63  */
64 EAPI int
ecore_sdl_init(const char * name EINA_UNUSED)65 ecore_sdl_init(const char *name EINA_UNUSED)
66 {
67    if(++_ecore_sdl_init_count != 1)
68      return _ecore_sdl_init_count;
69    _ecore_sdl_log_dom = eina_log_domain_register
70      ("ecore_sdl", ECORE_SDL_DEFAULT_LOG_COLOR);
71    if(_ecore_sdl_log_dom < 0)
72      {
73        EINA_LOG_ERR("Impossible to create a log domain for the Ecore SDL module.");
74        return --_ecore_sdl_init_count;
75      }
76    if (!ecore_event_init())
77      return --_ecore_sdl_init_count;
78 
79    SDL_Init(SDL_INIT_EVENTS);
80 
81    ECORE_SDL_EVENT_GOT_FOCUS  = ecore_event_type_new();
82    ECORE_SDL_EVENT_LOST_FOCUS = ecore_event_type_new();
83    ECORE_SDL_EVENT_RESIZE     = ecore_event_type_new();
84    ECORE_SDL_EVENT_EXPOSE     = ecore_event_type_new();
85 
86    return _ecore_sdl_init_count;
87 }
88 
89 /**
90  * Shuts down the Ecore_Sdl library.
91  * @return  @c The number of times the system has been initialised without
92  *             being shut down.
93  * @ingroup Ecore_SDL_Library_Group
94  */
95 EAPI int
ecore_sdl_shutdown(void)96 ecore_sdl_shutdown(void)
97 {
98    if (--_ecore_sdl_init_count != 0)
99      return _ecore_sdl_init_count;
100 
101    SDL_Quit();
102 
103    ecore_event_type_flush(ECORE_SDL_EVENT_GOT_FOCUS,
104                           ECORE_SDL_EVENT_LOST_FOCUS,
105                           ECORE_SDL_EVENT_RESIZE,
106                           ECORE_SDL_EVENT_EXPOSE);
107 
108    ecore_event_shutdown();
109    eina_log_domain_unregister(_ecore_sdl_log_dom);
110    _ecore_sdl_log_dom = -1;
111    return _ecore_sdl_init_count;
112 }
113 
114 static unsigned int
_ecore_sdl_event_modifiers(int mod)115 _ecore_sdl_event_modifiers(int mod)
116 {
117    unsigned int        modifiers = 0;
118 
119    if(mod & KMOD_LSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
120    if(mod & KMOD_RSHIFT) modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
121    if(mod & KMOD_LCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL;
122    if(mod & KMOD_RCTRL) modifiers |= ECORE_EVENT_MODIFIER_CTRL;
123    if(mod & KMOD_LALT) modifiers |= ECORE_EVENT_MODIFIER_ALT;
124    if(mod & KMOD_RALT) modifiers |= ECORE_EVENT_MODIFIER_ALT;
125    if(mod & KMOD_NUM) modifiers |= ECORE_EVENT_LOCK_NUM;
126    if(mod & KMOD_CAPS) modifiers |= ECORE_EVENT_LOCK_CAPS;
127 
128    return modifiers;
129 }
130 
131 static Ecore_Event_Key*
_ecore_sdl_event_key(SDL_Event * event,double timestamp)132 _ecore_sdl_event_key(SDL_Event *event, double timestamp)
133 {
134    Ecore_Event_Key *ev;
135    unsigned int i;
136 
137    ev = calloc(1, sizeof(Ecore_Event_Key));
138    if (!ev) return NULL;
139 
140    ev->timestamp = timestamp;
141    ev->window = event->key.windowID;
142    ev->event_window = 0;
143    ev->modifiers = _ecore_sdl_event_modifiers(SDL_GetModState());
144    ev->key = NULL;
145    ev->compose = NULL;
146 
147    for (i = 0; i < EINA_C_ARRAY_LENGTH(keystable); ++i)
148      if (keystable[i].code == event->key.keysym.sym)
149        {
150           ev->keyname = keystable[i].name;
151           ev->string = keystable[i].compose;
152 
153           return ev;
154        }
155 
156    free(ev);
157    return NULL;
158 }
159 
160 /**
161  * Poll SDL for mouse, keyboard, and window events, and add corresponding events to ecore.
162  * @ingroup Ecore_SDL_Library_Group
163  */
164 EAPI void
ecore_sdl_feed_events(void)165 ecore_sdl_feed_events(void)
166 {
167    SDL_Event    event;
168    unsigned int timestamp;
169 
170    while(SDL_PollEvent(&event))
171      {
172         timestamp = (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff);
173         switch(event.type)
174           {
175           case SDL_MOUSEMOTION:
176           {
177              Ecore_Event_Mouse_Move *ev;
178 
179              ev = calloc(1, sizeof(Ecore_Event_Mouse_Move));
180              if (!ev) return;
181 
182              ev->timestamp = timestamp;
183              ev->window = event.motion.windowID;
184              ev->event_window = event.motion.windowID;
185              ev->modifiers = 0; /* FIXME: keep modifier around. */
186              ev->x = event.motion.x;
187              ev->y = event.motion.y;
188              ev->root.x = ev->x;
189              ev->root.y = ev->y;
190 
191              /* Must set multi touch device to 0 or it will get ignored */
192              ev->multi.device = 0;
193              ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
194              ev->multi.pressure = ev->multi.angle = 0;
195              ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
196 
197              ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
198              break;
199           }
200           case SDL_MOUSEBUTTONDOWN:
201           {
202              Ecore_Event_Mouse_Button *ev;
203 
204              ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
205              if (!ev) return;
206 
207              ev->timestamp = timestamp;
208              ev->window = event.button.windowID;
209              ev->event_window = event.button.windowID;
210              ev->modifiers = 0; /* FIXME: keep modifier around. */
211              ev->buttons = event.button.button;
212              ev->double_click = 0;
213              ev->triple_click = 0;
214 
215              /* Must set multi touch device to 0 or it will get ignored */
216              ev->multi.device = 0;
217              ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
218              ev->multi.pressure = ev->multi.angle = 0;
219              ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
220 
221              ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
222              break;
223           }
224           case SDL_MOUSEWHEEL:
225           {
226              Ecore_Event_Mouse_Wheel *ev;
227 
228              ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
229              if (!ev) return;
230 
231              ev->timestamp = timestamp;
232              ev->window = event.wheel.windowID;
233              ev->event_window = event.wheel.windowID;
234              ev->modifiers = 0; /* FIXME: keep modifier around. */
235              ev->direction = 0;
236              ev->z = event.wheel.x != 0 ? event.wheel.x : event.wheel.y;
237              ev->direction = event.wheel.x != 0 ? 0 : 1;
238 
239              ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
240              break;
241           }
242           case SDL_MOUSEBUTTONUP:
243           {
244              Ecore_Event_Mouse_Button *ev;
245 
246              ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
247              if (!ev) return;
248              ev->timestamp = timestamp;
249              ev->window = event.button.windowID;
250              ev->event_window = event.button.windowID;
251              ev->modifiers = 0; /* FIXME: keep modifier around. */
252              ev->buttons = event.button.button;
253              ev->double_click = 0;
254              ev->triple_click = 0;
255 
256              /* Must set multi touch device to 0 or it will get ignored */
257              ev->multi.device = 0;
258              ev->multi.radius = ev->multi.radius_x = ev->multi.radius_y = 0;
259              ev->multi.pressure = ev->multi.angle = 0;
260              ev->multi.x = ev->multi.y = ev->multi.root.x = ev->multi.root.y = 0;
261 
262              ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
263              break;
264           }
265           case SDL_QUIT:
266              ecore_main_loop_quit();
267              break;
268 
269           case SDL_KEYDOWN:
270           {
271              Ecore_SDL_Pressed *entry;
272              Ecore_Event_Key *ev;
273 
274              entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym),
275                                                                     EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL);
276              if (entry)
277                {
278                   ev = _ecore_sdl_event_key(&event, timestamp);
279                   if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
280                }
281 
282              ev = _ecore_sdl_event_key(&event, timestamp);
283              if (ev) ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL);
284 
285              if (!entry)
286                {
287                   entry = malloc(sizeof (Ecore_SDL_Pressed));
288                   if (!entry) break;
289 
290                   entry->key = event.key.keysym.sym;
291 
292                   repeat = eina_rbtree_inline_insert(repeat, EINA_RBTREE_GET(entry),
293                                                      EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL);
294                }
295              break;
296           }
297           case SDL_KEYUP:
298           {
299              Ecore_Event_Key *ev;
300              Ecore_SDL_Pressed *entry;
301 
302              entry = (Ecore_SDL_Pressed*) eina_rbtree_inline_lookup(repeat, &event.key.keysym.sym, sizeof (event.key.keysym.sym),
303                                                                     EINA_RBTREE_CMP_KEY_CB(_ecore_sdl_pressed_node), NULL);
304              if (entry)
305                {
306                   repeat = eina_rbtree_inline_remove(repeat, EINA_RBTREE_GET(entry),
307                                                      EINA_RBTREE_CMP_NODE_CB(_ecore_sdl_pressed_key), NULL);
308                   free(entry);
309                }
310 
311              ev = _ecore_sdl_event_key(&event, timestamp);
312              if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
313              break;
314           }
315           case SDL_WINDOWEVENT:
316              switch (event.window.event)
317                {
318                 case SDL_WINDOWEVENT_RESIZED:
319                   {
320                      Ecore_Sdl_Event_Video_Resize *ev;
321 
322                      ev = calloc(1, sizeof (Ecore_Sdl_Event_Video_Resize));
323                      ev->windowID = event.window.windowID;
324                      ev->w = event.window.data1;
325                      ev->h = event.window.data2;
326 
327                      ecore_event_add(ECORE_SDL_EVENT_RESIZE, ev, NULL, NULL);
328                      break;
329                   }
330                 case SDL_WINDOWEVENT_EXPOSED:
331                   {
332                      Ecore_Sdl_Event_Window *ev;
333 
334                      ev = calloc(1, sizeof (Ecore_Sdl_Event_Window));
335                      ev->windowID = event.window.windowID;
336 
337                      ecore_event_add(ECORE_SDL_EVENT_EXPOSE, ev, NULL, NULL);
338                      break;
339                   }
340                 case SDL_WINDOWEVENT_ENTER:
341                 case SDL_WINDOWEVENT_LEAVE:
342                   {
343                      Ecore_Event_Mouse_IO *ev;
344 
345                      ev = calloc(1, sizeof (Ecore_Event_Mouse_IO));
346                      ev->window = event.window.windowID;
347                      ev->event_window = event.window.windowID;
348 
349                      ecore_event_add(event.window.event == SDL_WINDOWEVENT_ENTER ?
350                                      ECORE_EVENT_MOUSE_IN : ECORE_EVENT_MOUSE_OUT,
351                                      ev, NULL, NULL);
352                      break;
353                   }
354                 case SDL_WINDOWEVENT_FOCUS_GAINED:
355                 case SDL_WINDOWEVENT_FOCUS_LOST:
356                   {
357                      Ecore_Sdl_Event_Window *ev;
358 
359                      ev = calloc(1, sizeof (Ecore_Sdl_Event_Window));
360                      ev->windowID = event.window.windowID;
361 
362                      ecore_event_add(event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ?
363                                      ECORE_SDL_EVENT_GOT_FOCUS : ECORE_SDL_EVENT_LOST_FOCUS,
364                                      ev, NULL, NULL);
365                      break;
366                   }
367                }
368              break;
369           case SDL_SYSWMEVENT:
370           case SDL_USEREVENT:
371           case SDL_JOYAXISMOTION:
372           case SDL_JOYBALLMOTION:
373           case SDL_JOYHATMOTION:
374           case SDL_JOYBUTTONDOWN:
375           case SDL_JOYBUTTONUP:
376           default:
377              break;
378           }
379      }
380 }
381