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