Search
lxdream.org :: lxdream/src/drivers/input_lirc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/input_lirc.c
changeset 1075:1a21750d300c
prev1050:7d88277590d9
next1296:30ecee61f811
author nkeynes
date Fri Jul 31 13:45:32 2009 +1000 (11 years ago)
permissions -rw-r--r--
last change Remove or change the level of a bunch of INFO messages that shouldn't really
be INFO level
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * LIRC input device support
     5  *
     6  * Copyright (c) 2009 wahrhaft
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <sys/types.h>
    20 #include <sys/ioctl.h>
    21 #include <errno.h>
    22 #include <stdio.h>
    23 #include <signal.h>
    24 #include <string.h>
    25 #include <stdlib.h>
    26 #include <unistd.h>
    27 #include <fcntl.h>
    28 #include <dirent.h>
    29 #include <ctype.h>
    31 #include <glib/giochannel.h>
    32 #include <glib.h>
    34 #include <lirc/lirc_client.h>
    36 #include "lxdream.h"
    37 #include "plugin.h"
    38 #include "display.h"
    39 #include "maple/maple.h"
    41 typedef struct input_lirc {
    42     struct input_driver driver;
    43     char name[5];
    44     int fd;
    45     GIOChannel *channel;
    46 } *input_lirc_t;
    48 #define MAX_KEYSYMS 65536
    49 static GData *keysyms;
    50 static uint16_t last_keycode;
    51 static GQuark keysym_by_keycode_result;
    54 static uint16_t input_lirc_resolve_keysym( input_driver_t dev, const gchar *str );
    55 static gchar *input_lirc_keysym_for_keycode( input_driver_t dev, uint16_t keycode );
    56 static void get_keysym_by_keycode(GQuark key_id, gpointer data, gpointer user_data);
    57 static gboolean input_lirc_callback( GIOChannel *source, GIOCondition condition, gpointer data );
    59 input_driver_t system_lirc_driver;
    61 static gboolean input_lirc_init()
    62 {
    63     input_lirc_t system_lirc_driver = g_malloc0(sizeof(struct input_lirc));
    64     strcpy(system_lirc_driver->name, "LIRC");
    65     system_lirc_driver->driver.id = system_lirc_driver->name;
    66     system_lirc_driver->driver.resolve_keysym = input_lirc_resolve_keysym;
    67     system_lirc_driver->driver.get_keysym_for_keycode = input_lirc_keysym_for_keycode;
    68     system_lirc_driver->driver.destroy = NULL;
    70     system_lirc_driver->fd = lirc_init("lxdream", 1);
    71     if (system_lirc_driver->fd == -1) {
    72         WARN("Could not initialize LIRC.  LIRC hotkeys will be disabled.");
    73         return FALSE;
    74     }
    76     system_lirc_driver->channel = g_io_channel_unix_new(system_lirc_driver->fd);
    77     g_io_channel_set_flags(system_lirc_driver->channel, G_IO_FLAG_IS_READABLE | G_IO_FLAG_NONBLOCK, NULL);
    78     g_io_add_watch(system_lirc_driver->channel, G_IO_IN|G_IO_ERR|G_IO_HUP, input_lirc_callback, system_lirc_driver);
    79     g_datalist_init(&keysyms);
    80     input_register_device((input_driver_t)system_lirc_driver, MAX_KEYSYMS - 1);
    81     return TRUE;
    82 }
    84 void input_lirc_shutdown(void)
    85 {
    86     input_lirc_t lirc = (input_lirc_t)system_lirc_driver;
    87     g_io_channel_shutdown(lirc->channel, FALSE, NULL );
    88     g_io_channel_unref(lirc->channel);
    89     lirc_deinit();
    90     g_free(system_lirc_driver);
    91 }
    93 static uint16_t input_lirc_resolve_keysym( input_driver_t dev, const gchar *str )
    94 {
    95     //LIRC uses keysyms but no keycodes.  To generate a keycode, we'll just make them up as we go.
    96     //As long as we store keysyms instead of keycodes in any config files, this should be fine.
    98     uint16_t keycode;
    99     keycode = (uint16_t)GPOINTER_TO_INT(g_datalist_get_data(&keysyms, str));
   101     if (keycode == 0) {
   102         //this key is not in the list yet, so make a new keycode for it
   103         g_datalist_set_data(&keysyms, str, GINT_TO_POINTER(++last_keycode));
   104         return last_keycode;
   105     } else {
   106         return keycode;
   107     }
   109 }
   111 static gchar *input_lirc_keysym_for_keycode( input_driver_t dev, uint16_t keycode )
   112 {
   113     //This won't work if you send in keycodes that haven't been fired by the callback
   114     //or looked up using resolve_keysym yet.  This shouldn't be a problem, since these
   115     //two functions are the only way to get a keycode in the first place.
   117     if (keycode <= last_keycode) {
   118         //reverse lookup
   119         keysym_by_keycode_result = 0;
   120         g_datalist_foreach(&keysyms, get_keysym_by_keycode, GINT_TO_POINTER(keycode));
   121         return g_strdup(g_quark_to_string(keysym_by_keycode_result));
   122     } else {
   123         return NULL;
   124     }
   125 }
   127 static void get_keysym_by_keycode(GQuark key_id, gpointer data, gpointer user_data)
   128 {
   129     if (data == user_data)
   130         keysym_by_keycode_result = key_id;
   131 }
   133 static gboolean input_lirc_callback( GIOChannel *source, GIOCondition condition, gpointer data )
   134 {
   135     int ret;
   136     char *code, *c;
   138     input_lirc_t lirc = (input_lirc_t)data;
   140     if (condition & G_IO_IN)
   141     {
   142         //loop through all queued commands
   143         while ((ret = lirc_nextcode(&code)) == 0 && code != NULL)
   144         {
   145             //code contains id, repeat count, and keysym separated by spaces
   146             gchar **code_split = g_strsplit(code, " ", 4);
   148             //eliminate repeats by only accepting the first instance of a keysym
   149             if (atoi(code_split[1]) == 0)
   150             {
   151                 input_event_keydown((input_driver_t)lirc, input_lirc_resolve_keysym((input_driver_t)lirc, code_split[2]), MAX_PRESSURE);
   152             }
   154             g_strfreev(code_split);
   155             free(code);
   156         }
   157     }
   158     return TRUE;
   159 }
   161 DEFINE_PLUGIN( PLUGIN_INPUT_DRIVER, "lirc", input_lirc_init );
.