1 /*
2    (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 
35 #include <directfb.h>
36 
37 #include <SDL.h>
38 
39 #include <core/coredefs.h>
40 #include <core/coretypes.h>
41 #include <core/input.h>
42 #include <core/system.h>
43 
44 #include <direct/mem.h>
45 #include <direct/thread.h>
46 
47 #include "sdl.h"
48 
49 #include <core/input_driver.h>
50 
51 
52 DFB_INPUT_DRIVER( sdlinput )
53 
54 /*
55  * declaration of private data
56  */
57 typedef struct {
58      CoreInputDevice *device;
59      DirectThread    *thread;
60      DFBSDL          *dfb_sdl;
61      int              stop;
62 } SDLInputData;
63 
64 
65 static DFBInputEvent motionX = {
66      .type    = DIET_UNKNOWN,
67      .axisabs = 0,
68 };
69 
70 static DFBInputEvent motionY = {
71      .type    = DIET_UNKNOWN,
72      .axisabs = 0,
73 };
74 
75 static void
motion_compress(int x,int y)76 motion_compress( int x, int y )
77 {
78      if (motionX.axisabs != x) {
79           motionX.type    = DIET_AXISMOTION;
80           motionX.flags   = DIEF_AXISABS;
81           motionX.axis    = DIAI_X;
82           motionX.axisabs = x;
83      }
84 
85      if (motionY.axisabs != y) {
86           motionY.type    = DIET_AXISMOTION;
87           motionY.flags   = DIEF_AXISABS;
88           motionY.axis    = DIAI_Y;
89           motionY.axisabs = y;
90      }
91 }
92 
93 static void
motion_realize(SDLInputData * data)94 motion_realize( SDLInputData *data )
95 {
96      if (motionX.type != DIET_UNKNOWN) {
97           if (motionY.type != DIET_UNKNOWN) {
98                /* let DirectFB know two events are coming */
99                motionX.flags  |= DIEF_FOLLOW;
100           }
101 
102           dfb_input_dispatch( data->device, &motionX );
103 
104           motionX.type = DIET_UNKNOWN;
105      }
106 
107      if (motionY.type != DIET_UNKNOWN) {
108           dfb_input_dispatch( data->device, &motionY );
109 
110           motionY.type = DIET_UNKNOWN;
111      }
112 }
113 
114 static bool
translate_key(SDLKey key,DFBInputEvent * evt)115 translate_key( SDLKey key, DFBInputEvent *evt )
116 {
117      evt->flags = DIEF_KEYID;
118      /* Numeric keypad */
119      if (key >= SDLK_KP0  &&  key <= SDLK_KP9) {
120           evt->key_id = DIKI_KP_0 + key - SDLK_KP0;
121           return true;
122      }
123 
124      /* Function keys */
125      if (key >= SDLK_F1  &&  key <= SDLK_F12) {
126           evt->key_id = DIKI_F1 + key - SDLK_F1;
127           return true;
128      }
129 
130      /* letter keys */
131      if (key >= SDLK_a  &&  key <= SDLK_z) {
132           evt->key_id = DIKI_A + key - SDLK_a;
133           return true;
134      }
135 
136      if (key >= SDLK_0  &&  key <= SDLK_9) {
137           evt->key_id = DIKI_0 + key - SDLK_0;
138           return true;
139      }
140 
141      switch (key) {
142           case SDLK_QUOTE:
143                evt->key_id = DIKI_QUOTE_RIGHT;
144                return true;
145           case SDLK_BACKQUOTE:
146                evt->key_id = DIKI_QUOTE_LEFT;
147                return true;
148           case SDLK_COMMA:
149                evt->key_id = DIKI_COMMA;
150                return true;
151           case SDLK_MINUS:
152                evt->key_id = DIKI_MINUS_SIGN;
153                return true;
154           case SDLK_PERIOD:
155                evt->key_id = DIKI_PERIOD;
156                return true;
157           case SDLK_SLASH:
158                evt->key_id = DIKI_SLASH;
159                return true;
160           case SDLK_SEMICOLON:
161                evt->key_id = DIKI_SEMICOLON;
162                return true;
163           case SDLK_LESS:
164                evt->key_id = DIKI_LESS_SIGN;
165                return true;
166           case SDLK_EQUALS:
167                evt->key_id = DIKI_EQUALS_SIGN;
168                return true;
169           case SDLK_LEFTBRACKET:
170                evt->key_id = DIKI_BRACKET_LEFT;
171                return true;
172           case SDLK_RIGHTBRACKET:
173                evt->key_id = DIKI_BRACKET_RIGHT;
174                return true;
175           case SDLK_BACKSLASH:
176                evt->key_id = DIKI_BACKSLASH;
177                return true;
178           /* Numeric keypad */
179           case SDLK_KP_PERIOD:
180                evt->key_id = DIKI_KP_DECIMAL;
181                return true;
182 
183           case SDLK_KP_DIVIDE:
184                evt->key_id = DIKI_KP_DIV;
185                return true;
186 
187           case SDLK_KP_MULTIPLY:
188                evt->key_id = DIKI_KP_MULT;
189                return true;
190 
191           case SDLK_KP_MINUS:
192                evt->key_id = DIKI_KP_MINUS;
193                return true;
194           case SDLK_KP_PLUS:
195                evt->key_id = DIKI_KP_PLUS;
196                return true;
197           case SDLK_KP_ENTER:
198                evt->key_id = DIKI_KP_ENTER;
199                return true;
200 
201           case SDLK_KP_EQUALS:
202                evt->key_id = DIKI_KP_EQUAL;
203                return true;
204           case SDLK_ESCAPE:
205                evt->key_id = DIKI_ESCAPE;
206                return true;
207           case SDLK_TAB:
208                evt->key_id = DIKI_TAB;
209                return true;
210           case SDLK_RETURN:
211                evt->key_id = DIKI_ENTER;
212                return true;
213           case SDLK_SPACE:
214                evt->key_id = DIKI_SPACE;
215                return true;
216           case SDLK_BACKSPACE:
217                evt->key_id = DIKI_BACKSPACE;
218                return true;
219           case SDLK_INSERT:
220                evt->key_id = DIKI_INSERT;
221                return true;
222           case SDLK_DELETE:
223                evt->key_id = DIKI_DELETE;
224                return true;
225           case SDLK_PRINT:
226                evt->key_id = DIKI_PRINT;
227                return true;
228           case SDLK_PAUSE:
229                evt->key_id = DIKI_PAUSE;
230                return true;
231           /* Arrows + Home/End pad */
232           case SDLK_UP:
233                evt->key_id = DIKI_UP;
234                return true;
235 
236           case SDLK_DOWN:
237                evt->key_id = DIKI_DOWN;
238                return true;
239 
240           case SDLK_RIGHT:
241                evt->key_id = DIKI_RIGHT;
242                return true;
243           case SDLK_LEFT:
244                evt->key_id = DIKI_LEFT;
245                return true;
246           case SDLK_HOME:
247                evt->key_id = DIKI_HOME;
248                return true;
249           case SDLK_END:
250                evt->key_id = DIKI_END;
251                return true;
252 
253           case SDLK_PAGEUP:
254                evt->key_id = DIKI_PAGE_UP;
255                return true;
256 
257           case SDLK_PAGEDOWN:
258                evt->key_id = DIKI_PAGE_DOWN;
259                return true;
260 
261 
262           /* Key state modifier keys */
263           case SDLK_NUMLOCK:
264                evt->key_id = DIKI_NUM_LOCK;
265                return true;
266 
267           case SDLK_CAPSLOCK:
268                evt->key_id = DIKI_CAPS_LOCK;
269                return true;
270           case SDLK_SCROLLOCK:
271                evt->key_id = DIKI_SCROLL_LOCK;
272                return true;
273           case SDLK_RSHIFT:
274                evt->key_id = DIKI_SHIFT_R;
275                return true;
276 
277           case SDLK_LSHIFT:
278                evt->key_id = DIKI_SHIFT_L;
279                return true;
280           case SDLK_RCTRL:
281                evt->key_id = DIKI_CONTROL_R;
282                return true;
283 
284           case SDLK_LCTRL:
285                evt->key_id = DIKI_CONTROL_L;
286                return true;
287 
288           case SDLK_RALT:
289                evt->key_id = DIKI_ALT_R;
290                return true;
291 
292           case SDLK_LALT:
293                evt->key_id = DIKI_ALT_L;
294                return true;
295 
296           case SDLK_RMETA:
297                evt->key_id = DIKI_META_R;
298                return true;
299 
300           case SDLK_LMETA:
301                evt->key_id = DIKI_META_L;
302                return true;
303 
304           case SDLK_LSUPER:
305                evt->key_id = DIKI_SUPER_L;
306                return true;
307 
308           case SDLK_RSUPER:
309                evt->key_id = DIKI_SUPER_R;
310                return true;
311 
312           case SDLK_MODE:
313                evt->key_id     = DIKI_ALT_R;
314                evt->flags     |= DIEF_KEYSYMBOL;
315                evt->key_symbol = DIKS_ALTGR;
316                return true;
317           default:
318                break;
319      }
320 
321      evt->flags = DIEF_NONE;
322      return false;
323 }
324 
325 /*
326  * Input thread reading from device.
327  * Generates events on incoming data.
328  */
329 static void*
sdlEventThread(DirectThread * thread,void * driver_data)330 sdlEventThread( DirectThread *thread, void *driver_data )
331 {
332      SDLInputData *data    = (SDLInputData*) driver_data;
333      DFBSDL       *dfb_sdl = data->dfb_sdl;
334 
335      while (!data->stop) {
336           DFBInputEvent evt;
337           SDL_Event     event;
338 
339           fusion_skirmish_prevail( &dfb_sdl->lock );
340 
341           /* Check for events */
342           while ( SDL_PollEvent(&event) ) {
343                fusion_skirmish_dismiss( &dfb_sdl->lock );
344 
345                switch (event.type) {
346                     case SDL_MOUSEMOTION:
347                          motion_compress( event.motion.x, event.motion.y );
348                          break;
349 
350                     case SDL_MOUSEBUTTONUP:
351                     case SDL_MOUSEBUTTONDOWN:
352                          motion_realize( data );
353 
354                          if (event.type == SDL_MOUSEBUTTONDOWN)
355                               evt.type = DIET_BUTTONPRESS;
356                          else
357                               evt.type = DIET_BUTTONRELEASE;
358 
359                          evt.flags = DIEF_NONE;
360 
361                          switch (event.button.button) {
362                               case SDL_BUTTON_LEFT:
363                                    evt.button = DIBI_LEFT;
364                                    break;
365                               case SDL_BUTTON_MIDDLE:
366                                    evt.button = DIBI_MIDDLE;
367                                    break;
368                               case SDL_BUTTON_RIGHT:
369                                    evt.button = DIBI_RIGHT;
370                                    break;
371                               case SDL_BUTTON_WHEELUP:
372                               case SDL_BUTTON_WHEELDOWN:
373                                    if (event.type != SDL_MOUSEBUTTONDOWN) {
374                                         fusion_skirmish_prevail( &dfb_sdl->lock );
375                                         continue;
376                                    }
377                                    evt.type  = DIET_AXISMOTION;
378                                    evt.flags = DIEF_AXISREL;
379                                    evt.axis  = DIAI_Z;
380                                    if (event.button.button == SDL_BUTTON_WHEELUP)
381                                         evt.axisrel = -1;
382                                    else
383                                         evt.axisrel = 1;
384                                    break;
385                               default:
386                                    fusion_skirmish_prevail( &dfb_sdl->lock );
387                                    continue;
388                          }
389 
390                          dfb_input_dispatch( data->device, &evt );
391                          break;
392 
393                     case SDL_KEYUP:
394                     case SDL_KEYDOWN:
395                          if (event.type == SDL_KEYDOWN)
396                               evt.type = DIET_KEYPRESS;
397                          else
398                               evt.type = DIET_KEYRELEASE;
399 
400                          /* Get a key id first */
401                          translate_key( event.key.keysym.sym, &evt );
402 
403                          /* If SDL provided a symbol, use it */
404                          if (event.key.keysym.unicode) {
405                               evt.flags     |= DIEF_KEYSYMBOL;
406                               evt.key_symbol = event.key.keysym.unicode;
407 
408                               /**
409                                * Hack to translate the Control+[letter]
410                                * combination to
411                                * Modifier: CONTROL, Key Symbol: [letter]
412                                * A side effect here is that Control+Backspace
413                                * produces Control+h
414                                */
415                               if (evt.modifiers == DIMM_CONTROL &&
416                                   evt.key_symbol >= 1 && evt.key_symbol <= ('z'-'a'+1))
417                               {
418                                   evt.key_symbol += 'a'-1;
419                               }
420                          }
421 
422                          dfb_input_dispatch( data->device, &evt );
423                          break;
424                     case SDL_QUIT:
425                          evt.type       = DIET_KEYPRESS;
426                          evt.flags      = DIEF_KEYSYMBOL;
427                          evt.key_symbol = DIKS_ESCAPE;
428 
429                          dfb_input_dispatch( data->device, &evt );
430 
431                          evt.type       = DIET_KEYRELEASE;
432                          evt.flags      = DIEF_KEYSYMBOL;
433                          evt.key_symbol = DIKS_ESCAPE;
434 
435                          dfb_input_dispatch( data->device, &evt );
436                          break;
437 
438                     default:
439                          break;
440                }
441 
442                fusion_skirmish_prevail( &dfb_sdl->lock );
443           }
444 
445           fusion_skirmish_dismiss( &dfb_sdl->lock );
446 
447           motion_realize( data );
448 
449           usleep(10000);
450 
451           direct_thread_testcancel( thread );
452      }
453 
454      return NULL;
455 }
456 
457 /* exported symbols */
458 
459 /*
460  * Return the number of available devices.
461  * Called once during initialization of DirectFB.
462  */
463 static int
driver_get_available(void)464 driver_get_available( void )
465 {
466      if (dfb_system_type() == CORE_SDL)
467           return 1;
468 
469      return 0;
470 }
471 
472 /*
473  * Fill out general information about this driver.
474  * Called once during initialization of DirectFB.
475  */
476 static void
driver_get_info(InputDriverInfo * info)477 driver_get_info( InputDriverInfo *info )
478 {
479      /* fill driver info structure */
480      snprintf ( info->name,
481                 DFB_INPUT_DRIVER_INFO_NAME_LENGTH, "SDL Input Driver" );
482      snprintf ( info->vendor,
483                 DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH, "Denis Oliver Kropp" );
484 
485      info->version.major = 0;
486      info->version.minor = 1;
487 }
488 
489 /*
490  * Open the device, fill out information about it,
491  * allocate and fill private data, start input thread.
492  * Called during initialization, resuming or taking over mastership.
493  */
494 static DFBResult
driver_open_device(CoreInputDevice * device,unsigned int number,InputDeviceInfo * info,void ** driver_data)495 driver_open_device( CoreInputDevice  *device,
496                     unsigned int      number,
497                     InputDeviceInfo  *info,
498                     void            **driver_data )
499 {
500      SDLInputData *data;
501      DFBSDL       *dfb_sdl = dfb_system_data();
502 
503      fusion_skirmish_prevail( &dfb_sdl->lock );
504 
505      SDL_EnableUNICODE( true );
506 
507      SDL_EnableKeyRepeat( 250, 40 );
508 
509      fusion_skirmish_dismiss( &dfb_sdl->lock );
510 
511      /* set device name */
512      snprintf( info->desc.name,
513                DFB_INPUT_DEVICE_DESC_NAME_LENGTH, "SDL Input" );
514 
515      /* set device vendor */
516      snprintf( info->desc.vendor,
517                DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "SDL" );
518 
519      /* set one of the primary input device IDs */
520      info->prefered_id = DIDID_KEYBOARD;
521 
522      /* set type flags */
523      info->desc.type   = DIDTF_JOYSTICK | DIDTF_KEYBOARD | DIDTF_MOUSE;
524 
525      /* set capabilities */
526      info->desc.caps   = DICAPS_ALL;
527 
528 
529      /* allocate and fill private data */
530      data = D_CALLOC( 1, sizeof(SDLInputData) );
531 
532      data->device  = device;
533      data->dfb_sdl = dfb_sdl;
534 
535      /* start input thread */
536      data->thread = direct_thread_create( DTT_INPUT, sdlEventThread, data, "SDL Input" );
537 
538      /* set private data pointer */
539      *driver_data = data;
540 
541      return DFB_OK;
542 }
543 
544 /*
545  * Fetch one entry from the device's keymap if supported.
546  */
547 static DFBResult
driver_get_keymap_entry(CoreInputDevice * device,void * driver_data,DFBInputDeviceKeymapEntry * entry)548 driver_get_keymap_entry( CoreInputDevice           *device,
549                          void                      *driver_data,
550                          DFBInputDeviceKeymapEntry *entry )
551 {
552      return DFB_UNSUPPORTED;
553 }
554 /*
555  * End thread, close device and free private data.
556  */
557 static void
driver_close_device(void * driver_data)558 driver_close_device( void *driver_data )
559 {
560      SDLInputData *data = (SDLInputData*) driver_data;
561 
562      /* stop input thread */
563      data->stop = 1;
564 
565      direct_thread_join( data->thread );
566      direct_thread_destroy( data->thread );
567 
568      /* free private data */
569      D_FREE ( data );
570 }
571 
572