1 /*
2    (c) Copyright 2001-2010  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 <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 
40 #include <directfb.h>
41 #include <directfb_keynames.h>
42 
43 #include <direct/debug.h>
44 #include <direct/list.h>
45 #include <direct/memcpy.h>
46 #include <direct/messages.h>
47 
48 
49 #include <fusion/shmalloc.h>
50 #include <fusion/reactor.h>
51 #include <fusion/arena.h>
52 
53 #include <core/CoreInputDevice.h>
54 
55 #include <core/core.h>
56 #include <core/coredefs.h>
57 #include <core/coretypes.h>
58 
59 #include <core/core_parts.h>
60 
61 #include <core/gfxcard.h>
62 #include <core/surface.h>
63 #include <core/surface_buffer.h>
64 #include <core/system.h>
65 #include <core/layer_context.h>
66 #include <core/layer_control.h>
67 #include <core/layer_region.h>
68 #include <core/layers.h>
69 #include <core/input.h>
70 #include <core/windows.h>
71 #include <core/windows_internal.h>
72 
73 #include <direct/mem.h>
74 #include <direct/memcpy.h>
75 #include <direct/messages.h>
76 #include <direct/modules.h>
77 #include <direct/trace.h>
78 
79 #include <fusion/build.h>
80 
81 #include <misc/conf.h>
82 #include <misc/util.h>
83 
84 #include <gfx/convert.h>
85 
86 
87 #define CHECK_INTERVAL 20000  // Microseconds
88 #define CHECK_NUMBER   200
89 
90 
91 D_DEBUG_DOMAIN( Core_Input,    "Core/Input",     "DirectFB Input Core" );
92 D_DEBUG_DOMAIN( Core_InputEvt, "Core/Input/Evt", "DirectFB Input Core Events & Dispatch" );
93 
94 
95 DEFINE_MODULE_DIRECTORY( dfb_input_modules, "inputdrivers", DFB_INPUT_DRIVER_ABI_VERSION );
96 
97 /**********************************************************************************************************************/
98 
99 typedef enum {
100      CIDC_RELOAD_KEYMAP
101 } CoreInputDeviceCommand;
102 
103 typedef struct {
104      DirectLink               link;
105 
106      int                      magic;
107 
108      DirectModuleEntry       *module;
109 
110      const InputDriverFuncs  *funcs;
111 
112      InputDriverInfo          info;
113 
114      int                      nr_devices;
115 } InputDriver;
116 
117 typedef struct {
118      int                          min_keycode;
119      int                          max_keycode;
120      int                          num_entries;
121      DFBInputDeviceKeymapEntry   *entries;
122 } InputDeviceKeymap;
123 
124 typedef struct {
125      int                          magic;
126 
127      DFBInputDeviceID             id;            /* unique device id */
128 
129      int                          num;
130 
131      InputDeviceInfo              device_info;
132 
133      InputDeviceKeymap            keymap;
134 
135      CoreInputDeviceState         state;
136 
137      DFBInputDeviceKeyIdentifier  last_key;      /* last key pressed */
138      DFBInputDeviceKeySymbol      last_symbol;   /* last symbol pressed */
139      bool                         first_press;   /* first press of key */
140 
141      FusionReactor               *reactor;       /* event dispatcher */
142      FusionSkirmish               lock;
143 
144      unsigned int                 axis_num;
145      DFBInputDeviceAxisInfo      *axis_info;
146      FusionRef                    ref; /* Ref between shared device & local device */
147 
148      FusionCall                   call;
149 } InputDeviceShared;
150 
151 struct __DFB_CoreInputDevice {
152      DirectLink          link;
153 
154      int                 magic;
155 
156      InputDeviceShared  *shared;
157 
158      InputDriver        *driver;
159      void               *driver_data;
160 
161      CoreDFB            *core;
162 };
163 
164 /**********************************************************************************************************************/
165 
166 DirectResult
CoreInputDevice_Call(CoreInputDevice * device,FusionCallExecFlags flags,int call_arg,void * ptr,unsigned int length,void * ret_ptr,unsigned int ret_size,unsigned int * ret_length)167 CoreInputDevice_Call( CoreInputDevice     *device,
168                       FusionCallExecFlags  flags,
169                       int                  call_arg,
170                       void                *ptr,
171                       unsigned int         length,
172                       void                *ret_ptr,
173                       unsigned int         ret_size,
174                       unsigned int        *ret_length )
175 {
176      D_ASSERT( device != NULL );
177      D_ASSERT( device->shared != NULL );
178 
179      return fusion_call_execute3( &device->shared->call, flags, call_arg, ptr, length, ret_ptr, ret_size, ret_length );
180 }
181 
182 /**********************************************************************************************************************/
183 
184 typedef struct {
185      int                 magic;
186 
187      int                 num;
188      InputDeviceShared  *devices[MAX_INPUTDEVICES];
189      FusionReactor      *reactor; /* For input hot-plug event */
190 } DFBInputCoreShared;
191 
192 struct __DFB_DFBInputCore {
193      int                 magic;
194 
195      CoreDFB            *core;
196 
197      DFBInputCoreShared *shared;
198 
199      DirectLink         *drivers;
200      DirectLink         *devices;
201 };
202 
203 
204 DFB_CORE_PART( input_core, InputCore );
205 
206 /**********************************************************************************************************************/
207 
208 typedef struct {
209      DFBInputDeviceKeySymbol      target;
210      DFBInputDeviceKeySymbol      result;
211 } DeadKeyCombo;
212 
213 typedef struct {
214      DFBInputDeviceKeySymbol      deadkey;
215      const DeadKeyCombo          *combos;
216 } DeadKeyMap;
217 
218 /* Data struct of input device hotplug event */
219 typedef struct {
220      bool             is_plugin;   /* Hotplug in or not */
221      int              dev_id;      /* Input device ID*/
222      struct timeval   stamp;       /* Time stamp of event */
223 } InputDeviceHotplugEvent;
224 
225 /**********************************************************************************************************************/
226 
227 static const DeadKeyCombo combos_grave[] = {
228      { DIKS_SPACE,     (unsigned char) '`' },
229      { DIKS_SMALL_A,   (unsigned char) 0xe0 }, // '�'
230      { DIKS_SMALL_E,   (unsigned char) 0xe8 }, // '�'
231      { DIKS_SMALL_I,   (unsigned char) 0xec }, // '�'
232      { DIKS_SMALL_O,   (unsigned char) 0xf2 }, // '�'
233      { DIKS_SMALL_U,   (unsigned char) 0xf9 }, // '�'
234      { DIKS_CAPITAL_A, (unsigned char) 0xc0 }, // '�'
235      { DIKS_CAPITAL_E, (unsigned char) 0xc8 }, // '�'
236      { DIKS_CAPITAL_I, (unsigned char) 0xcc }, // '�'
237      { DIKS_CAPITAL_O, (unsigned char) 0xd2 }, // '�'
238      { DIKS_CAPITAL_U, (unsigned char) 0xd9 }, // '�'
239      { 0, 0 }
240 };
241 
242 static const DeadKeyCombo combos_acute[] = {
243      { DIKS_SPACE,     (unsigned char) '\'' },
244      { DIKS_SMALL_A,   (unsigned char) '�' },
245      { DIKS_SMALL_E,   (unsigned char) '�' },
246      { DIKS_SMALL_I,   (unsigned char) '�' },
247      { DIKS_SMALL_O,   (unsigned char) '�' },
248      { DIKS_SMALL_U,   (unsigned char) '�' },
249      { DIKS_SMALL_Y,   (unsigned char) '�' },
250      { DIKS_CAPITAL_A, (unsigned char) '�' },
251      { DIKS_CAPITAL_E, (unsigned char) '�' },
252      { DIKS_CAPITAL_I, (unsigned char) '�' },
253      { DIKS_CAPITAL_O, (unsigned char) '�' },
254      { DIKS_CAPITAL_U, (unsigned char) '�' },
255      { DIKS_CAPITAL_Y, (unsigned char) '�' },
256      { 0, 0 }
257 };
258 
259 static const DeadKeyCombo combos_circumflex[] = {
260      { DIKS_SPACE,     (unsigned char) '^' },
261      { DIKS_SMALL_A,   (unsigned char) '�' },
262      { DIKS_SMALL_E,   (unsigned char) '�' },
263      { DIKS_SMALL_I,   (unsigned char) '�' },
264      { DIKS_SMALL_O,   (unsigned char) '�' },
265      { DIKS_SMALL_U,   (unsigned char) '�' },
266      { DIKS_CAPITAL_A, (unsigned char) '�' },
267      { DIKS_CAPITAL_E, (unsigned char) '�' },
268      { DIKS_CAPITAL_I, (unsigned char) '�' },
269      { DIKS_CAPITAL_O, (unsigned char) '�' },
270      { DIKS_CAPITAL_U, (unsigned char) '�' },
271      { 0, 0 }
272 };
273 
274 static const DeadKeyCombo combos_diaeresis[] = {
275      { DIKS_SPACE,     (unsigned char) '�' },
276      { DIKS_SMALL_A,   (unsigned char) '�' },
277      { DIKS_SMALL_E,   (unsigned char) '�' },
278      { DIKS_SMALL_I,   (unsigned char) '�' },
279      { DIKS_SMALL_O,   (unsigned char) '�' },
280      { DIKS_SMALL_U,   (unsigned char) '�' },
281      { DIKS_CAPITAL_A, (unsigned char) '�' },
282      { DIKS_CAPITAL_E, (unsigned char) '�' },
283      { DIKS_CAPITAL_I, (unsigned char) '�' },
284      { DIKS_CAPITAL_O, (unsigned char) '�' },
285      { DIKS_CAPITAL_U, (unsigned char) '�' },
286      { 0, 0 }
287 };
288 
289 static const DeadKeyCombo combos_tilde[] = {
290      { DIKS_SPACE,     (unsigned char) '~' },
291      { DIKS_SMALL_A,   (unsigned char) '�' },
292      { DIKS_SMALL_N,   (unsigned char) '�' },
293      { DIKS_SMALL_O,   (unsigned char) '�' },
294      { DIKS_CAPITAL_A, (unsigned char) '�' },
295      { DIKS_CAPITAL_N, (unsigned char) '�' },
296      { DIKS_CAPITAL_O, (unsigned char) '�' },
297      { 0, 0 }
298 };
299 
300 static const DeadKeyMap deadkey_maps[] = {
301      { DIKS_DEAD_GRAVE,      combos_grave },
302      { DIKS_DEAD_ACUTE,      combos_acute },
303      { DIKS_DEAD_CIRCUMFLEX, combos_circumflex },
304      { DIKS_DEAD_DIAERESIS,  combos_diaeresis },
305      { DIKS_DEAD_TILDE,      combos_tilde }
306 };
307 
308 /* define a lookup table to go from key IDs to names.
309  * This is used to look up the names provided in a loaded key table */
310 /* this table is roughly 4Kb in size */
311 DirectFBKeySymbolNames(KeySymbolNames);
312 DirectFBKeyIdentifierNames(KeyIdentifierNames);
313 
314 /**********************************************************************************************************************/
315 
316 static void init_devices( CoreDFB *core );
317 
318 static void allocate_device_keymap( CoreDFB *core, CoreInputDevice *device );
319 
320 static DFBInputDeviceKeymapEntry *get_keymap_entry( CoreInputDevice *device,
321                                                     int              code );
322 
323 static DFBResult set_keymap_entry( CoreInputDevice                 *device,
324                                    int                              code,
325                                    const DFBInputDeviceKeymapEntry *entry );
326 
327 static DFBResult load_keymap( CoreInputDevice           *device,
328                               char                      *filename );
329 
330 static DFBResult reload_keymap( CoreInputDevice *device );
331 
332 static DFBInputDeviceKeySymbol     lookup_keysymbol( char *symbolname );
333 static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername );
334 
335 /**********************************************************************************************************************/
336 
337 static bool lookup_from_table( CoreInputDevice    *device,
338                                DFBInputEvent      *event,
339                                DFBInputEventFlags  lookup );
340 
341 static void fixup_key_event  ( CoreInputDevice    *device,
342                                DFBInputEvent      *event );
343 
344 static void fixup_mouse_event( CoreInputDevice    *device,
345                                DFBInputEvent      *event );
346 
347 static void flush_keys       ( CoreInputDevice    *device );
348 
349 static bool core_input_filter( CoreInputDevice    *device,
350                                DFBInputEvent      *event );
351 
352 /**********************************************************************************************************************/
353 
354 static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol     symbol );
355 
356 static DFBInputDeviceKeySymbol     id_to_symbol( DFBInputDeviceKeyIdentifier id,
357                                                  DFBInputDeviceModifierMask  modifiers,
358                                                  DFBInputDeviceLockState     locks );
359 
360 /**********************************************************************************************************************/
361 
362 static ReactionResult local_processing_hotplug( const void *msg_data, void *ctx );
363 
364 /**********************************************************************************************************************/
365 
366 static ReactionFunc dfb_input_globals[MAX_INPUT_GLOBALS+1] = {
367 /* 0 */   _dfb_windowstack_inputdevice_listener,
368           NULL
369 };
370 
371 DFBResult
dfb_input_add_global(ReactionFunc func,int * ret_index)372 dfb_input_add_global( ReactionFunc  func,
373                       int          *ret_index )
374 {
375      int i;
376 
377      D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, func, ret_index );
378 
379      D_ASSERT( func != NULL );
380      D_ASSERT( ret_index != NULL );
381 
382      for (i=0; i<MAX_INPUT_GLOBALS; i++) {
383           if (!dfb_input_globals[i]) {
384                dfb_input_globals[i] = func;
385 
386                D_DEBUG_AT( Core_Input, "  -> index %d\n", i );
387 
388                *ret_index = i;
389 
390                return DFB_OK;
391           }
392      }
393 
394      return DFB_LIMITEXCEEDED;
395 }
396 
397 DFBResult
dfb_input_set_global(ReactionFunc func,int index)398 dfb_input_set_global( ReactionFunc func,
399                       int          index )
400 {
401      D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, func, index );
402 
403      D_ASSERT( func != NULL );
404      D_ASSERT( index >= 0 );
405      D_ASSERT( index < MAX_INPUT_GLOBALS );
406 
407      D_ASSUME( dfb_input_globals[index] == NULL );
408 
409      dfb_input_globals[index] = func;
410 
411      return DFB_OK;
412 }
413 
414 /**********************************************************************************************************************/
415 
416 static DFBInputCore       *core_local; /* FIXME */
417 static DFBInputCoreShared *core_input; /* FIXME */
418 
419 #if FUSION_BUILD_MULTI
420 static Reaction            local_processing_react; /* Local reaction to hot-plug event */
421 #endif
422 
423 
424 static DFBResult
dfb_input_core_initialize(CoreDFB * core,DFBInputCore * data,DFBInputCoreShared * shared)425 dfb_input_core_initialize( CoreDFB            *core,
426                            DFBInputCore       *data,
427                            DFBInputCoreShared *shared )
428 {
429 #if FUSION_BUILD_MULTI
430      DFBResult result = DFB_OK;
431 #endif
432 
433      D_DEBUG_AT( Core_Input, "dfb_input_core_initialize( %p, %p, %p )\n", core, data, shared );
434 
435      D_ASSERT( data != NULL );
436      D_ASSERT( shared != NULL );
437 
438      core_local = data;   /* FIXME */
439      core_input = shared; /* FIXME */
440 
441      data->core   = core;
442      data->shared = shared;
443 
444 
445      direct_modules_explore_directory( &dfb_input_modules );
446 
447 #if FUSION_BUILD_MULTI
448      /* Create the reactor that responds input device hot-plug events. */
449      core_input->reactor = fusion_reactor_new(
450                               sizeof( InputDeviceHotplugEvent ),
451                               "Input Hotplug",
452                               dfb_core_world(core) );
453      if (!core_input->reactor) {
454           D_ERROR( "DirectFB/Input: fusion_reactor_new() failed!\n" );
455           result = DFB_FAILURE;
456           goto errorExit;
457      }
458 
459      fusion_reactor_add_permissions( core_input->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH );
460 
461      /* Attach local process function to the input hot-plug reactor. */
462      result = fusion_reactor_attach(
463                               core_input->reactor,
464                               local_processing_hotplug,
465                               (void*) core,
466                               &local_processing_react );
467      if (result) {
468           D_ERROR( "DirectFB/Input: fusion_reactor_attach() failed!\n" );
469           goto errorExit;
470      }
471 #endif
472 
473      init_devices( core );
474 
475 
476      D_MAGIC_SET( data, DFBInputCore );
477      D_MAGIC_SET( shared, DFBInputCoreShared );
478 
479      return DFB_OK;
480 
481 #if FUSION_BUILD_MULTI
482 errorExit:
483      /* Destroy the hot-plug reactor if it was created. */
484      if (core_input->reactor)
485           fusion_reactor_destroy(core_input->reactor);
486 
487      return result;
488 #endif
489 }
490 
491 static DFBResult
dfb_input_core_join(CoreDFB * core,DFBInputCore * data,DFBInputCoreShared * shared)492 dfb_input_core_join( CoreDFB            *core,
493                      DFBInputCore       *data,
494                      DFBInputCoreShared *shared )
495 {
496      int i;
497 #if FUSION_BUILD_MULTI
498      DFBResult result;
499 #endif
500 
501      D_DEBUG_AT( Core_Input, "dfb_input_core_join( %p, %p, %p )\n", core, data, shared );
502 
503      D_ASSERT( data != NULL );
504      D_MAGIC_ASSERT( shared, DFBInputCoreShared );
505      D_ASSERT( shared->reactor != NULL );
506 
507      core_local = data;   /* FIXME */
508      core_input = shared; /* FIXME */
509 
510      data->core   = core;
511      data->shared = shared;
512 
513 #if FUSION_BUILD_MULTI
514      /* Attach the local process function to the input hot-plug reactor. */
515      result = fusion_reactor_attach( core_input->reactor,
516                                      local_processing_hotplug,
517                                      (void*) core,
518                                      &local_processing_react );
519      if (result) {
520           D_ERROR( "DirectFB/Input: fusion_reactor_attach failed!\n" );
521           return result;
522      }
523 #endif
524 
525      for (i=0; i<core_input->num; i++) {
526           CoreInputDevice *device;
527 
528           device = D_CALLOC( 1, sizeof(CoreInputDevice) );
529           if (!device) {
530                D_OOM();
531                continue;
532           }
533 
534           device->shared = core_input->devices[i];
535 
536 #if FUSION_BUILD_MULTI
537           /* Increase the reference counter. */
538           fusion_ref_up( &device->shared->ref, false );
539 #endif
540 
541           /* add it to the list */
542           direct_list_append( &data->devices, &device->link );
543 
544           D_MAGIC_SET( device, CoreInputDevice );
545      }
546 
547 
548      D_MAGIC_SET( data, DFBInputCore );
549 
550      return DFB_OK;
551 }
552 
553 static DFBResult
dfb_input_core_shutdown(DFBInputCore * data,bool emergency)554 dfb_input_core_shutdown( DFBInputCore *data,
555                          bool          emergency )
556 {
557      DFBInputCoreShared  *shared;
558      DirectLink          *n;
559      CoreInputDevice     *device;
560      FusionSHMPoolShared *pool = dfb_core_shmpool( data->core );
561      InputDriver         *driver;
562 
563      D_DEBUG_AT( Core_Input, "dfb_input_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " );
564 
565      D_MAGIC_ASSERT( data, DFBInputCore );
566      D_MAGIC_ASSERT( data->shared, DFBInputCoreShared );
567 
568      shared = data->shared;
569 
570      /* Stop each input provider's hot-plug thread that supports device hot-plugging. */
571      direct_list_foreach_safe (driver, n, core_local->drivers) {
572           if (driver->funcs->GetCapability && driver->funcs->StopHotplug) {
573                if (IDC_HOTPLUG & driver->funcs->GetCapability()) {
574                     D_DEBUG_AT( Core_Input, "Stopping hot-plug detection thread "
575                                 "within %s\n ", driver->module->name );
576                     if (driver->funcs->StopHotplug()) {
577                          D_ERROR( "DirectFB/Input: StopHotplug() failed with %s\n",
578                                   driver->module->name );
579                     }
580                }
581           }
582      }
583 
584 #if FUSION_BUILD_MULTI
585      fusion_reactor_detach( core_input->reactor, &local_processing_react );
586      fusion_reactor_destroy( core_input->reactor );
587 #endif
588 
589      direct_list_foreach_safe (device, n, data->devices) {
590           InputDeviceShared *devshared;
591 
592           D_MAGIC_ASSERT( device, CoreInputDevice );
593 
594           driver = device->driver;
595           D_ASSERT( driver != NULL );
596 
597           devshared = device->shared;
598           D_ASSERT( devshared != NULL );
599 
600           CoreInputDevice_Deinit_Dispatch( &devshared->call );
601 
602           fusion_skirmish_destroy( &devshared->lock );
603 
604           if (device->driver_data != NULL) {
605                void *driver_data;
606 
607                D_ASSERT( driver->funcs != NULL );
608                D_ASSERT( driver->funcs->CloseDevice != NULL );
609 
610                D_DEBUG_AT( Core_Input, "  -> closing '%s' (%d) %d.%d (%s)\n",
611                            devshared->device_info.desc.name, devshared->num + 1,
612                            driver->info.version.major,
613                            driver->info.version.minor, driver->info.vendor );
614 
615                driver_data = device->driver_data;
616                device->driver_data = NULL;
617                driver->funcs->CloseDevice( driver_data );
618           }
619 
620           if (!--driver->nr_devices) {
621                direct_module_unref( driver->module );
622                D_FREE( driver );
623           }
624 
625 #if FUSION_BUILD_MULTI
626           fusion_ref_destroy( &device->shared->ref );
627 #endif
628 
629           fusion_reactor_free( devshared->reactor );
630 
631           if (devshared->keymap.entries)
632                SHFREE( pool, devshared->keymap.entries );
633 
634           if (devshared->axis_info)
635                SHFREE( pool, devshared->axis_info );
636 
637           SHFREE( pool, devshared );
638 
639           D_MAGIC_CLEAR( device );
640 
641           D_FREE( device );
642      }
643 
644      D_MAGIC_CLEAR( data );
645      D_MAGIC_CLEAR( shared );
646 
647      return DFB_OK;
648 }
649 
650 static DFBResult
dfb_input_core_leave(DFBInputCore * data,bool emergency)651 dfb_input_core_leave( DFBInputCore *data,
652                       bool          emergency )
653 {
654      DFBInputCoreShared *shared;
655      DirectLink         *n;
656      CoreInputDevice    *device;
657 
658      D_DEBUG_AT( Core_Input, "dfb_input_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " );
659 
660      D_MAGIC_ASSERT( data, DFBInputCore );
661      D_MAGIC_ASSERT( data->shared, DFBInputCoreShared );
662 
663      shared = data->shared;
664 
665 #if FUSION_BUILD_MULTI
666      fusion_reactor_detach( core_input->reactor, &local_processing_react );
667 #endif
668 
669      direct_list_foreach_safe (device, n, data->devices) {
670           D_MAGIC_ASSERT( device, CoreInputDevice );
671 
672 #if FUSION_BUILD_MULTI
673           /* Decrease the ref between shared device and local device. */
674           fusion_ref_down( &device->shared->ref, false );
675 #endif
676 
677           D_FREE( device );
678      }
679 
680 
681      D_MAGIC_CLEAR( data );
682 
683      return DFB_OK;
684 }
685 
686 static DFBResult
dfb_input_core_suspend(DFBInputCore * data)687 dfb_input_core_suspend( DFBInputCore *data )
688 {
689      DFBInputCoreShared *shared;
690      CoreInputDevice    *device;
691      InputDriver        *driver;
692 
693      D_DEBUG_AT( Core_Input, "dfb_input_core_suspend( %p )\n", data );
694 
695      D_MAGIC_ASSERT( data, DFBInputCore );
696      D_MAGIC_ASSERT( data->shared, DFBInputCoreShared );
697 
698      shared = data->shared;
699 
700      D_DEBUG_AT( Core_Input, "  -> suspending...\n" );
701 
702      /* Go through the drivers list and attempt to suspend all of the drivers that
703       * support the Suspend function.
704       */
705      direct_list_foreach (driver, core_local->drivers) {
706           DFBResult ret;
707 
708           D_ASSERT( driver->funcs->Suspend != NULL );
709           ret = driver->funcs->Suspend();
710 
711           if (ret != DFB_OK && ret != DFB_UNSUPPORTED) {
712                D_DERROR( ret, "driver->Suspend failed during suspend (%s)\n",
713                          driver->info.name );
714           }
715      }
716 
717      direct_list_foreach (device, data->devices) {
718           InputDeviceShared *devshared;
719 
720           D_MAGIC_ASSERT( device, CoreInputDevice );
721 
722           driver = device->driver;
723           D_ASSERT( driver != NULL );
724 
725           devshared = device->shared;
726           D_ASSERT( devshared != NULL );
727 
728           if (device->driver_data != NULL) {
729                void *driver_data;
730 
731                D_ASSERT( driver->funcs != NULL );
732                D_ASSERT( driver->funcs->CloseDevice != NULL );
733 
734                D_DEBUG_AT( Core_Input, "  -> closing '%s' (%d) %d.%d (%s)\n",
735                            devshared->device_info.desc.name, devshared->num + 1,
736                            driver->info.version.major,
737                            driver->info.version.minor, driver->info.vendor );
738 
739                driver_data = device->driver_data;
740                device->driver_data = NULL;
741                driver->funcs->CloseDevice( driver_data );
742           }
743 
744           flush_keys( device );
745      }
746 
747      D_DEBUG_AT( Core_Input, "  -> suspended.\n" );
748 
749      return DFB_OK;
750 }
751 
752 static DFBResult
dfb_input_core_resume(DFBInputCore * data)753 dfb_input_core_resume( DFBInputCore *data )
754 {
755      DFBInputCoreShared *shared;
756      DFBResult           ret;
757      CoreInputDevice    *device;
758      InputDriver        *driver;
759 
760      D_DEBUG_AT( Core_Input, "dfb_input_core_resume( %p )\n", data );
761 
762      D_MAGIC_ASSERT( data, DFBInputCore );
763      D_MAGIC_ASSERT( data->shared, DFBInputCoreShared );
764 
765      shared = data->shared;
766 
767      D_DEBUG_AT( Core_Input, "  -> resuming...\n" );
768 
769      direct_list_foreach (device, data->devices) {
770           D_MAGIC_ASSERT( device, CoreInputDevice );
771 
772           D_DEBUG_AT( Core_Input, "  -> reopening '%s' (%d) %d.%d (%s)\n",
773                       device->shared->device_info.desc.name, device->shared->num + 1,
774                       device->driver->info.version.major,
775                       device->driver->info.version.minor,
776                       device->driver->info.vendor );
777 
778           D_ASSERT( device->driver_data == NULL );
779 
780           ret = device->driver->funcs->OpenDevice( device, device->shared->num,
781                                                    &device->shared->device_info,
782                                                    &device->driver_data );
783           if (ret) {
784                D_DERROR( ret, "DirectFB/Input: Failed reopening device "
785                          "during resume (%s)!\n", device->shared->device_info.desc.name );
786                device->driver_data = NULL;
787           }
788      }
789 
790      /* Go through the drivers list and attempt to resume all of the drivers that
791       * support the Resume function.
792       */
793      direct_list_foreach (driver, core_local->drivers) {
794           D_ASSERT( driver->funcs->Resume != NULL );
795 
796           ret = driver->funcs->Resume();
797           if (ret != DFB_OK && ret != DFB_UNSUPPORTED) {
798                D_DERROR( ret, "driver->Resume failed during resume (%s)\n",
799                          driver->info.name );
800           }
801      }
802 
803      D_DEBUG_AT( Core_Input, "  -> resumed.\n" );
804 
805      return DFB_OK;
806 }
807 
808 void
dfb_input_enumerate_devices(InputDeviceCallback callback,void * ctx,DFBInputDeviceCapabilities caps)809 dfb_input_enumerate_devices( InputDeviceCallback         callback,
810                              void                       *ctx,
811                              DFBInputDeviceCapabilities  caps )
812 {
813      CoreInputDevice *device;
814 
815      D_ASSERT( core_input != NULL );
816 
817      direct_list_foreach (device, core_local->devices) {
818           DFBInputDeviceCapabilities dev_caps;
819 
820           D_MAGIC_ASSERT( device, CoreInputDevice );
821           D_ASSERT( device->shared != NULL );
822 
823           dev_caps = device->shared->device_info.desc.caps;
824 
825           /* Always match if unclassified */
826           if (!dev_caps)
827                dev_caps = DICAPS_ALL;
828 
829           if ((dev_caps & caps) && callback( device, ctx ) == DFENUM_CANCEL)
830                break;
831      }
832 }
833 
834 DirectResult
dfb_input_attach(CoreInputDevice * device,ReactionFunc func,void * ctx,Reaction * reaction)835 dfb_input_attach( CoreInputDevice *device,
836                   ReactionFunc     func,
837                   void            *ctx,
838                   Reaction        *reaction )
839 {
840      D_DEBUG_AT( Core_Input, "%s( %p, %p, %p, %p )\n", __FUNCTION__, device, func, ctx, reaction );
841 
842      D_MAGIC_ASSERT( device, CoreInputDevice );
843 
844      D_ASSERT( core_input != NULL );
845      D_ASSERT( device != NULL );
846      D_ASSERT( device->shared != NULL );
847 
848      return fusion_reactor_attach( device->shared->reactor, func, ctx, reaction );
849 }
850 
851 DirectResult
dfb_input_detach(CoreInputDevice * device,Reaction * reaction)852 dfb_input_detach( CoreInputDevice *device,
853                   Reaction        *reaction )
854 {
855      D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction );
856 
857      D_MAGIC_ASSERT( device, CoreInputDevice );
858 
859      D_ASSERT( core_input != NULL );
860      D_ASSERT( device != NULL );
861      D_ASSERT( device->shared != NULL );
862 
863      return fusion_reactor_detach( device->shared->reactor, reaction );
864 }
865 
866 DirectResult
dfb_input_attach_global(CoreInputDevice * device,int index,void * ctx,GlobalReaction * reaction)867 dfb_input_attach_global( CoreInputDevice *device,
868                          int              index,
869                          void            *ctx,
870                          GlobalReaction  *reaction )
871 {
872      D_DEBUG_AT( Core_Input, "%s( %p, %d, %p, %p )\n", __FUNCTION__, device, index, ctx, reaction );
873 
874      D_MAGIC_ASSERT( device, CoreInputDevice );
875 
876      D_ASSERT( core_input != NULL );
877      D_ASSERT( device != NULL );
878      D_ASSERT( device->shared != NULL );
879 
880      return fusion_reactor_attach_global( device->shared->reactor, index, ctx, reaction );
881 }
882 
883 DirectResult
dfb_input_detach_global(CoreInputDevice * device,GlobalReaction * reaction)884 dfb_input_detach_global( CoreInputDevice *device,
885                          GlobalReaction  *reaction )
886 {
887      D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction );
888 
889      D_MAGIC_ASSERT( device, CoreInputDevice );
890 
891      D_ASSERT( core_input != NULL );
892      D_ASSERT( device != NULL );
893      D_ASSERT( device->shared != NULL );
894 
895      return fusion_reactor_detach_global( device->shared->reactor, reaction );
896 }
897 
898 const char *
dfb_input_event_type_name(DFBInputEventType type)899 dfb_input_event_type_name( DFBInputEventType type )
900 {
901      switch (type) {
902           case DIET_UNKNOWN:
903                return "UNKNOWN";
904 
905           case DIET_KEYPRESS:
906                return "KEYPRESS";
907 
908           case DIET_KEYRELEASE:
909                return "KEYRELEASE";
910 
911           case DIET_BUTTONPRESS:
912                return "BUTTONPRESS";
913 
914           case DIET_BUTTONRELEASE:
915                return "BUTTONRELEASE";
916 
917           case DIET_AXISMOTION:
918                return "AXISMOTION";
919 
920           default:
921                break;
922      }
923 
924      return "<invalid>";
925 }
926 
927 void
dfb_input_dispatch(CoreInputDevice * device,DFBInputEvent * event)928 dfb_input_dispatch( CoreInputDevice *device, DFBInputEvent *event )
929 {
930      D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, event );
931 
932      D_MAGIC_ASSERT( device, CoreInputDevice );
933 
934      D_ASSERT( core_input != NULL );
935      D_ASSERT( device != NULL );
936      D_ASSERT( event != NULL );
937 
938      /*
939       * When a USB device is hot-removed, it is possible that there are pending events
940       * still being dispatched and the shared field becomes NULL.
941       */
942 
943      /*
944       * 0. Sanity checks & debugging...
945       */
946      if (!device->shared) {
947           D_DEBUG_AT( Core_Input, "  -> No shared data!\n" );
948           return;
949      }
950 
951      D_ASSUME( device->shared->reactor != NULL );
952 
953      if (!device->shared->reactor) {
954           D_DEBUG_AT( Core_Input, "  -> No reactor!\n" );
955           return;
956      }
957 
958      D_DEBUG_AT( Core_InputEvt, "  -> (%02x) %s%s%s\n", event->type,
959                  dfb_input_event_type_name( event->type ),
960                  (event->flags & DIEF_FOLLOW) ? " [FOLLOW]" : "",
961                  (event->flags & DIEF_REPEAT) ? " [REPEAT]" : "" );
962 
963 #if D_DEBUG_ENABLED
964      if (event->flags & DIEF_TIMESTAMP)
965           D_DEBUG_AT( Core_InputEvt, "  -> TIMESTAMP  %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec );
966      if (event->flags & DIEF_AXISABS)
967           D_DEBUG_AT( Core_InputEvt, "  -> AXISABS    %d at %d\n",  event->axis, event->axisabs );
968      if (event->flags & DIEF_AXISREL)
969           D_DEBUG_AT( Core_InputEvt, "  -> AXISREL    %d by %d\n",  event->axis, event->axisrel );
970      if (event->flags & DIEF_KEYCODE)
971           D_DEBUG_AT( Core_InputEvt, "  -> KEYCODE    %d\n",        event->key_code );
972      if (event->flags & DIEF_KEYID)
973           D_DEBUG_AT( Core_InputEvt, "  -> KEYID      0x%04x\n",    event->key_id );
974      if (event->flags & DIEF_KEYSYMBOL)
975           D_DEBUG_AT( Core_InputEvt, "  -> KEYSYMBOL  0x%04x\n",    event->key_symbol );
976      if (event->flags & DIEF_MODIFIERS)
977           D_DEBUG_AT( Core_InputEvt, "  -> MODIFIERS  0x%04x\n",    event->modifiers );
978      if (event->flags & DIEF_LOCKS)
979           D_DEBUG_AT( Core_InputEvt, "  -> LOCKS      0x%04x\n",    event->locks );
980      if (event->flags & DIEF_BUTTONS)
981           D_DEBUG_AT( Core_InputEvt, "  -> BUTTONS    0x%04x\n",    event->buttons );
982      if (event->flags & DIEF_GLOBAL)
983           D_DEBUG_AT( Core_InputEvt, "  -> GLOBAL\n" );
984 #endif
985 
986      /*
987       * 1. Fixup event...
988       */
989      event->clazz     = DFEC_INPUT;
990      event->device_id = device->shared->id;
991 
992      if (!(event->flags & DIEF_TIMESTAMP)) {
993           gettimeofday( &event->timestamp, NULL );
994           event->flags |= DIEF_TIMESTAMP;
995      }
996 
997      switch (event->type) {
998           case DIET_BUTTONPRESS:
999           case DIET_BUTTONRELEASE:
1000                D_DEBUG_AT( Core_InputEvt, "  -> BUTTON     0x%04x\n", event->button );
1001 
1002                if (dfb_config->lefty) {
1003                     if (event->button == DIBI_LEFT)
1004                          event->button = DIBI_RIGHT;
1005                     else if (event->button == DIBI_RIGHT)
1006                          event->button = DIBI_LEFT;
1007 
1008                     D_DEBUG_AT( Core_InputEvt, "  -> lefty!  => 0x%04x <=\n", event->button );
1009                }
1010                /* fallthru */
1011 
1012           case DIET_AXISMOTION:
1013                fixup_mouse_event( device, event );
1014                break;
1015 
1016           case DIET_KEYPRESS:
1017           case DIET_KEYRELEASE:
1018                if (dfb_config->capslock_meta) {
1019                     if (device->shared->keymap.num_entries && (event->flags & DIEF_KEYCODE))
1020                          lookup_from_table( device, event, (DIEF_KEYID |
1021                                                             DIEF_KEYSYMBOL) & ~event->flags );
1022 
1023                     if (event->key_id == DIKI_CAPS_LOCK || event->key_symbol == DIKS_CAPS_LOCK) {
1024                          event->flags     |= DIEF_KEYID | DIEF_KEYSYMBOL;
1025                          event->key_code   = -1;
1026                          event->key_id     = DIKI_META_L;
1027                          event->key_symbol = DIKS_META;
1028                     }
1029                }
1030 
1031                fixup_key_event( device, event );
1032                break;
1033 
1034           default:
1035                ;
1036      }
1037 
1038 #if D_DEBUG_ENABLED
1039      if (event->flags & DIEF_TIMESTAMP)
1040           D_DEBUG_AT( Core_InputEvt, "  => TIMESTAMP  %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec );
1041      if (event->flags & DIEF_AXISABS)
1042           D_DEBUG_AT( Core_InputEvt, "  => AXISABS    %d at %d\n",  event->axis, event->axisabs );
1043      if (event->flags & DIEF_AXISREL)
1044           D_DEBUG_AT( Core_InputEvt, "  => AXISREL    %d by %d\n",  event->axis, event->axisrel );
1045      if (event->flags & DIEF_KEYCODE)
1046           D_DEBUG_AT( Core_InputEvt, "  => KEYCODE    %d\n",        event->key_code );
1047      if (event->flags & DIEF_KEYID)
1048           D_DEBUG_AT( Core_InputEvt, "  => KEYID      0x%04x\n",    event->key_id );
1049      if (event->flags & DIEF_KEYSYMBOL)
1050           D_DEBUG_AT( Core_InputEvt, "  => KEYSYMBOL  0x%04x\n",    event->key_symbol );
1051      if (event->flags & DIEF_MODIFIERS)
1052           D_DEBUG_AT( Core_InputEvt, "  => MODIFIERS  0x%04x\n",    event->modifiers );
1053      if (event->flags & DIEF_LOCKS)
1054           D_DEBUG_AT( Core_InputEvt, "  => LOCKS      0x%04x\n",    event->locks );
1055      if (event->flags & DIEF_BUTTONS)
1056           D_DEBUG_AT( Core_InputEvt, "  => BUTTONS    0x%04x\n",    event->buttons );
1057      if (event->flags & DIEF_GLOBAL)
1058           D_DEBUG_AT( Core_InputEvt, "  => GLOBAL\n" );
1059 #endif
1060 
1061      if (core_input_filter( device, event ))
1062           D_DEBUG_AT( Core_InputEvt, "  ****>> FILTERED\n" );
1063      else
1064           fusion_reactor_dispatch( device->shared->reactor, event, true, dfb_input_globals );
1065 }
1066 
1067 DFBInputDeviceID
dfb_input_device_id(const CoreInputDevice * device)1068 dfb_input_device_id( const CoreInputDevice *device )
1069 {
1070      D_MAGIC_ASSERT( device, CoreInputDevice );
1071 
1072      D_ASSERT( core_input != NULL );
1073      D_ASSERT( device != NULL );
1074      D_ASSERT( device->shared != NULL );
1075 
1076      return device->shared->id;
1077 }
1078 
1079 CoreInputDevice *
dfb_input_device_at(DFBInputDeviceID id)1080 dfb_input_device_at( DFBInputDeviceID id )
1081 {
1082      CoreInputDevice *device;
1083 
1084      D_ASSERT( core_input != NULL );
1085 
1086      direct_list_foreach (device, core_local->devices) {
1087           D_MAGIC_ASSERT( device, CoreInputDevice );
1088 
1089           if (device->shared->id == id)
1090                return device;
1091      }
1092 
1093      return NULL;
1094 }
1095 
1096 /* Get an input device's capabilities. */
1097 DFBInputDeviceCapabilities
dfb_input_device_caps(const CoreInputDevice * device)1098 dfb_input_device_caps( const CoreInputDevice *device )
1099 {
1100      D_MAGIC_ASSERT( device, CoreInputDevice );
1101 
1102      D_ASSERT( core_input != NULL );
1103      D_ASSERT( device != NULL );
1104      D_ASSERT( device->shared != NULL );
1105 
1106      return device->shared->device_info.desc.caps;
1107 }
1108 
1109 void
dfb_input_device_description(const CoreInputDevice * device,DFBInputDeviceDescription * desc)1110 dfb_input_device_description( const CoreInputDevice     *device,
1111                               DFBInputDeviceDescription *desc )
1112 {
1113      D_MAGIC_ASSERT( device, CoreInputDevice );
1114 
1115      D_ASSERT( core_input != NULL );
1116      D_ASSERT( device != NULL );
1117      D_ASSERT( device->shared != NULL );
1118 
1119      *desc = device->shared->device_info.desc;
1120 }
1121 
1122 DFBResult
dfb_input_device_get_keymap_entry(CoreInputDevice * device,int keycode,DFBInputDeviceKeymapEntry * entry)1123 dfb_input_device_get_keymap_entry( CoreInputDevice           *device,
1124                                    int                        keycode,
1125                                    DFBInputDeviceKeymapEntry *entry )
1126 {
1127      DFBInputDeviceKeymapEntry *keymap_entry;
1128 
1129      D_MAGIC_ASSERT( device, CoreInputDevice );
1130 
1131      D_ASSERT( core_input != NULL );
1132      D_ASSERT( device != NULL );
1133      D_ASSERT( entry != NULL );
1134 
1135      keymap_entry = get_keymap_entry( device, keycode );
1136      if (!keymap_entry)
1137           return DFB_FAILURE;
1138 
1139      *entry = *keymap_entry;
1140 
1141      return DFB_OK;
1142 }
1143 
1144 DFBResult
dfb_input_device_set_keymap_entry(CoreInputDevice * device,int keycode,const DFBInputDeviceKeymapEntry * entry)1145 dfb_input_device_set_keymap_entry( CoreInputDevice                 *device,
1146                                    int                              keycode,
1147                                    const DFBInputDeviceKeymapEntry *entry )
1148 {
1149      D_MAGIC_ASSERT( device, CoreInputDevice );
1150 
1151      D_ASSERT( core_input != NULL );
1152      D_ASSERT( device != NULL );
1153      D_ASSERT( entry != NULL );
1154 
1155      return set_keymap_entry( device, keycode, entry );
1156 }
1157 
1158 DFBResult
dfb_input_device_load_keymap(CoreInputDevice * device,char * filename)1159 dfb_input_device_load_keymap   ( CoreInputDevice           *device,
1160                                  char                      *filename )
1161 {
1162      D_MAGIC_ASSERT( device, CoreInputDevice );
1163 
1164      D_ASSERT( core_input != NULL );
1165      D_ASSERT( device != NULL );
1166      D_ASSERT( filename != NULL );
1167 
1168      return load_keymap( device, filename );
1169 }
1170 
1171 DFBResult
dfb_input_device_reload_keymap(CoreInputDevice * device)1172 dfb_input_device_reload_keymap( CoreInputDevice *device )
1173 {
1174      InputDeviceShared *shared;
1175 
1176      D_MAGIC_ASSERT( device, CoreInputDevice );
1177 
1178      shared = device->shared;
1179      D_ASSERT( shared != NULL );
1180 
1181      D_INFO( "DirectFB/Input: Reloading keymap for '%s' [0x%02x]...\n",
1182              shared->device_info.desc.name, shared->id );
1183 
1184      return reload_keymap( device );
1185 }
1186 
1187 DFBResult
dfb_input_device_get_state(CoreInputDevice * device,CoreInputDeviceState * ret_state)1188 dfb_input_device_get_state( CoreInputDevice      *device,
1189                             CoreInputDeviceState *ret_state )
1190 {
1191      InputDeviceShared *shared;
1192 
1193      D_MAGIC_ASSERT( device, CoreInputDevice );
1194 
1195      shared = device->shared;
1196      D_ASSERT( shared != NULL );
1197 
1198      *ret_state = shared->state;
1199 
1200      return DFB_OK;
1201 }
1202 
1203 /** internal **/
1204 
1205 static void
input_add_device(CoreInputDevice * device)1206 input_add_device( CoreInputDevice *device )
1207 {
1208      D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device );
1209 
1210      D_MAGIC_ASSERT( device, CoreInputDevice );
1211 
1212      D_ASSERT( core_input != NULL );
1213      D_ASSERT( device != NULL );
1214      D_ASSERT( device->shared != NULL );
1215 
1216      if (core_input->num == MAX_INPUTDEVICES) {
1217           D_ERROR( "DirectFB/Input: Maximum number of devices reached!\n" );
1218           return;
1219      }
1220 
1221      direct_list_append( &core_local->devices, &device->link );
1222 
1223      core_input->devices[ core_input->num++ ] = device->shared;
1224 }
1225 
1226 static void
allocate_device_keymap(CoreDFB * core,CoreInputDevice * device)1227 allocate_device_keymap( CoreDFB *core, CoreInputDevice *device )
1228 {
1229      int                        i;
1230      DFBInputDeviceKeymapEntry *entries;
1231      FusionSHMPoolShared       *pool        = dfb_core_shmpool( core );
1232      InputDeviceShared         *shared      = device->shared;
1233      DFBInputDeviceDescription *desc        = &shared->device_info.desc;
1234      int                        num_entries = desc->max_keycode -
1235                                               desc->min_keycode + 1;
1236 
1237      D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, core, device );
1238 
1239      D_MAGIC_ASSERT( device, CoreInputDevice );
1240 
1241      D_ASSERT( core_input != NULL );
1242 
1243      entries = SHCALLOC( pool, num_entries, sizeof(DFBInputDeviceKeymapEntry) );
1244      if (!entries) {
1245           D_OOSHM();
1246           return;
1247      }
1248 
1249      /* write -1 indicating entry is not fetched yet from driver */
1250      for (i=0; i<num_entries; i++)
1251           entries[i].code = -1;
1252 
1253      shared->keymap.min_keycode = desc->min_keycode;
1254      shared->keymap.max_keycode = desc->max_keycode;
1255      shared->keymap.num_entries = num_entries;
1256      shared->keymap.entries     = entries;
1257 
1258 #if FUSION_BUILD_MULTI
1259      /* we need to fetch the whole map, otherwise a slave would try to */
1260      for (i=desc->min_keycode; i<=desc->max_keycode; i++)
1261           get_keymap_entry( device, i );
1262 #endif
1263 }
1264 
1265 static int
make_id(DFBInputDeviceID prefered)1266 make_id( DFBInputDeviceID prefered )
1267 {
1268      CoreInputDevice *device;
1269 
1270      D_DEBUG_AT( Core_Input, "%s( 0x%02x )\n", __FUNCTION__, prefered );
1271 
1272      D_ASSERT( core_input != NULL );
1273 
1274      direct_list_foreach (device, core_local->devices) {
1275           D_MAGIC_ASSERT( device, CoreInputDevice );
1276 
1277           if (device->shared->id == prefered)
1278                return make_id( (prefered < DIDID_ANY) ? DIDID_ANY : (prefered + 1) );
1279      }
1280 
1281      return prefered;
1282 }
1283 
1284 static DFBResult
reload_keymap(CoreInputDevice * device)1285 reload_keymap( CoreInputDevice *device )
1286 {
1287      int                i;
1288      InputDeviceShared *shared;
1289 
1290      D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device );
1291 
1292      D_MAGIC_ASSERT( device, CoreInputDevice );
1293 
1294      shared = device->shared;
1295 
1296      D_ASSERT( shared != NULL );
1297 
1298      if (shared->device_info.desc.min_keycode < 0 ||
1299          shared->device_info.desc.max_keycode < 0)
1300           return DFB_UNSUPPORTED;
1301 
1302      /* write -1 indicating entry is not fetched yet from driver */
1303      for (i=0; i<shared->keymap.num_entries; i++)
1304           shared->keymap.entries[i].code = -1;
1305 
1306      /* fetch the whole map */
1307      for (i=shared->keymap.min_keycode; i<=shared->keymap.max_keycode; i++)
1308           get_keymap_entry( device, i );
1309 
1310      D_INFO( "DirectFB/Input: Reloaded keymap for '%s' [0x%02x]\n",
1311              shared->device_info.desc.name, shared->id );
1312 
1313      return DFB_OK;
1314 }
1315 
1316 static DFBResult
init_axes(CoreInputDevice * device)1317 init_axes( CoreInputDevice *device )
1318 {
1319      int                     i, num;
1320      DFBResult               ret;
1321      InputDeviceShared      *shared;
1322      const InputDriverFuncs *funcs;
1323 
1324      D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device );
1325 
1326      D_MAGIC_ASSERT( device, CoreInputDevice );
1327      D_ASSERT( device->driver != NULL );
1328 
1329      funcs = device->driver->funcs;
1330      D_ASSERT( funcs != NULL );
1331 
1332      shared = device->shared;
1333      D_ASSERT( shared != NULL );
1334 
1335      if (shared->device_info.desc.max_axis < 0)
1336           return DFB_OK;
1337 
1338      num = shared->device_info.desc.max_axis + 1;
1339 
1340      shared->axis_info = SHCALLOC( dfb_core_shmpool(device->core), num, sizeof(DFBInputDeviceAxisInfo) );
1341      if (!shared->axis_info)
1342           return D_OOSHM();
1343 
1344      shared->axis_num = num;
1345 
1346      if (funcs->GetAxisInfo) {
1347           for (i=0; i<num; i++) {
1348                ret = funcs->GetAxisInfo( device, device->driver_data, i, &shared->axis_info[i] );
1349                if (ret)
1350                     D_DERROR( ret, "Core/Input: GetAxisInfo() failed for '%s' [%d] on axis %d!\n",
1351                               shared->device_info.desc.name, shared->id, i );
1352           }
1353      }
1354 
1355      return DFB_OK;
1356 }
1357 
1358 static void
init_devices(CoreDFB * core)1359 init_devices( CoreDFB *core )
1360 {
1361      DirectLink          *next;
1362      DirectModuleEntry   *module;
1363      FusionSHMPoolShared *pool = dfb_core_shmpool( core );
1364 
1365      D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core );
1366 
1367      D_ASSERT( core_input != NULL );
1368 
1369      direct_list_foreach_safe (module, next, dfb_input_modules.entries) {
1370           int                     n;
1371           InputDriver            *driver;
1372           const InputDriverFuncs *funcs;
1373           InputDriverCapability   driver_cap;
1374           DFBResult               result;
1375 
1376           driver_cap = IDC_NONE;
1377 
1378           funcs = direct_module_ref( module );
1379           if (!funcs)
1380                continue;
1381 
1382           driver = D_CALLOC( 1, sizeof(InputDriver) );
1383           if (!driver) {
1384                D_OOM();
1385                direct_module_unref( module );
1386                continue;
1387           }
1388 
1389           D_ASSERT( funcs->GetDriverInfo != NULL );
1390 
1391           funcs->GetDriverInfo( &driver->info );
1392 
1393           D_DEBUG_AT( Core_Input, "  -> probing '%s'...\n", driver->info.name );
1394 
1395           driver->nr_devices = funcs->GetAvailable();
1396 
1397           /*
1398            * If the input provider supports hot-plug, always load the module.
1399            */
1400           if (!funcs->GetCapability) {
1401                D_DEBUG_AT(Core_Input, "InputDriverFuncs::GetCapability is NULL\n");
1402           }
1403           else {
1404                driver_cap = funcs->GetCapability();
1405           }
1406 
1407           if (!driver->nr_devices && !(driver_cap & IDC_HOTPLUG)) {
1408                direct_module_unref( module );
1409                D_FREE( driver );
1410                continue;
1411           }
1412 
1413           D_DEBUG_AT( Core_Input, "  -> %d available device(s) provided by '%s'.\n",
1414                       driver->nr_devices, driver->info.name );
1415 
1416           driver->module = module;
1417           driver->funcs  = funcs;
1418 
1419           direct_list_prepend( &core_local->drivers, &driver->link );
1420 
1421 
1422           for (n=0; n<driver->nr_devices; n++) {
1423                char               buf[128];
1424                CoreInputDevice   *device;
1425                InputDeviceInfo    device_info;
1426                InputDeviceShared *shared;
1427                void              *driver_data;
1428 
1429                device = D_CALLOC( 1, sizeof(CoreInputDevice) );
1430                if (!device) {
1431                     D_OOM();
1432                     continue;
1433                }
1434 
1435                shared = SHCALLOC( pool, 1, sizeof(InputDeviceShared) );
1436                if (!shared) {
1437                     D_OOSHM();
1438                     D_FREE( device );
1439                     continue;
1440                }
1441 
1442                device->core = core;
1443 
1444                memset( &device_info, 0, sizeof(InputDeviceInfo) );
1445 
1446                device_info.desc.min_keycode = -1;
1447                device_info.desc.max_keycode = -1;
1448 
1449                D_MAGIC_SET( device, CoreInputDevice );
1450 
1451                if (funcs->OpenDevice( device, n, &device_info, &driver_data )) {
1452                     SHFREE( pool, shared );
1453                     D_MAGIC_CLEAR( device );
1454                     D_FREE( device );
1455                     continue;
1456                }
1457 
1458                D_DEBUG_AT( Core_Input, "  -> opened '%s' (%d) %d.%d (%s)\n",
1459                            device_info.desc.name, n + 1, driver->info.version.major,
1460                            driver->info.version.minor, driver->info.vendor );
1461 
1462                if (driver->nr_devices > 1)
1463                     snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, n+1 );
1464                else
1465                     snprintf( buf, sizeof(buf), "%s", device_info.desc.name );
1466 
1467                /* init skirmish */
1468                fusion_skirmish_init( &shared->lock, buf, dfb_core_world(core) );
1469 
1470                /* create reactor */
1471                shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world(core) );
1472 
1473                fusion_reactor_add_permissions( shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH );
1474 
1475                fusion_reactor_set_lock( shared->reactor, &shared->lock );
1476 
1477                /* init call */
1478                CoreInputDevice_Init_Dispatch( core, device, &shared->call );
1479 
1480                /* initialize shared data */
1481                shared->id          = make_id(device_info.prefered_id);
1482                shared->num         = n;
1483                shared->device_info = device_info;
1484                shared->last_key    = DIKI_UNKNOWN;
1485                shared->first_press = true;
1486 
1487                /* initialize local data */
1488                device->shared      = shared;
1489                device->driver      = driver;
1490                device->driver_data = driver_data;
1491 
1492                D_INFO( "DirectFB/Input: %s %d.%d (%s)\n",
1493                        buf, driver->info.version.major,
1494                        driver->info.version.minor, driver->info.vendor );
1495 
1496 #if FUSION_BUILD_MULTI
1497                /* Initialize the ref between shared device and local device. */
1498                snprintf( buf, sizeof(buf), "Ref of input device(%d)", shared->id );
1499                fusion_ref_init( &shared->ref, buf, dfb_core_world(core) );
1500 
1501                fusion_ref_add_permissions( &shared->ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL );
1502 
1503                /* Increase reference counter. */
1504                fusion_ref_up( &shared->ref, false );
1505 #endif
1506 
1507                if (device_info.desc.min_keycode > device_info.desc.max_keycode) {
1508                     D_BUG("min_keycode > max_keycode");
1509                     device_info.desc.min_keycode = -1;
1510                     device_info.desc.max_keycode = -1;
1511                }
1512                else if (device_info.desc.min_keycode >= 0 &&
1513                         device_info.desc.max_keycode >= 0)
1514                     allocate_device_keymap( core, device );
1515 
1516                init_axes( device );
1517 
1518                /* add it to the list */
1519                input_add_device( device );
1520           }
1521 
1522           /*
1523            * If the driver supports hot-plug, launch its hot-plug thread to respond to
1524            * hot-plug events.  Failures in launching the hot-plug thread will only
1525            * result in no hot-plug feature being available.
1526            */
1527           if (driver_cap == IDC_HOTPLUG) {
1528                result = funcs->LaunchHotplug(core, (void*) driver);
1529 
1530                /* On failure, the input provider can still be used without hot-plug. */
1531                if (result) {
1532                     D_INFO( "DirectFB/Input: Failed to enable hot-plug "
1533                             "detection with %s\n ", driver->info.name);
1534                }
1535                else {
1536                     D_INFO( "DirectFB/Input: Hot-plug detection enabled with %s \n",
1537                             driver->info.name);
1538                }
1539           }
1540      }
1541 }
1542 
1543 /*
1544  * Create the DFB shared core input device, add the input device into the
1545  * local device list and shared dev array and broadcast the hot-plug in
1546  * message to all slaves.
1547  */
1548 DFBResult
dfb_input_create_device(int device_index,CoreDFB * core_in,void * driver_in)1549 dfb_input_create_device(int device_index, CoreDFB *core_in, void *driver_in)
1550 {
1551      char                    buf[128];
1552      CoreInputDevice        *device;
1553      InputDeviceInfo         device_info;
1554      InputDeviceShared      *shared;
1555      void                   *driver_data;
1556      InputDriver            *driver = NULL;
1557      const InputDriverFuncs *funcs;
1558      FusionSHMPoolShared    *pool;
1559      DFBResult               result;
1560 
1561      D_DEBUG_AT(Core_Input, "Enter: %s()\n", __FUNCTION__);
1562 
1563      driver = (InputDriver *)driver_in;
1564 
1565      pool = dfb_core_shmpool(core_in);
1566      funcs = driver->funcs;
1567      if (!funcs) {
1568           D_ERROR("DirectFB/Input: driver->funcs is NULL\n");
1569           goto errorExit;
1570      }
1571 
1572      device = D_CALLOC( 1, sizeof(CoreInputDevice) );
1573      if (!device) {
1574           D_OOM();
1575           goto errorExit;
1576      }
1577      shared = SHCALLOC( pool, 1, sizeof(InputDeviceShared) );
1578      if (!shared) {
1579           D_OOM();
1580           D_FREE( device );
1581           goto errorExit;
1582      }
1583 
1584      device->core = core_in;
1585 
1586      memset( &device_info, 0, sizeof(InputDeviceInfo) );
1587 
1588      device_info.desc.min_keycode = -1;
1589      device_info.desc.max_keycode = -1;
1590 
1591      D_MAGIC_SET( device, CoreInputDevice );
1592 
1593      if (funcs->OpenDevice( device, device_index, &device_info, &driver_data )) {
1594           SHFREE( pool, shared );
1595           D_MAGIC_CLEAR( device );
1596           D_FREE( device );
1597           D_DEBUG_AT( Core_Input,
1598                       "DirectFB/Input: Cannot open device in %s, at %d in %s\n",
1599                       __FUNCTION__, __LINE__, __FILE__);
1600           goto errorExit;
1601      }
1602 
1603      snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, device_index);
1604 
1605      /* init skirmish */
1606      result = fusion_skirmish_init( &shared->lock, buf, dfb_core_world(device->core) );
1607      if (result) {
1608           funcs->CloseDevice( driver_data );
1609           SHFREE( pool, shared );
1610           D_MAGIC_CLEAR( device );
1611           D_FREE( device );
1612           D_ERROR("DirectFB/Input: fusion_skirmish_init() failed! in %s, at %d in %s\n",
1613                   __FUNCTION__, __LINE__, __FILE__);
1614           goto errorExit;
1615      }
1616 
1617      /* create reactor */
1618      shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent),
1619                                            buf,
1620                                            dfb_core_world(device->core) );
1621      if (!shared->reactor) {
1622           funcs->CloseDevice( driver_data );
1623           SHFREE( pool, shared );
1624           D_MAGIC_CLEAR( device );
1625           D_FREE( device );
1626           fusion_skirmish_destroy(&shared->lock);
1627           D_ERROR("DirectFB/Input: fusion_reactor_new() failed! in %s, at %d in %s\n",
1628                   __FUNCTION__, __LINE__, __FILE__);
1629           goto errorExit;
1630      }
1631 
1632      fusion_reactor_add_permissions( shared->reactor, 0, FUSION_REACTOR_PERMIT_ATTACH_DETACH );
1633 
1634      fusion_reactor_set_lock( shared->reactor, &shared->lock );
1635 
1636      /* init call */
1637      CoreInputDevice_Init_Dispatch( device->core, device, &shared->call );
1638 
1639      /* initialize shared data */
1640      shared->id          = make_id(device_info.prefered_id);
1641      shared->num         = device_index;
1642      shared->device_info = device_info;
1643      shared->last_key    = DIKI_UNKNOWN;
1644      shared->first_press = true;
1645 
1646      /* initialize local data */
1647      device->shared      = shared;
1648      device->driver      = driver;
1649      device->driver_data = driver_data;
1650 
1651      D_INFO( "DirectFB/Input: %s %d.%d (%s)\n",
1652              buf, driver->info.version.major,
1653              driver->info.version.minor, driver->info.vendor );
1654 
1655 #if FUSION_BUILD_MULTI
1656      snprintf( buf, sizeof(buf), "Ref of input device(%d)", shared->id);
1657      fusion_ref_init( &shared->ref, buf, dfb_core_world(core_in));
1658      fusion_ref_add_permissions( &shared->ref, 0, FUSION_REF_PERMIT_REF_UNREF_LOCAL );
1659      fusion_ref_up( &shared->ref, false );
1660 #endif
1661 
1662      if (device_info.desc.min_keycode > device_info.desc.max_keycode) {
1663           D_BUG("min_keycode > max_keycode");
1664           device_info.desc.min_keycode = -1;
1665           device_info.desc.max_keycode = -1;
1666      }
1667      else if (device_info.desc.min_keycode >= 0 && device_info.desc.max_keycode >= 0)
1668           allocate_device_keymap( device->core, device );
1669 
1670      /* add it into local device list and shared dev array */
1671      D_DEBUG_AT(Core_Input,
1672                 "In master, add a new device with dev_id=%d\n",
1673                 shared->id);
1674 
1675      input_add_device( device );
1676      driver->nr_devices++;
1677 
1678      D_DEBUG_AT(Core_Input,
1679                 "Successfully added new input device with dev_id=%d in shared array\n",
1680                 shared->id);
1681 
1682      InputDeviceHotplugEvent    message;
1683 
1684      /* Setup the hot-plug in message. */
1685      message.is_plugin = true;
1686      message.dev_id = shared->id;
1687      gettimeofday (&message.stamp, NULL);
1688 
1689      /* Send the hot-plug in message */
1690 #if FUSION_BUILD_MULTI
1691      fusion_reactor_dispatch(core_input->reactor, &message, true, NULL);
1692 #else
1693      local_processing_hotplug((const void *) &message, (void*) core_in);
1694 #endif
1695      return DFB_OK;
1696 
1697 errorExit:
1698      return DFB_FAILURE;
1699 }
1700 
1701 /*
1702  * Tell whether the DFB input device handling of the system input device
1703  * indicated by device_index is already created.
1704  */
1705 static CoreInputDevice *
search_device_created(int device_index,void * driver_in)1706 search_device_created(int device_index, void *driver_in)
1707 {
1708      DirectLink  *n;
1709      CoreInputDevice *device;
1710 
1711      D_ASSERT(driver_in != NULL);
1712 
1713      direct_list_foreach_safe(device, n, core_local->devices) {
1714           if (device->driver != driver_in)
1715                continue;
1716 
1717           if (device->driver_data == NULL) {
1718                D_DEBUG_AT(Core_Input,
1719                           "The device %d has been closed!\n",
1720                           device->shared->id);
1721                return NULL;
1722           }
1723 
1724           if (device->driver->funcs->IsCreated &&
1725               !device->driver->funcs->IsCreated(device_index, device->driver_data)) {
1726                return device;
1727           }
1728      }
1729 
1730      return NULL;
1731 }
1732 
1733 /*
1734  * Remove the DFB shared core input device handling of the system input device
1735  * indicated by device_index and broadcast the hot-plug out message to all slaves.
1736  */
1737 DFBResult
dfb_input_remove_device(int device_index,void * driver_in)1738 dfb_input_remove_device(int device_index, void *driver_in)
1739 {
1740      CoreInputDevice    *device;
1741      InputDeviceShared  *shared;
1742      FusionSHMPoolShared *pool;
1743      int                 i;
1744      int                 found = 0;
1745      int                 device_id;
1746 
1747      D_DEBUG_AT(Core_Input, "Enter: %s()\n", __FUNCTION__);
1748 
1749      D_ASSERT(driver_in !=NULL);
1750 
1751      device = search_device_created(device_index, driver_in);
1752      if (device == NULL) {
1753           D_DEBUG_AT(Core_Input,
1754                      "DirectFB/input: Failed to find the device[%d] or the device is "
1755                      "closed.\n",
1756                      device_index);
1757           goto errorExit;
1758      }
1759 
1760      shared = device->shared;
1761      pool = dfb_core_shmpool( device->core );
1762      device_id = shared->id;
1763 
1764      D_DEBUG_AT(Core_Input, "Find the device with dev_id=%d\n", device_id);
1765 
1766      device->driver->funcs->CloseDevice( device->driver_data );
1767 
1768      device->driver->nr_devices--;
1769 
1770      InputDeviceHotplugEvent    message;
1771 
1772      /* Setup the hot-plug out message */
1773      message.is_plugin = false;
1774      message.dev_id = device_id;
1775      gettimeofday (&message.stamp, NULL);
1776 
1777      /* Send the hot-plug out message */
1778 #if FUSION_BUILD_MULTI
1779      fusion_reactor_dispatch( core_input->reactor, &message, true, NULL);
1780 
1781      int    loop = CHECK_NUMBER;
1782 
1783      while (--loop) {
1784           if (fusion_ref_zero_trylock( &device->shared->ref ) == DR_OK) {
1785                fusion_ref_unlock(&device->shared->ref);
1786                break;
1787           }
1788 
1789           usleep(CHECK_INTERVAL);
1790      }
1791 
1792      if (!loop)
1793           D_DEBUG_AT(Core_Input, "Shared device might be connected to by others\n");
1794 
1795      fusion_ref_destroy(&device->shared->ref);
1796 #else
1797      local_processing_hotplug((const void*) &message, (void*) device->core);
1798 #endif
1799 
1800      /* Remove the device from shared array */
1801      for (i = 0; i < core_input->num; i++) {
1802           if (!found && (core_input->devices[i]->id == shared->id))
1803                found = 1;
1804 
1805           if (found)
1806                core_input->devices[i] = core_input->devices[(i + 1) % MAX_INPUTDEVICES];
1807      }
1808      if (found)
1809           core_input->devices[core_input->num -1] = NULL;
1810 
1811      core_input->num--;
1812 
1813      CoreInputDevice_Deinit_Dispatch( &shared->call );
1814 
1815      fusion_skirmish_destroy( &shared->lock );
1816 
1817      fusion_reactor_free( shared->reactor );
1818 
1819      if (shared->keymap.entries)
1820           SHFREE( pool, shared->keymap.entries );
1821 
1822      SHFREE( pool, shared );
1823 
1824      D_DEBUG_AT(Core_Input,
1825                 "Successfully remove the device with dev_id=%d in shared array\n",
1826                 device_id);
1827 
1828      return DFB_OK;
1829 
1830 errorExit:
1831      return DFB_FAILURE;
1832 }
1833 
1834 /*
1835  * Create local input device and add it into the local input devices list.
1836  */
1837 static CoreInputDevice *
add_device_into_local_list(int dev_id)1838 add_device_into_local_list(int dev_id)
1839 {
1840      int i;
1841      D_DEBUG_AT(Core_Input, "Enter: %s()\n", __FUNCTION__);
1842      for (i = 0; i < core_input->num; i++) {
1843           if (core_input->devices[i]->id == dev_id) {
1844                CoreInputDevice *device;
1845 
1846                D_DEBUG_AT(Core_Input,
1847                           "Find the device with dev_id=%d in shared array, and "
1848                           "allocate local device\n",
1849                           dev_id);
1850 
1851                device = D_CALLOC( 1, sizeof(CoreInputDevice) );
1852                if (!device) {
1853                    return NULL;
1854                }
1855 
1856                device->shared = core_input->devices[i];
1857 
1858 #if FUSION_BUILD_MULTI
1859                /* Increase the reference counter. */
1860                fusion_ref_up( &device->shared->ref, false );
1861 #endif
1862 
1863                /* add it to the list */
1864                direct_list_append( &core_local->devices, &device->link );
1865 
1866                D_MAGIC_SET( device, CoreInputDevice );
1867                return device;
1868           }
1869      }
1870 
1871      return NULL;
1872 }
1873 
1874 /*
1875  * Local input device function that handles hot-plug in/out messages.
1876  */
1877 static ReactionResult
local_processing_hotplug(const void * msg_data,void * ctx)1878 local_processing_hotplug( const void *msg_data, void *ctx )
1879 {
1880      const InputDeviceHotplugEvent *message = msg_data;
1881      CoreInputDevice               *device = NULL;
1882 
1883      D_DEBUG_AT(Core_Input, "Enter: %s()\n", __FUNCTION__);
1884 
1885      D_DEBUG_AT(Core_Input,
1886                 "<PID:%6d> hotplug-in:%d device_id=%d message!\n",
1887                 getpid(),
1888                 message->is_plugin,
1889                 message->dev_id );
1890 
1891      if (message->is_plugin) {
1892 
1893           device = dfb_input_device_at(message->dev_id);
1894 
1895           if (!device){
1896                /* Update local device list according to shared devices array */
1897                if (!(device = add_device_into_local_list(message->dev_id))) {
1898                     D_ERROR("DirectFB/Input: update_local_devices_list() failed\n" );
1899                     goto errorExit;
1900                }
1901           }
1902 
1903           /* attach the device to event containers */
1904           containers_attach_device( device );
1905           /* attach the device to stack containers  */
1906           stack_containers_attach_device( device );
1907      }
1908      else {
1909           device = dfb_input_device_at(message->dev_id);
1910           if (device) {
1911 
1912                direct_list_remove(&core_local->devices, &device->link);
1913 
1914                containers_detach_device(device);
1915                stack_containers_detach_device(device);
1916 
1917 #if FUSION_BUILD_MULTI
1918                /* Decrease reference counter. */
1919                fusion_ref_down( &device->shared->ref, false );
1920 #endif
1921                D_MAGIC_CLEAR( device );
1922                D_FREE(device);
1923           }
1924           else
1925                D_ERROR("DirectFB/Input:Can't find the device to be removed!\n");
1926 
1927      }
1928 
1929      return DFB_OK;
1930 
1931 errorExit:
1932      return DFB_FAILURE;
1933 }
1934 
1935 static DFBInputDeviceKeymapEntry *
get_keymap_entry(CoreInputDevice * device,int code)1936 get_keymap_entry( CoreInputDevice *device,
1937                   int              code )
1938 {
1939      InputDeviceKeymap         *map;
1940      DFBInputDeviceKeymapEntry *entry;
1941 
1942      D_MAGIC_ASSERT( device, CoreInputDevice );
1943 
1944      D_ASSERT( core_input != NULL );
1945      D_ASSERT( device != NULL );
1946      D_ASSERT( device->shared != NULL );
1947 
1948      map = &device->shared->keymap;
1949 
1950      /* safety check */
1951      if (code < map->min_keycode || code > map->max_keycode)
1952           return NULL;
1953 
1954      /* point to right array index */
1955      entry = &map->entries[code - map->min_keycode];
1956 
1957      /* need to initialize? */
1958      if (entry->code != code) {
1959           DFBResult    ret;
1960           InputDriver *driver = device->driver;
1961 
1962           if (!driver) {
1963                D_BUG("seem to be a slave with an empty keymap");
1964                return NULL;
1965           }
1966 
1967           /* write keycode to entry */
1968           entry->code = code;
1969 
1970           /* fetch entry from driver */
1971           ret = driver->funcs->GetKeymapEntry( device,
1972                                                device->driver_data, entry );
1973           if (ret)
1974                return NULL;
1975 
1976           /* drivers may leave this blank */
1977           if (entry->identifier == DIKI_UNKNOWN)
1978                entry->identifier = symbol_to_id( entry->symbols[DIKSI_BASE] );
1979 
1980           if (entry->symbols[DIKSI_BASE_SHIFT] == DIKS_NULL)
1981                entry->symbols[DIKSI_BASE_SHIFT] = entry->symbols[DIKSI_BASE];
1982 
1983           if (entry->symbols[DIKSI_ALT] == DIKS_NULL)
1984                entry->symbols[DIKSI_ALT] = entry->symbols[DIKSI_BASE];
1985 
1986           if (entry->symbols[DIKSI_ALT_SHIFT] == DIKS_NULL)
1987                entry->symbols[DIKSI_ALT_SHIFT] = entry->symbols[DIKSI_ALT];
1988      }
1989 
1990      return entry;
1991 }
1992 
1993 /* replace a single keymap entry with the code-entry pair */
1994 static DFBResult
set_keymap_entry(CoreInputDevice * device,int code,const DFBInputDeviceKeymapEntry * entry)1995 set_keymap_entry( CoreInputDevice                 *device,
1996                   int                              code,
1997                   const DFBInputDeviceKeymapEntry *entry )
1998 {
1999      InputDeviceKeymap         *map;
2000 
2001      D_ASSERT( device->shared != NULL );
2002      D_ASSERT( device->shared->keymap.entries != NULL );
2003 
2004      map = &device->shared->keymap;
2005 
2006      /* sanity check */
2007      if (code < map->min_keycode || code > map->max_keycode)
2008           return DFB_FAILURE;
2009 
2010      /* copy the entry to the map */
2011      map->entries[code - map->min_keycode] = *entry;
2012 
2013      return DFB_OK;
2014 }
2015 
2016 /* replace the complete current keymap with a keymap from a file.
2017  * the minimum-maximum keycodes of the driver are to be respected.
2018  */
2019 static DFBResult
load_keymap(CoreInputDevice * device,char * filename)2020 load_keymap( CoreInputDevice           *device,
2021              char                      *filename )
2022 {
2023      DFBResult                  ret       = DFB_OK;
2024      InputDeviceKeymap         *map       = 0;
2025      FILE                      *file      = 0;
2026      DFBInputDeviceLockState    lockstate = 0;
2027 
2028      D_ASSERT( device->shared != NULL );
2029      D_ASSERT( device->shared->keymap.entries != NULL );
2030 
2031      map = &device->shared->keymap;
2032 
2033      /* open the file */
2034      file = fopen( filename, "r" );
2035      if( !file )
2036      {
2037           return errno2result( errno );
2038      }
2039 
2040      /* read the file, line by line, and consume the mentioned scancodes */
2041      while(1)
2042      {
2043           int   i;
2044           int   dummy;
2045           char  buffer[201];
2046           int   keycode;
2047           char  diki[201];
2048           char  diks[4][201];
2049           char *b;
2050 
2051           DFBInputDeviceKeymapEntry entry = { .code = 0 };
2052 
2053           b = fgets( buffer, 200, file );
2054           if( !b ) {
2055                if( feof(file) ) {
2056                     fclose(file);
2057                     return DFB_OK;
2058                }
2059                fclose(file);
2060                return errno2result(errno);
2061           }
2062 
2063           /* comment or empty line */
2064           if( buffer[0]=='#' || strcmp(buffer,"\n")==0 )
2065                continue;
2066 
2067           /* check for lock state change */
2068           if( !strncmp(buffer,"capslock:",9) ) { lockstate |=  DILS_CAPS; continue; }
2069           if( !strncmp(buffer,":capslock",9) ) { lockstate &= ~DILS_CAPS; continue; }
2070           if( !strncmp(buffer,"numlock:",8)  ) { lockstate |=  DILS_NUM;  continue; }
2071           if( !strncmp(buffer,":numlock",8)  ) { lockstate &= ~DILS_NUM;  continue; }
2072 
2073           i = sscanf( buffer, " keycode %i = %s = %s %s %s %s %i\n",
2074                     &keycode, diki, diks[0], diks[1], diks[2], diks[3], &dummy );
2075 
2076           if( i < 3 || i > 6 ) {
2077                /* we want 1 to 4 key symbols */
2078                D_INFO( "DirectFB/Input: skipped erroneous input line %s\n", buffer );
2079                continue;
2080           }
2081 
2082           if( keycode > map->max_keycode || keycode < map->min_keycode ) {
2083                D_INFO( "DirectFB/Input: skipped keycode %d out of range\n", keycode );
2084                continue;
2085           }
2086 
2087           entry.code       = keycode;
2088           entry.locks      = lockstate;
2089           entry.identifier = lookup_keyidentifier( diki );
2090 
2091           switch( i ) {
2092                case 6:  entry.symbols[3] = lookup_keysymbol( diks[3] );
2093                case 5:  entry.symbols[2] = lookup_keysymbol( diks[2] );
2094                case 4:  entry.symbols[1] = lookup_keysymbol( diks[1] );
2095                case 3:  entry.symbols[0] = lookup_keysymbol( diks[0] );
2096 
2097                     /* fall through */
2098           }
2099 
2100           switch( i ) {
2101                case 3:  entry.symbols[1] = entry.symbols[0];
2102                case 4:  entry.symbols[2] = entry.symbols[0];
2103                case 5:  entry.symbols[3] = entry.symbols[1];
2104 
2105                /* fall through */
2106           }
2107 
2108           ret = CoreInputDevice_SetKeymapEntry( device, keycode, &entry );
2109           if( ret )
2110                return ret;
2111      }
2112 }
2113 
lookup_keysymbol(char * symbolname)2114 static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname )
2115 {
2116      int i;
2117 
2118      /* we want uppercase */
2119      for( i=0; i<strlen(symbolname); i++ )
2120           if( symbolname[i] >= 'a' && symbolname[i] <= 'z' )
2121                symbolname[i] = symbolname[i] - 'a' + 'A';
2122 
2123      for( i=0; i < sizeof (KeySymbolNames) / sizeof (KeySymbolNames[0]); i++ ) {
2124           if( strcmp( symbolname, KeySymbolNames[i].name ) == 0 )
2125                return KeySymbolNames[i].symbol;
2126      }
2127 
2128      /* not found, maybe starting with 0x for raw conversion.
2129       * We are already at uppercase.
2130       */
2131      if( symbolname[0]=='0' && symbolname[1]=='X' ) {
2132           int code=0;
2133           symbolname+=2;
2134           while(*symbolname) {
2135                if( *symbolname >= '0' && *symbolname <= '9' ) {
2136                     code = code*16 + *symbolname - '0';
2137                } else if( *symbolname >= 'A' && *symbolname <= 'F' ) {
2138                     code = code*16 + *symbolname - 'A' + 10;
2139                } else {
2140                     /* invalid character */
2141                     return DIKS_NULL;
2142                }
2143                symbolname++;
2144           }
2145           return code;
2146      }
2147 
2148      return DIKS_NULL;
2149 }
2150 
lookup_keyidentifier(char * identifiername)2151 static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername )
2152 {
2153      int i;
2154 
2155      /* we want uppercase */
2156      for( i=0; i<strlen(identifiername); i++ )
2157           if( identifiername[i] >= 'a' && identifiername[i] <= 'z' )
2158                identifiername[i] = identifiername[i] - 'a' + 'A';
2159 
2160      for( i=0; i < sizeof (KeyIdentifierNames) / sizeof (KeyIdentifierNames[0]); i++ ) {
2161           if( strcmp( identifiername, KeyIdentifierNames[i].name ) == 0 )
2162                return KeyIdentifierNames[i].identifier;
2163      }
2164 
2165      return DIKI_UNKNOWN;
2166 }
2167 
2168 static bool
lookup_from_table(CoreInputDevice * device,DFBInputEvent * event,DFBInputEventFlags lookup)2169 lookup_from_table( CoreInputDevice    *device,
2170                    DFBInputEvent      *event,
2171                    DFBInputEventFlags  lookup )
2172 {
2173      DFBInputDeviceKeymapEntry *entry;
2174 
2175      D_MAGIC_ASSERT( device, CoreInputDevice );
2176 
2177      D_ASSERT( core_input != NULL );
2178      D_ASSERT( device != NULL );
2179      D_ASSERT( device->shared != NULL );
2180      D_ASSERT( event != NULL );
2181 
2182      /* fetch the entry from the keymap, possibly calling the driver */
2183      entry = get_keymap_entry( device, event->key_code );
2184      if (!entry)
2185           return false;
2186 
2187      /* lookup identifier */
2188      if (lookup & DIEF_KEYID)
2189           event->key_id = entry->identifier;
2190 
2191      /* lookup symbol */
2192      if (lookup & DIEF_KEYSYMBOL) {
2193           DFBInputDeviceKeymapSymbolIndex index =
2194                (event->modifiers & DIMM_ALTGR) ? DIKSI_ALT : DIKSI_BASE;
2195 
2196           if ((event->modifiers & DIMM_SHIFT) || (entry->locks & event->locks))
2197                index++;
2198 
2199           /* don't modify modifiers */
2200           if (DFB_KEY_TYPE( entry->symbols[DIKSI_BASE] ) == DIKT_MODIFIER)
2201                event->key_symbol = entry->symbols[DIKSI_BASE];
2202           else
2203                event->key_symbol = entry->symbols[index];
2204      }
2205 
2206      return true;
2207 }
2208 
2209 static int
find_key_code_by_id(CoreInputDevice * device,DFBInputDeviceKeyIdentifier id)2210 find_key_code_by_id( CoreInputDevice             *device,
2211                      DFBInputDeviceKeyIdentifier  id )
2212 {
2213      int                i;
2214      InputDeviceKeymap *map;
2215 
2216      D_MAGIC_ASSERT( device, CoreInputDevice );
2217 
2218      D_ASSERT( core_input != NULL );
2219      D_ASSERT( device != NULL );
2220      D_ASSERT( device->shared != NULL );
2221 
2222      map = &device->shared->keymap;
2223 
2224      for (i=0; i<map->num_entries; i++) {
2225           DFBInputDeviceKeymapEntry *entry = &map->entries[i];
2226 
2227           if (entry->identifier == id)
2228                return entry->code;
2229      }
2230 
2231      return -1;
2232 }
2233 
2234 static int
find_key_code_by_symbol(CoreInputDevice * device,DFBInputDeviceKeySymbol symbol)2235 find_key_code_by_symbol( CoreInputDevice         *device,
2236                          DFBInputDeviceKeySymbol  symbol )
2237 {
2238      int                i;
2239      InputDeviceKeymap *map;
2240 
2241      D_MAGIC_ASSERT( device, CoreInputDevice );
2242 
2243      D_ASSERT( core_input != NULL );
2244      D_ASSERT( device != NULL );
2245      D_ASSERT( device->shared != NULL );
2246 
2247      map = &device->shared->keymap;
2248 
2249      for (i=0; i<map->num_entries; i++) {
2250           int                        n;
2251           DFBInputDeviceKeymapEntry *entry = &map->entries[i];
2252 
2253           for (n=0; n<=DIKSI_LAST; n++)
2254                if (entry->symbols[n] == symbol)
2255                     return entry->code;
2256      }
2257 
2258      return -1;
2259 }
2260 
2261 #define FIXUP_KEY_FIELDS     (DIEF_MODIFIERS | DIEF_LOCKS | \
2262                               DIEF_KEYCODE | DIEF_KEYID | DIEF_KEYSYMBOL)
2263 
2264 /*
2265  * Fill partially missing values for key_code, key_id and key_symbol by
2266  * translating those that are set. Fix modifiers/locks before if not set.
2267  *
2268  *
2269  * There are five valid constellations that give reasonable values.
2270  * (not counting the constellation where everything is set)
2271  *
2272  * Device has no translation table
2273  *   1. key_id is set, key_symbol not
2274  *      -> key_code defaults to -1, key_symbol from key_id (up-translation)
2275  *   2. key_symbol is set, key_id not
2276  *      -> key_code defaults to -1, key_id from key_symbol (down-translation)
2277  *
2278  * Device has a translation table
2279  *   3. key_code is set
2280  *      -> look up key_id and/or key_symbol (key_code being the index)
2281  *   4. key_id is set
2282  *      -> look up key_code and possibly key_symbol (key_id being searched for)
2283  *   5. key_symbol is set
2284  *      -> look up key_code and key_id (key_symbol being searched for)
2285  *
2286  * Fields remaining will be set to the default, e.g. key_code to -1.
2287  */
2288 static void
fixup_key_event(CoreInputDevice * device,DFBInputEvent * event)2289 fixup_key_event( CoreInputDevice *device, DFBInputEvent *event )
2290 {
2291      int                 i;
2292      DFBInputEventFlags  valid   = event->flags & FIXUP_KEY_FIELDS;
2293      DFBInputEventFlags  missing = valid ^ FIXUP_KEY_FIELDS;
2294      InputDeviceShared  *shared  = device->shared;
2295 
2296      D_MAGIC_ASSERT( device, CoreInputDevice );
2297 
2298      /* Add missing flags */
2299      event->flags |= missing;
2300 
2301      /*
2302       * Use cached values for modifiers/locks if they are missing.
2303       */
2304      if (missing & DIEF_MODIFIERS)
2305           event->modifiers = shared->state.modifiers_l | shared->state.modifiers_r;
2306 
2307      if (missing & DIEF_LOCKS)
2308           event->locks = shared->state.locks;
2309 
2310      /*
2311       * With translation table
2312       */
2313      if (device->shared->keymap.num_entries) {
2314           if (valid & DIEF_KEYCODE) {
2315                lookup_from_table( device, event, missing );
2316 
2317                missing &= ~(DIEF_KEYID | DIEF_KEYSYMBOL);
2318           }
2319           else if (valid & DIEF_KEYID) {
2320                event->key_code = find_key_code_by_id( device, event->key_id );
2321 
2322                if (event->key_code != -1) {
2323                     lookup_from_table( device, event, missing );
2324 
2325                     missing &= ~(DIEF_KEYCODE | DIEF_KEYSYMBOL);
2326                }
2327                else if (missing & DIEF_KEYSYMBOL) {
2328                     event->key_symbol = id_to_symbol( event->key_id,
2329                                                       event->modifiers,
2330                                                       event->locks );
2331                     missing &= ~DIEF_KEYSYMBOL;
2332                }
2333           }
2334           else if (valid & DIEF_KEYSYMBOL) {
2335                event->key_code = find_key_code_by_symbol( device,
2336                                                           event->key_symbol );
2337 
2338                if (event->key_code != -1) {
2339                     lookup_from_table( device, event, missing );
2340 
2341                     missing &= ~(DIEF_KEYCODE | DIEF_KEYID);
2342                }
2343                else {
2344                     event->key_id = symbol_to_id( event->key_symbol );
2345                     missing &= ~DIEF_KEYSYMBOL;
2346                }
2347           }
2348      }
2349      else {
2350           /*
2351            * Without translation table
2352            */
2353           if (valid & DIEF_KEYID) {
2354                if (missing & DIEF_KEYSYMBOL) {
2355                     event->key_symbol = id_to_symbol( event->key_id,
2356                                                       event->modifiers,
2357                                                       event->locks );
2358                     missing &= ~DIEF_KEYSYMBOL;
2359                }
2360           }
2361           else if (valid & DIEF_KEYSYMBOL) {
2362                event->key_id = symbol_to_id( event->key_symbol );
2363                missing &= ~DIEF_KEYID;
2364           }
2365      }
2366 
2367      /*
2368       * Clear remaining fields.
2369       */
2370      if (missing & DIEF_KEYCODE)
2371           event->key_code = -1;
2372 
2373      if (missing & DIEF_KEYID)
2374           event->key_id = DIKI_UNKNOWN;
2375 
2376      if (missing & DIEF_KEYSYMBOL)
2377           event->key_symbol = DIKS_NULL;
2378 
2379      /*
2380       * Update cached values for modifiers.
2381       */
2382      if (DFB_KEY_TYPE(event->key_symbol) == DIKT_MODIFIER) {
2383           if (event->type == DIET_KEYPRESS) {
2384                switch (event->key_id) {
2385                     case DIKI_SHIFT_L:
2386                          shared->state.modifiers_l |= DIMM_SHIFT;
2387                          break;
2388                     case DIKI_SHIFT_R:
2389                          shared->state.modifiers_r |= DIMM_SHIFT;
2390                          break;
2391                     case DIKI_CONTROL_L:
2392                          shared->state.modifiers_l |= DIMM_CONTROL;
2393                          break;
2394                     case DIKI_CONTROL_R:
2395                          shared->state.modifiers_r |= DIMM_CONTROL;
2396                          break;
2397                     case DIKI_ALT_L:
2398                          shared->state.modifiers_l |= DIMM_ALT;
2399                          break;
2400                     case DIKI_ALT_R:
2401                          shared->state.modifiers_r |= (event->key_symbol == DIKS_ALTGR) ? DIMM_ALTGR : DIMM_ALT;
2402                          break;
2403                     case DIKI_META_L:
2404                          shared->state.modifiers_l |= DIMM_META;
2405                          break;
2406                     case DIKI_META_R:
2407                          shared->state.modifiers_r |= DIMM_META;
2408                          break;
2409                     case DIKI_SUPER_L:
2410                          shared->state.modifiers_l |= DIMM_SUPER;
2411                          break;
2412                     case DIKI_SUPER_R:
2413                          shared->state.modifiers_r |= DIMM_SUPER;
2414                          break;
2415                     case DIKI_HYPER_L:
2416                          shared->state.modifiers_l |= DIMM_HYPER;
2417                          break;
2418                     case DIKI_HYPER_R:
2419                          shared->state.modifiers_r |= DIMM_HYPER;
2420                          break;
2421                     default:
2422                          ;
2423                }
2424           }
2425           else {
2426                switch (event->key_id) {
2427                     case DIKI_SHIFT_L:
2428                          shared->state.modifiers_l &= ~DIMM_SHIFT;
2429                          break;
2430                     case DIKI_SHIFT_R:
2431                          shared->state.modifiers_r &= ~DIMM_SHIFT;
2432                          break;
2433                     case DIKI_CONTROL_L:
2434                          shared->state.modifiers_l &= ~DIMM_CONTROL;
2435                          break;
2436                     case DIKI_CONTROL_R:
2437                          shared->state.modifiers_r &= ~DIMM_CONTROL;
2438                          break;
2439                     case DIKI_ALT_L:
2440                          shared->state.modifiers_l &= ~DIMM_ALT;
2441                          break;
2442                     case DIKI_ALT_R:
2443                          shared->state.modifiers_r &= (event->key_symbol == DIKS_ALTGR) ? ~DIMM_ALTGR : ~DIMM_ALT;
2444                          break;
2445                     case DIKI_META_L:
2446                          shared->state.modifiers_l &= ~DIMM_META;
2447                          break;
2448                     case DIKI_META_R:
2449                          shared->state.modifiers_r &= ~DIMM_META;
2450                          break;
2451                     case DIKI_SUPER_L:
2452                          shared->state.modifiers_l &= ~DIMM_SUPER;
2453                          break;
2454                     case DIKI_SUPER_R:
2455                          shared->state.modifiers_r &= ~DIMM_SUPER;
2456                          break;
2457                     case DIKI_HYPER_L:
2458                          shared->state.modifiers_l &= ~DIMM_HYPER;
2459                          break;
2460                     case DIKI_HYPER_R:
2461                          shared->state.modifiers_r &= ~DIMM_HYPER;
2462                          break;
2463                     default:
2464                          ;
2465                }
2466           }
2467 
2468           /* write back to event */
2469           if (missing & DIEF_MODIFIERS)
2470                event->modifiers = shared->state.modifiers_l | shared->state.modifiers_r;
2471      }
2472 
2473      /*
2474       * Update cached values for locks.
2475       */
2476      if (event->type == DIET_KEYPRESS) {
2477 
2478           /* When we receive a new key press, toggle lock flags */
2479           if (shared->first_press || shared->last_key != event->key_id) {
2480               switch (event->key_id) {
2481                    case DIKI_CAPS_LOCK:
2482                         shared->state.locks ^= DILS_CAPS;
2483                         break;
2484                    case DIKI_NUM_LOCK:
2485                         shared->state.locks ^= DILS_NUM;
2486                         break;
2487                    case DIKI_SCROLL_LOCK:
2488                         shared->state.locks ^= DILS_SCROLL;
2489                         break;
2490                    default:
2491                         ;
2492               }
2493           }
2494 
2495           /* write back to event */
2496           if (missing & DIEF_LOCKS)
2497                event->locks = shared->state.locks;
2498 
2499           /* store last pressed key */
2500           shared->last_key = event->key_id;
2501           shared->first_press = false;
2502      }
2503      else if (event->type == DIET_KEYRELEASE) {
2504 
2505           shared->first_press = true;
2506      }
2507 
2508      /* Handle dead keys. */
2509      if (DFB_KEY_TYPE(shared->last_symbol) == DIKT_DEAD) {
2510           for (i=0; i<D_ARRAY_SIZE(deadkey_maps); i++) {
2511                const DeadKeyMap *map = &deadkey_maps[i];
2512 
2513                if (map->deadkey == shared->last_symbol) {
2514                     for (i=0; map->combos[i].target; i++) {
2515                          if (map->combos[i].target == event->key_symbol) {
2516                               event->key_symbol = map->combos[i].result;
2517                               break;
2518                          }
2519                     }
2520                     break;
2521                }
2522           }
2523 
2524           if (event->type == DIET_KEYRELEASE &&
2525               DFB_KEY_TYPE(event->key_symbol) != DIKT_MODIFIER)
2526                shared->last_symbol = event->key_symbol;
2527      }
2528      else
2529           shared->last_symbol = event->key_symbol;
2530 }
2531 
2532 static void
fixup_mouse_event(CoreInputDevice * device,DFBInputEvent * event)2533 fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event )
2534 {
2535      InputDeviceShared *shared = device->shared;
2536 
2537      D_MAGIC_ASSERT( device, CoreInputDevice );
2538 
2539      if (event->flags & DIEF_BUTTONS) {
2540           shared->state.buttons = event->buttons;
2541      }
2542      else {
2543           switch (event->type) {
2544                case DIET_BUTTONPRESS:
2545                     shared->state.buttons |= (1 << event->button);
2546                     break;
2547                case DIET_BUTTONRELEASE:
2548                     shared->state.buttons &= ~(1 << event->button);
2549                     break;
2550                default:
2551                     ;
2552           }
2553 
2554           /* Add missing flag */
2555           event->flags |= DIEF_BUTTONS;
2556 
2557           event->buttons = shared->state.buttons;
2558      }
2559 
2560      switch (event->type) {
2561           case DIET_AXISMOTION:
2562                if ((event->flags & DIEF_AXISABS) && event->axis >= 0 && event->axis < shared->axis_num) {
2563                     if (!(event->flags & DIEF_MIN) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MIN)) {
2564                          event->min = shared->axis_info[event->axis].abs_min;
2565 
2566                          event->flags |= DIEF_MIN;
2567                     }
2568 
2569                     if (!(event->flags & DIEF_MAX) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MAX)) {
2570                          event->max = shared->axis_info[event->axis].abs_max;
2571 
2572                          event->flags |= DIEF_MAX;
2573                     }
2574                }
2575                break;
2576 
2577           default:
2578                break;
2579      }
2580 }
2581 
2582 static DFBInputDeviceKeyIdentifier
symbol_to_id(DFBInputDeviceKeySymbol symbol)2583 symbol_to_id( DFBInputDeviceKeySymbol symbol )
2584 {
2585      if (symbol >= 'a' && symbol <= 'z')
2586           return DIKI_A + symbol - 'a';
2587 
2588      if (symbol >= 'A' && symbol <= 'Z')
2589           return DIKI_A + symbol - 'A';
2590 
2591      if (symbol >= '0' && symbol <= '9')
2592           return DIKI_0 + symbol - '0';
2593 
2594      if (symbol >= DIKS_F1 && symbol <= DIKS_F12)
2595           return DIKI_F1 + symbol - DIKS_F1;
2596 
2597      switch (symbol) {
2598           case DIKS_ESCAPE:
2599                return DIKI_ESCAPE;
2600 
2601           case DIKS_CURSOR_LEFT:
2602                return DIKI_LEFT;
2603 
2604           case DIKS_CURSOR_RIGHT:
2605                return DIKI_RIGHT;
2606 
2607           case DIKS_CURSOR_UP:
2608                return DIKI_UP;
2609 
2610           case DIKS_CURSOR_DOWN:
2611                return DIKI_DOWN;
2612 
2613           case DIKS_ALTGR:
2614                return DIKI_ALT_R;
2615 
2616           case DIKS_CONTROL:
2617                return DIKI_CONTROL_L;
2618 
2619           case DIKS_SHIFT:
2620                return DIKI_SHIFT_L;
2621 
2622           case DIKS_ALT:
2623                return DIKI_ALT_L;
2624 
2625           case DIKS_META:
2626                return DIKI_META_L;
2627 
2628           case DIKS_SUPER:
2629                return DIKI_SUPER_L;
2630 
2631           case DIKS_HYPER:
2632                return DIKI_HYPER_L;
2633 
2634           case DIKS_TAB:
2635                return DIKI_TAB;
2636 
2637           case DIKS_ENTER:
2638                return DIKI_ENTER;
2639 
2640           case DIKS_SPACE:
2641                return DIKI_SPACE;
2642 
2643           case DIKS_BACKSPACE:
2644                return DIKI_BACKSPACE;
2645 
2646           case DIKS_INSERT:
2647                return DIKI_INSERT;
2648 
2649           case DIKS_DELETE:
2650                return DIKI_DELETE;
2651 
2652           case DIKS_HOME:
2653                return DIKI_HOME;
2654 
2655           case DIKS_END:
2656                return DIKI_END;
2657 
2658           case DIKS_PAGE_UP:
2659                return DIKI_PAGE_UP;
2660 
2661           case DIKS_PAGE_DOWN:
2662                return DIKI_PAGE_DOWN;
2663 
2664           case DIKS_CAPS_LOCK:
2665                return DIKI_CAPS_LOCK;
2666 
2667           case DIKS_NUM_LOCK:
2668                return DIKI_NUM_LOCK;
2669 
2670           case DIKS_SCROLL_LOCK:
2671                return DIKI_SCROLL_LOCK;
2672 
2673           case DIKS_PRINT:
2674                return DIKI_PRINT;
2675 
2676           case DIKS_PAUSE:
2677                return DIKI_PAUSE;
2678 
2679           case DIKS_BACKSLASH:
2680                return DIKI_BACKSLASH;
2681 
2682           case DIKS_PERIOD:
2683                return DIKI_PERIOD;
2684 
2685           case DIKS_COMMA:
2686                return DIKI_COMMA;
2687 
2688           default:
2689                ;
2690      }
2691 
2692      return DIKI_UNKNOWN;
2693 }
2694 
2695 static DFBInputDeviceKeySymbol
id_to_symbol(DFBInputDeviceKeyIdentifier id,DFBInputDeviceModifierMask modifiers,DFBInputDeviceLockState locks)2696 id_to_symbol( DFBInputDeviceKeyIdentifier id,
2697               DFBInputDeviceModifierMask  modifiers,
2698               DFBInputDeviceLockState     locks )
2699 {
2700      bool shift = (modifiers & DIMM_SHIFT) || (locks & DILS_CAPS);
2701 
2702      if (id >= DIKI_A && id <= DIKI_Z)
2703           return (shift ? DIKS_CAPITAL_A : DIKS_SMALL_A) + id - DIKI_A;
2704 
2705      if (id >= DIKI_0 && id <= DIKI_9)
2706           return DIKS_0 + id - DIKI_0;
2707 
2708      if (id >= DIKI_KP_0 && id <= DIKI_KP_9)
2709           return DIKS_0 + id - DIKI_KP_0;
2710 
2711      if (id >= DIKI_F1 && id <= DIKI_F12)
2712           return DIKS_F1 + id - DIKI_F1;
2713 
2714      switch (id) {
2715           case DIKI_ESCAPE:
2716                return DIKS_ESCAPE;
2717 
2718           case DIKI_LEFT:
2719                return DIKS_CURSOR_LEFT;
2720 
2721           case DIKI_RIGHT:
2722                return DIKS_CURSOR_RIGHT;
2723 
2724           case DIKI_UP:
2725                return DIKS_CURSOR_UP;
2726 
2727           case DIKI_DOWN:
2728                return DIKS_CURSOR_DOWN;
2729 
2730           case DIKI_CONTROL_L:
2731           case DIKI_CONTROL_R:
2732                return DIKS_CONTROL;
2733 
2734           case DIKI_SHIFT_L:
2735           case DIKI_SHIFT_R:
2736                return DIKS_SHIFT;
2737 
2738           case DIKI_ALT_L:
2739           case DIKI_ALT_R:
2740                return DIKS_ALT;
2741 
2742           case DIKI_META_L:
2743           case DIKI_META_R:
2744                return DIKS_META;
2745 
2746           case DIKI_SUPER_L:
2747           case DIKI_SUPER_R:
2748                return DIKS_SUPER;
2749 
2750           case DIKI_HYPER_L:
2751           case DIKI_HYPER_R:
2752                return DIKS_HYPER;
2753 
2754           case DIKI_TAB:
2755                return DIKS_TAB;
2756 
2757           case DIKI_ENTER:
2758                return DIKS_ENTER;
2759 
2760           case DIKI_SPACE:
2761                return DIKS_SPACE;
2762 
2763           case DIKI_BACKSPACE:
2764                return DIKS_BACKSPACE;
2765 
2766           case DIKI_INSERT:
2767                return DIKS_INSERT;
2768 
2769           case DIKI_DELETE:
2770                return DIKS_DELETE;
2771 
2772           case DIKI_HOME:
2773                return DIKS_HOME;
2774 
2775           case DIKI_END:
2776                return DIKS_END;
2777 
2778           case DIKI_PAGE_UP:
2779                return DIKS_PAGE_UP;
2780 
2781           case DIKI_PAGE_DOWN:
2782                return DIKS_PAGE_DOWN;
2783 
2784           case DIKI_CAPS_LOCK:
2785                return DIKS_CAPS_LOCK;
2786 
2787           case DIKI_NUM_LOCK:
2788                return DIKS_NUM_LOCK;
2789 
2790           case DIKI_SCROLL_LOCK:
2791                return DIKS_SCROLL_LOCK;
2792 
2793           case DIKI_PRINT:
2794                return DIKS_PRINT;
2795 
2796           case DIKI_PAUSE:
2797                return DIKS_PAUSE;
2798 
2799           case DIKI_KP_DIV:
2800                return DIKS_SLASH;
2801 
2802           case DIKI_KP_MULT:
2803                return DIKS_ASTERISK;
2804 
2805           case DIKI_KP_MINUS:
2806                return DIKS_MINUS_SIGN;
2807 
2808           case DIKI_KP_PLUS:
2809                return DIKS_PLUS_SIGN;
2810 
2811           case DIKI_KP_ENTER:
2812                return DIKS_ENTER;
2813 
2814           case DIKI_KP_SPACE:
2815                return DIKS_SPACE;
2816 
2817           case DIKI_KP_TAB:
2818                return DIKS_TAB;
2819 
2820           case DIKI_KP_EQUAL:
2821                return DIKS_EQUALS_SIGN;
2822 
2823           case DIKI_KP_DECIMAL:
2824                return DIKS_PERIOD;
2825 
2826           case DIKI_KP_SEPARATOR:
2827                return DIKS_COMMA;
2828 
2829           case DIKI_BACKSLASH:
2830                return DIKS_BACKSLASH;
2831 
2832           case DIKI_EQUALS_SIGN:
2833                return DIKS_EQUALS_SIGN;
2834 
2835           case DIKI_LESS_SIGN:
2836                return DIKS_LESS_THAN_SIGN;
2837 
2838           case DIKI_MINUS_SIGN:
2839                return DIKS_MINUS_SIGN;
2840 
2841           case DIKI_PERIOD:
2842                return DIKS_PERIOD;
2843 
2844           case DIKI_QUOTE_LEFT:
2845           case DIKI_QUOTE_RIGHT:
2846                return DIKS_QUOTATION;
2847 
2848           case DIKI_SEMICOLON:
2849                return DIKS_SEMICOLON;
2850 
2851           case DIKI_SLASH:
2852                return DIKS_SLASH;
2853 
2854           default:
2855                ;
2856      }
2857 
2858      return DIKS_NULL;
2859 }
2860 
2861 static void
release_key(CoreInputDevice * device,DFBInputDeviceKeyIdentifier id)2862 release_key( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id )
2863 {
2864      DFBInputEvent evt;
2865 
2866      D_MAGIC_ASSERT( device, CoreInputDevice );
2867 
2868      evt.type = DIET_KEYRELEASE;
2869 
2870      if (DFB_KEY_TYPE(id) == DIKT_IDENTIFIER) {
2871           evt.flags  = DIEF_KEYID;
2872           evt.key_id = id;
2873      }
2874      else {
2875           evt.flags      = DIEF_KEYSYMBOL;
2876           evt.key_symbol = id;
2877      }
2878 
2879      dfb_input_dispatch( device, &evt );
2880 }
2881 
2882 static void
flush_keys(CoreInputDevice * device)2883 flush_keys( CoreInputDevice *device )
2884 {
2885      D_MAGIC_ASSERT( device, CoreInputDevice );
2886 
2887      if (device->shared->state.modifiers_l) {
2888           if (device->shared->state.modifiers_l & DIMM_ALT)
2889                release_key( device, DIKI_ALT_L );
2890 
2891           if (device->shared->state.modifiers_l & DIMM_CONTROL)
2892                release_key( device, DIKI_CONTROL_L );
2893 
2894           if (device->shared->state.modifiers_l & DIMM_HYPER)
2895                release_key( device, DIKI_HYPER_L );
2896 
2897           if (device->shared->state.modifiers_l & DIMM_META)
2898                release_key( device, DIKI_META_L );
2899 
2900           if (device->shared->state.modifiers_l & DIMM_SHIFT)
2901                release_key( device, DIKI_SHIFT_L );
2902 
2903           if (device->shared->state.modifiers_l & DIMM_SUPER)
2904                release_key( device, DIKI_SUPER_L );
2905      }
2906 
2907      if (device->shared->state.modifiers_r) {
2908           if (device->shared->state.modifiers_r & DIMM_ALTGR)
2909                release_key( device, DIKS_ALTGR );
2910 
2911           if (device->shared->state.modifiers_r & DIMM_ALT)
2912                release_key( device, DIKI_ALT_R );
2913 
2914           if (device->shared->state.modifiers_r & DIMM_CONTROL)
2915                release_key( device, DIKI_CONTROL_R );
2916 
2917           if (device->shared->state.modifiers_r & DIMM_HYPER)
2918                release_key( device, DIKI_HYPER_R );
2919 
2920           if (device->shared->state.modifiers_r & DIMM_META)
2921                release_key( device, DIKI_META_R );
2922 
2923           if (device->shared->state.modifiers_r & DIMM_SHIFT)
2924                release_key( device, DIKI_SHIFT_R );
2925 
2926           if (device->shared->state.modifiers_r & DIMM_SUPER)
2927                release_key( device, DIKI_SUPER_R );
2928      }
2929 }
2930 
2931 static void
dump_primary_layer_surface(CoreDFB * core)2932 dump_primary_layer_surface( CoreDFB *core )
2933 {
2934      CoreLayer        *layer = dfb_layer_at( DLID_PRIMARY );
2935      CoreLayerContext *context;
2936 
2937      /* Get the currently active context. */
2938      if (dfb_layer_get_active_context( layer, &context ) == DFB_OK) {
2939           CoreLayerRegion *region;
2940 
2941           /* Get the first region. */
2942           if (dfb_layer_context_get_primary_region( context,
2943                                                     false, &region ) == DFB_OK)
2944           {
2945                CoreSurface *surface;
2946 
2947                /* Lock the region to avoid tearing due to concurrent updates. */
2948                dfb_layer_region_lock( region );
2949 
2950                /* Get the surface of the region. */
2951                if (dfb_layer_region_get_surface( region, &surface ) == DFB_OK) {
2952                     /* Dump the surface contents. */
2953                     dfb_surface_dump_buffer( surface, CSBR_FRONT, dfb_config->screenshot_dir, "dfb" );
2954 
2955                     /* Release the surface. */
2956                     dfb_surface_unref( surface );
2957                }
2958 
2959                /* Unlock the region. */
2960                dfb_layer_region_unlock( region );
2961 
2962                /* Release the region. */
2963                dfb_layer_region_unref( region );
2964           }
2965 
2966           /* Release the context. */
2967           dfb_layer_context_unref( context );
2968      }
2969 }
2970 
2971 static bool
core_input_filter(CoreInputDevice * device,DFBInputEvent * event)2972 core_input_filter( CoreInputDevice *device, DFBInputEvent *event )
2973 {
2974      D_MAGIC_ASSERT( device, CoreInputDevice );
2975 
2976      if (dfb_system_input_filter( device, event ))
2977           return true;
2978 
2979      if (event->type == DIET_KEYPRESS) {
2980           switch (event->key_symbol) {
2981                case DIKS_PRINT:
2982                     if (!event->modifiers && dfb_config->screenshot_dir) {
2983                          dump_primary_layer_surface( device->core );
2984                          return true;
2985                     }
2986                     break;
2987 
2988                case DIKS_BACKSPACE:
2989                     if (event->modifiers == DIMM_META)
2990                          direct_trace_print_stacks();
2991 
2992                     break;
2993 
2994                case DIKS_ESCAPE:
2995                     if (event->modifiers == DIMM_META) {
2996 #if FUSION_BUILD_MULTI
2997                          DFBResult         ret;
2998                          CoreLayer        *layer = dfb_layer_at( DLID_PRIMARY );
2999                          CoreLayerContext *context;
3000 
3001                          /* Get primary (shared) context. */
3002                          ret = dfb_layer_get_primary_context( layer,
3003                                                               false, &context );
3004                          if (ret)
3005                               return false;
3006 
3007                          /* Activate the context. */
3008                          dfb_layer_activate_context( layer, context );
3009 
3010                          /* Release the context. */
3011                          dfb_layer_context_unref( context );
3012 
3013 #else
3014                          kill( 0, SIGINT );
3015 #endif
3016 
3017                          return true;
3018                     }
3019                     break;
3020 
3021                default:
3022                     break;
3023           }
3024      }
3025 
3026      return false;
3027 }
3028 
3029