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