Search
lxdream.org :: lxdream/src/drivers/input_lirc.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/input_lirc.c
changeset 1015:ad448bedc48a
next1024:c67f2d61ab97
author nkeynes
date Wed Jun 03 11:37:10 2009 +0000 (14 years ago)
permissions -rw-r--r--
last change Add missing svn:keywords property
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/drivers/input_lirc.c Wed Jun 03 11:37:10 2009 +0000
1.3 @@ -0,0 +1,156 @@
1.4 +/**
1.5 + * $Id: $
1.6 + *
1.7 + * LIRC input device support
1.8 + *
1.9 + * Copyright (c) 2009 wahrhaft
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#ifndef _GNU_SOURCE
1.23 +#define _GNU_SOURCE
1.24 +#endif
1.25 +#include <sys/types.h>
1.26 +#include <sys/ioctl.h>
1.27 +#include <errno.h>
1.28 +#include <stdio.h>
1.29 +#include <signal.h>
1.30 +#include <string.h>
1.31 +#include <stdlib.h>
1.32 +#include <unistd.h>
1.33 +#include <fcntl.h>
1.34 +#include <dirent.h>
1.35 +#include <ctype.h>
1.36 +
1.37 +#include <glib/giochannel.h>
1.38 +#include <glib.h>
1.39 +
1.40 +#include <lirc/lirc_client.h>
1.41 +
1.42 +#include "lxdream.h"
1.43 +#include "display.h"
1.44 +#include "maple/maple.h"
1.45 +#include "drivers/input_lirc.h"
1.46 +
1.47 +typedef struct input_lirc {
1.48 + struct input_driver driver;
1.49 + char name[5];
1.50 + int fd;
1.51 + GIOChannel *channel;
1.52 +} *input_lirc_t;
1.53 +
1.54 +#define MAX_KEYSYMS 256
1.55 +static char *keysyms[MAX_KEYSYMS];
1.56 +
1.57 +static uint16_t input_lirc_resolve_keysym( input_driver_t dev, const gchar *str );
1.58 +static gchar *input_lirc_keysym_for_keycode( input_driver_t dev, uint16_t keycode );
1.59 +static gboolean input_lirc_callback( GIOChannel *source, GIOCondition condition, gpointer data );
1.60 +
1.61 +input_driver_t system_lirc_driver;
1.62 +
1.63 +void input_lirc_create()
1.64 +{
1.65 + input_lirc_t system_lirc_driver = g_malloc0(sizeof(struct input_lirc));
1.66 + strcpy(system_lirc_driver->name, "LIRC");
1.67 + system_lirc_driver->driver.id = system_lirc_driver->name;
1.68 + system_lirc_driver->driver.resolve_keysym = input_lirc_resolve_keysym;
1.69 + system_lirc_driver->driver.get_keysym_for_keycode = input_lirc_keysym_for_keycode;
1.70 + system_lirc_driver->driver.destroy = NULL;
1.71 +
1.72 + system_lirc_driver->fd = lirc_init("lxdream", 1);
1.73 + if (system_lirc_driver->fd == -1) {
1.74 + WARN("Could not initialize LIRC. LIRC hotkeys will be disabled.");
1.75 + return;
1.76 + }
1.77 +
1.78 + system_lirc_driver->channel = g_io_channel_unix_new(system_lirc_driver->fd);
1.79 + g_io_channel_set_flags(system_lirc_driver->channel, G_IO_FLAG_IS_READABLE | G_IO_FLAG_NONBLOCK, NULL);
1.80 + g_io_add_watch(system_lirc_driver->channel, G_IO_IN|G_IO_ERR|G_IO_HUP, input_lirc_callback, system_lirc_driver);
1.81 + memset(keysyms, 0, MAX_KEYSYMS);
1.82 + input_register_device((input_driver_t)system_lirc_driver, MAX_KEYSYMS - 1);
1.83 + INFO("LIRC initialized");
1.84 +}
1.85 +
1.86 +void input_lirc_shutdown(void)
1.87 +{
1.88 + input_lirc_t lirc = (input_lirc_t)system_lirc_driver;
1.89 + g_io_channel_shutdown(lirc->channel, FALSE, NULL );
1.90 + g_io_channel_unref(lirc->channel);
1.91 + lirc_deinit();
1.92 + g_free(system_lirc_driver);
1.93 +}
1.94 +
1.95 +static uint16_t input_lirc_resolve_keysym( input_driver_t dev, const gchar *str )
1.96 +{
1.97 + //LIRC uses keysyms but no keycodes. To generate a keycode, we'll just make them up as we go.
1.98 + //As long as we store keysyms instead of keycodes in any config files, this should be fine.
1.99 + uint16_t i;
1.100 + for (i = 1; i < MAX_KEYSYMS && keysyms[i] != NULL; i++) {
1.101 + if (strcasecmp(str, keysyms[i]) == 0) {
1.102 + //keycode already exists
1.103 + return i;
1.104 + }
1.105 + }
1.106 +
1.107 + if (i < MAX_KEYSYMS) {
1.108 + //this key is not in the list yet, so make a new keycode for it
1.109 + keysyms[i] = g_strdup(str);
1.110 + return i;
1.111 + } else {
1.112 + //if your remote has more than 256 buttons, you may need to increase MAX_KEYSYMS
1.113 + ERROR("LIRC has too many keysyms!");
1.114 + return 0;
1.115 + }
1.116 +}
1.117 +
1.118 +static gchar *input_lirc_keysym_for_keycode( input_driver_t dev, uint16_t keycode )
1.119 +{
1.120 + //This won't work if you send in keycodes that haven't been fired by the callback
1.121 + //or looked up using resolve_keysym yet. This shouldn't be a problem, since these
1.122 + //two functions are the only way to get a keycode in the first place.
1.123 +
1.124 + if (keycode < MAX_KEYSYMS)
1.125 + return g_strdup(keysyms[keycode]);
1.126 + else
1.127 + return NULL;
1.128 +}
1.129 +
1.130 +gboolean input_lirc_callback( GIOChannel *source, GIOCondition condition, gpointer data )
1.131 +{
1.132 + int ret;
1.133 + char *code, *c;
1.134 + char keysym[256];
1.135 +
1.136 + input_lirc_t lirc = (input_lirc_t)data;
1.137 +
1.138 + if (condition & G_IO_IN)
1.139 + {
1.140 + //loop through all queued commands
1.141 + while ((ret = lirc_nextcode(&code)) == 0 && code != NULL)
1.142 + {
1.143 + INFO("LIRC code (%s)", code);
1.144 + //code contains id, repeat count, and keysym separated by spaces
1.145 + gchar **code_split = g_strsplit(code, " ", 4);
1.146 +
1.147 + //eliminate repeats by only accepting the first instance of a keysym
1.148 + if (atoi(code_split[1]) == 0)
1.149 + {
1.150 + input_event_keydown((input_driver_t)lirc, input_lirc_resolve_keysym((input_driver_t)lirc, code_split[2]), MAX_PRESSURE);
1.151 + }
1.152 +
1.153 + g_strfreev(code_split);
1.154 + free(code);
1.155 + }
1.156 + }
1.157 + return TRUE;
1.158 +}
1.159 +
.