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
file annotate diff log raw
nkeynes@1015
     1
/**
nkeynes@1075
     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
            //code contains id, repeat count, and keysym separated by spaces
nkeynes@1015
   146
            gchar **code_split = g_strsplit(code, " ", 4);
nkeynes@1050
   147
nkeynes@1015
   148
            //eliminate repeats by only accepting the first instance of a keysym
nkeynes@1015
   149
            if (atoi(code_split[1]) == 0)
nkeynes@1015
   150
            {
nkeynes@1015
   151
                input_event_keydown((input_driver_t)lirc, input_lirc_resolve_keysym((input_driver_t)lirc, code_split[2]), MAX_PRESSURE);
nkeynes@1015
   152
            }
nkeynes@1050
   153
nkeynes@1015
   154
            g_strfreev(code_split);
nkeynes@1015
   155
            free(code);
nkeynes@1015
   156
        }
nkeynes@1015
   157
    }
nkeynes@1015
   158
    return TRUE;
nkeynes@1015
   159
}
nkeynes@1015
   160
nkeynes@1024
   161
DEFINE_PLUGIN( PLUGIN_INPUT_DRIVER, "lirc", input_lirc_init );
.