linux 用户输入增强

https://ox-hugo.scripter.co/doc/dates/ ,hugo 可以设置更新时间。

更新我的 yasnippet 头,这确实是个隐藏我的博客的好方法,除非有人看我的源码。

用户输入增强是一个开发的,这篇文章我不想让别人看到,所以:

https://github.com/kaushalmodi/ox-hugo/issues/358 ,list 可以绐导出的 md 增加变量。

这篇文章仅知道路径的人才可见。这篇文章的路径是: https://guolongji.xyz/post/input-enhance

今天把代码写完。 并测试完成。明天还有活要干。

一期

实现功能代码

drivers >> input >> input-enhance.h

/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INPUT_ENHANCE_H
#define _INPUT_ENHANCE_H

#include <linux/ioctl.h>

// long enhance_state = 0; // 0 close; 1 open
struct enhance_param {
        int enhance_state;
        int encrypt_type;
        char *public_key;
};

#define CMD_IOC_MAGIC 'a'
#define CMD_IOC_0 _IOR(CMD_IOC_MAGIC, 0, struct enhance_param)
#define CMD_IOC_1 _IOW(CMD_IOC_MAGIC, 1, struct enhance_param)
#define CMD_IOC_2 _IOW(CMD_IOC_MAGIC, 2, struct enhance_param)

#endif /* _INPUT_ENHANCE_H */

drivers >> input >> input-enhance.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/scpi_protocol.h>
#include <asm/io.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>

#include "input-enhance.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("Driver to enhance input");

static int      majorNumber;
static struct   class*  enhance_module_class = NULL;
static struct   device* enhance_module_device = NULL;
#define DEVICE_NAME "input_enhance"
#define CLASS_NAME  "enhance_module"


struct enhance_param enhance_param_data = {
        0,
        0,
};
EXPORT_SYMBOL(enhance_param_data);


static long enhance_module_ioctl(struct file *, unsigned int, unsigned long);
static int __init enhance_init(void);
static void __exit enhance_exit(void);


static const struct file_operations enhance_module_fo = {
        .owner = THIS_MODULE,
        .unlocked_ioctl = enhance_module_ioctl,
};


static long enhance_module_ioctl(struct file *file,
                 unsigned int cmd,
                 unsigned long arg)
{

        switch(cmd){
        case CMD_IOC_0:
        {
                printk(KERN_INFO "[EnhanceModule:] Inner function (CMD_IOC_0) finished.\n");
                if (copy_to_user((void __user *)arg, &enhance_param_data, sizeof(struct enhance_param)))
                        return -EFAULT;
                break;
        }
        case CMD_IOC_1:
        {
                printk(KERN_INFO "[EnhanceModule:] Inner function (CMD_IOC_1) finished.\n");
                if (copy_from_user(&enhance_param_data, (void __user *)arg, sizeof(struct enhance_param)))
                        return -EFAULT;
                break;
        }
        default:
                printk(KERN_INFO "[EnhanceModule:] Unknown ioctl cmd!\n");
                return -EINVAL;
        }
        return 0;
}


static int __init enhance_init(void) {
        printk(KERN_INFO "[EnhanceModule:] Entering test module. \n");
        majorNumber = register_chrdev(0, DEVICE_NAME, &enhance_module_fo);
        if(majorNumber < 0){
                printk(KERN_INFO "[EnhanceModule:] Failed to register a major number. \n");
                return majorNumber;
        }
        printk(KERN_INFO "[EnhanceModule:] Successful to register a major number %d. \n", majorNumber);

        enhance_module_class = class_create(THIS_MODULE, CLASS_NAME);
        if(IS_ERR(enhance_module_class)) {
                unregister_chrdev(majorNumber, DEVICE_NAME);
                printk(KERN_INFO "[EnhanceModule:] Class device register failed!\n");
                return PTR_ERR(enhance_module_class);
        }
        printk(KERN_INFO "[EnhanceModule:] Class device register success!\n");

        enhance_module_device = device_create(enhance_module_class, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
        if (IS_ERR(enhance_module_device)) {
                class_destroy(enhance_module_class);
                unregister_chrdev(majorNumber, DEVICE_NAME);
                printk(KERN_ALERT "Failed to create the device\n");
                return PTR_ERR(enhance_module_device);
        }
        printk(KERN_INFO "[EnhanceModule:] Test module register successful. \n");
        return 0;
}


static void __exit enhance_exit(void)
{
        printk(KERN_INFO "[EnhanceModule:] Start to clean up module.\n");
        device_destroy(enhance_module_class, MKDEV(majorNumber, 0));
        class_destroy(enhance_module_class);
        unregister_chrdev(majorNumber, DEVICE_NAME);
        printk(KERN_INFO "[EnhanceModule:] Clean up successful. Bye.\n");

}

module_init(enhance_init);
module_exit(enhance_exit);

在drivers >> inoput >> input.c文件内添加内容

// ...
#include "input-poller.h"
//新增内容开始
#include "input-enhance.h"

extern struct enhance_param enhance_param_data;
//新增内容结尾

MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");


// ...

void input_event(struct input_dev *dev,
                 unsigned int type, unsigned int code, int value)
{
        unsigned long flags;
    //新增内容开始
        if (enhance_param_data.enhance_state == 1 && type == 0x01
                        && code != 272 && code != 273 && code != 274) {
                                code = code +1;
                        }
    //新增内容结尾

        if (is_event_supported(type, dev->evbit, EV_MAX)) {

                spin_lock_irqsave(&dev->event_lock, flags);
                input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
}

配置内核

将input_enhance.h和input_enhance.c文件拷贝至linux内核源码下的drivers>>input目录下,修改drivers>>input>>Makefile文件

#原先内容
input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o

#修改后的内容
input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o input-enhance.o

修改drivers>>input>>Kconfig文件,增加如下内容

config INPUT_ENHANCE
        bool "Input Enhance"
        default y
        help
                Say y herel if you want enhance input.
                To compile this driver as a module,choose M here: the module will be called input_enhance.

编译并替换内核

make
make modules
make install
make modules_install
reboot
#重启后,选择新编译的内核

编译libinput_enhance库

libinput_enhance.h

#ifndef _LIBINPUT_ENHANCE_H
#define _LIBINPUT_ENHANCE_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>

/**
 * @ingroup config
 *
 * Set kernel input enhance public key
 *
 * Todo
 */

/**
 * @ingroup config
 *
 * Get kernel input enhance state
 *
 * @return true if kernel input enhance is open
 */
bool libinput_enhance_is_enhance();

/**
 * @ingroup config
 *
 * Decrypt the reported code value
 *
 * @param keycode The encryted code
 * @return The decrypt code value
 */
unsigned short libinput_enhance_decode_keycode(unsigned short keycode);


/**
 * @ingroup config
 *
 * Set kernel start or stop enhance process
 *
 * @param start True is start, false is stop
 * @return 0 is success
 */
int libinput_enhance_start_or_stop_enhance(bool start);


/**
 * @ingroup config
 *
 * Set kernel encrypt data by specific algrithm
 *
 * @param type algrithm type
 * @param pkey optional public key for some algrithms
 * @return 0 is success
 */
int libinput_enhance_set_encrypt_info(int type, char * pkey);


#ifdef __cplusplus
}
#endif

#endif /* _LIBINPUT_ENHANCE_H */

libinput_enhance.c

#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdbool.h>

struct enhance_param {
        int enhance_state;
        int encrypt_type;
        char *public_key;
};

#define CMD_IOC_MAGIC	'a'
#define CMD_IOC_0	_IOR(CMD_IOC_MAGIC, 0, struct enhance_param)
#define CMD_IOC_1	_IOW(CMD_IOC_MAGIC, 1, struct enhance_param)

bool
libinput_enhance_is_enhance()
{
        int fd;
        struct enhance_param p;
        fd = open("/dev/input_enhance", O_RDWR);
        if (fd < 0)
                return false;
        int ret = ioctl(fd, CMD_IOC_0, &p);
        close(fd);
        if (p.enhance_state == 1)
                return true;
        return false;
}


unsigned short
libinput_enhance_decode_keycode(unsigned short keycode)
{
        return (keycode - 1);
}



int
libinput_enhance_start_or_stop_enhance(bool start)
{
        int fd;
        struct enhance_param p;
        if(start)
                p.enhance_state = 1;
        else
                p.enhance_state = 0;
        fd = open("/dev/input_enhance", O_RDWR);
        if (fd < 0)
                return 1;
        int ret = ioctl(fd, CMD_IOC_1, &p);
        close(fd);
        return ret;
}

int
libinput_enhance_set_encrypt_info(int type, char *pkey)
{
        int fd;
        struct enhance_param p;
        fd = open("/dev/input_enhance", O_RDWR);
        p.encrypt_type = type;
        p.public_key = pkey;
        if (fd < 0)
                return false;
        int ret = ioctl(fd, CMD_IOC_1, &p);
        close(fd);
        if (p.enhance_state == 1)
                return true;
        return false;
}

编译

#编译成动态库:
gcc -c libinput_enhance.c -o libinput_enhance.o -fPIC
gcc libinput_enhance.o -o libinput_enhance.so -shared

#编译成静态库:
ar -crv libinput_enhance.a libinput_enhance.o

编写测试用例

demo.c

#include "libinput_enhance.h"
#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <stdint.h>

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <linux/input.h>

#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <signal.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/types.h>

#ifndef input_event_sec
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#endif

#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x)  ((x)%BITS_PER_LONG)
#define BIT(x)  (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array)	((array[LONG(bit)] >> OFF(bit)) & 1)

#define DEV_INPUT_EVENT "/dev/input"
#define EVENT_DEV_NAME "event"

#ifndef EV_SYN
#define EV_SYN 0
#endif
#ifndef SYN_MAX
#define SYN_MAX 3
#define SYN_CNT (SYN_MAX + 1)
#endif
#ifndef SYN_MT_REPORT
#define SYN_MT_REPORT 2
#endif
#ifndef SYN_DROPPED
#define SYN_DROPPED 3
#endif

#define NAME_ELEMENT(element) [element] = #element

enum evtest_mode {
        MODE_CAPTURE,
        MODE_QUERY,
        MODE_VERSION,
};

static const struct query_mode {
        const char *name;
        int event_type;
        int max;
        int rq;
} query_modes[] = {
        { "EV_KEY", EV_KEY, KEY_MAX, EVIOCGKEY(KEY_MAX) },
        { "EV_LED", EV_LED, LED_MAX, EVIOCGLED(LED_MAX) },
        { "EV_SND", EV_SND, SND_MAX, EVIOCGSND(SND_MAX) },
        { "EV_SW",  EV_SW, SW_MAX, EVIOCGSW(SW_MAX) },
};

static int grab_flag = 0;
static char* progname;
static volatile sig_atomic_t stop = 0;

static void interrupt_handler(int sig)
{
        stop = 1;
}

/**
 * Look up an entry in the query_modes table by its textual name.
 *
 * @param mode The name of the entry to be found.
 *
 * @return The requested query_mode, or NULL if it could not be found.
 */
static const struct query_mode *find_query_mode_by_name(const char *name)
{
        int i;
        for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) {
                const struct query_mode *mode = &query_modes[i];
                if (strcmp(mode->name, name) == 0)
                        return mode;
        }
        return NULL;
}

/**
 * Look up an entry in the query_modes table by value.
 *
 * @param event_type The value of the entry to be found.
 *
 * @return The requested query_mode, or NULL if it could not be found.
 */
static const struct query_mode *find_query_mode_by_value(int event_type)
{
        int i;
        for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) {
                const struct query_mode *mode = &query_modes[i];
                if (mode->event_type == event_type)
                        return mode;
        }
        return NULL;
}

/**
 * Find a query_mode based on a string identifier. The string can either
 * be a numerical value (e.g. "5") or the name of the event type in question
 * (e.g. "EV_SW").
 *
 * @param query_mode The mode to search for
 *
 * @return The requested code's numerical value, or negative on error.
 */
static const struct query_mode *find_query_mode(const char *query_mode)
{
        if (isdigit(query_mode[0])) {
                unsigned long val;
                errno = 0;
                val = strtoul(query_mode, NULL, 0);
                if (errno)
                        return NULL;
                return find_query_mode_by_value(val);
        } else {
                return find_query_mode_by_name(query_mode);
        }
}

static const char * const events[EV_MAX + 1] = {
        [0 ... EV_MAX] = NULL,
        NAME_ELEMENT(EV_SYN),			NAME_ELEMENT(EV_KEY),
        NAME_ELEMENT(EV_REL),			NAME_ELEMENT(EV_ABS),
        NAME_ELEMENT(EV_MSC),			NAME_ELEMENT(EV_LED),
        NAME_ELEMENT(EV_SND),			NAME_ELEMENT(EV_REP),
        NAME_ELEMENT(EV_FF),			NAME_ELEMENT(EV_PWR),
        NAME_ELEMENT(EV_FF_STATUS),		NAME_ELEMENT(EV_SW),
};

static const int maxval[EV_MAX + 1] = {
        [0 ... EV_MAX] = -1,
        [EV_SYN] = SYN_MAX,
        [EV_KEY] = KEY_MAX,
        [EV_REL] = REL_MAX,
        [EV_ABS] = ABS_MAX,
        [EV_MSC] = MSC_MAX,
        [EV_SW] = SW_MAX,
        [EV_LED] = LED_MAX,
        [EV_SND] = SND_MAX,
        [EV_REP] = REP_MAX,
        [EV_FF] = FF_MAX,
        [EV_FF_STATUS] = FF_STATUS_MAX,
};


#ifdef INPUT_PROP_SEMI_MT
static const char * const props[INPUT_PROP_MAX + 1] = {
        [0 ... INPUT_PROP_MAX] = NULL,
        NAME_ELEMENT(INPUT_PROP_POINTER),
        NAME_ELEMENT(INPUT_PROP_DIRECT),
        NAME_ELEMENT(INPUT_PROP_BUTTONPAD),
        NAME_ELEMENT(INPUT_PROP_SEMI_MT),
#ifdef INPUT_PROP_TOPBUTTONPAD
        NAME_ELEMENT(INPUT_PROP_TOPBUTTONPAD),
#endif
#ifdef INPUT_PROP_POINTING_STICK
        NAME_ELEMENT(INPUT_PROP_POINTING_STICK),
#endif
#ifdef INPUT_PROP_ACCELEROMETER
        NAME_ELEMENT(INPUT_PROP_ACCELEROMETER),
#endif
};
#endif

static const char * const keys[KEY_MAX + 1] = {
        [0 ... KEY_MAX] = NULL,
        NAME_ELEMENT(KEY_RESERVED),		NAME_ELEMENT(KEY_ESC),
        NAME_ELEMENT(KEY_1),			NAME_ELEMENT(KEY_2),
        NAME_ELEMENT(KEY_3),			NAME_ELEMENT(KEY_4),
        NAME_ELEMENT(KEY_5),			NAME_ELEMENT(KEY_6),
        NAME_ELEMENT(KEY_7),			NAME_ELEMENT(KEY_8),
        NAME_ELEMENT(KEY_9),			NAME_ELEMENT(KEY_0),
        NAME_ELEMENT(KEY_MINUS),		NAME_ELEMENT(KEY_EQUAL),
        NAME_ELEMENT(KEY_BACKSPACE),		NAME_ELEMENT(KEY_TAB),
        NAME_ELEMENT(KEY_Q),			NAME_ELEMENT(KEY_W),
        NAME_ELEMENT(KEY_E),			NAME_ELEMENT(KEY_R),
        NAME_ELEMENT(KEY_T),			NAME_ELEMENT(KEY_Y),
        NAME_ELEMENT(KEY_U),			NAME_ELEMENT(KEY_I),
        NAME_ELEMENT(KEY_O),			NAME_ELEMENT(KEY_P),
        NAME_ELEMENT(KEY_LEFTBRACE),		NAME_ELEMENT(KEY_RIGHTBRACE),
        NAME_ELEMENT(KEY_ENTER),		NAME_ELEMENT(KEY_LEFTCTRL),
        NAME_ELEMENT(KEY_A),			NAME_ELEMENT(KEY_S),
        NAME_ELEMENT(KEY_D),			NAME_ELEMENT(KEY_F),
        NAME_ELEMENT(KEY_G),			NAME_ELEMENT(KEY_H),
        NAME_ELEMENT(KEY_J),			NAME_ELEMENT(KEY_K),
        NAME_ELEMENT(KEY_L),			NAME_ELEMENT(KEY_SEMICOLON),
        NAME_ELEMENT(KEY_APOSTROPHE),		NAME_ELEMENT(KEY_GRAVE),
        NAME_ELEMENT(KEY_LEFTSHIFT),		NAME_ELEMENT(KEY_BACKSLASH),
        NAME_ELEMENT(KEY_Z),			NAME_ELEMENT(KEY_X),
        NAME_ELEMENT(KEY_C),			NAME_ELEMENT(KEY_V),
        NAME_ELEMENT(KEY_B),			NAME_ELEMENT(KEY_N),
        NAME_ELEMENT(KEY_M),			NAME_ELEMENT(KEY_COMMA),
        NAME_ELEMENT(KEY_DOT),			NAME_ELEMENT(KEY_SLASH),
        NAME_ELEMENT(KEY_RIGHTSHIFT),		NAME_ELEMENT(KEY_KPASTERISK),
        NAME_ELEMENT(KEY_LEFTALT),		NAME_ELEMENT(KEY_SPACE),
        NAME_ELEMENT(KEY_CAPSLOCK),		NAME_ELEMENT(KEY_F1),
        NAME_ELEMENT(KEY_F2),			NAME_ELEMENT(KEY_F3),
        NAME_ELEMENT(KEY_F4),			NAME_ELEMENT(KEY_F5),
        NAME_ELEMENT(KEY_F6),			NAME_ELEMENT(KEY_F7),
        NAME_ELEMENT(KEY_F8),			NAME_ELEMENT(KEY_F9),
        NAME_ELEMENT(KEY_F10),			NAME_ELEMENT(KEY_NUMLOCK),
        NAME_ELEMENT(KEY_SCROLLLOCK),		NAME_ELEMENT(KEY_KP7),
        NAME_ELEMENT(KEY_KP8),			NAME_ELEMENT(KEY_KP9),
        NAME_ELEMENT(KEY_KPMINUS),		NAME_ELEMENT(KEY_KP4),
        NAME_ELEMENT(KEY_KP5),			NAME_ELEMENT(KEY_KP6),
        NAME_ELEMENT(KEY_KPPLUS),		NAME_ELEMENT(KEY_KP1),
        NAME_ELEMENT(KEY_KP2),			NAME_ELEMENT(KEY_KP3),
        NAME_ELEMENT(KEY_KP0),			NAME_ELEMENT(KEY_KPDOT),
        NAME_ELEMENT(KEY_ZENKAKUHANKAKU), 	NAME_ELEMENT(KEY_102ND),
        NAME_ELEMENT(KEY_F11),			NAME_ELEMENT(KEY_F12),
        NAME_ELEMENT(KEY_RO),			NAME_ELEMENT(KEY_KATAKANA),
        NAME_ELEMENT(KEY_HIRAGANA),		NAME_ELEMENT(KEY_HENKAN),
        NAME_ELEMENT(KEY_KATAKANAHIRAGANA),	NAME_ELEMENT(KEY_MUHENKAN),
        NAME_ELEMENT(KEY_KPJPCOMMA),		NAME_ELEMENT(KEY_KPENTER),
        NAME_ELEMENT(KEY_RIGHTCTRL),		NAME_ELEMENT(KEY_KPSLASH),
        NAME_ELEMENT(KEY_SYSRQ),		NAME_ELEMENT(KEY_RIGHTALT),
        NAME_ELEMENT(KEY_LINEFEED),		NAME_ELEMENT(KEY_HOME),
        NAME_ELEMENT(KEY_UP),			NAME_ELEMENT(KEY_PAGEUP),
        NAME_ELEMENT(KEY_LEFT),			NAME_ELEMENT(KEY_RIGHT),
        NAME_ELEMENT(KEY_END),			NAME_ELEMENT(KEY_DOWN),
        NAME_ELEMENT(KEY_PAGEDOWN),		NAME_ELEMENT(KEY_INSERT),
        NAME_ELEMENT(KEY_DELETE),		NAME_ELEMENT(KEY_MACRO),
        NAME_ELEMENT(KEY_MUTE),			NAME_ELEMENT(KEY_VOLUMEDOWN),
        NAME_ELEMENT(KEY_VOLUMEUP),		NAME_ELEMENT(KEY_POWER),
        NAME_ELEMENT(KEY_KPEQUAL),		NAME_ELEMENT(KEY_KPPLUSMINUS),
        NAME_ELEMENT(KEY_PAUSE),		NAME_ELEMENT(KEY_KPCOMMA),
        NAME_ELEMENT(KEY_HANGUEL),		NAME_ELEMENT(KEY_HANJA),
        NAME_ELEMENT(KEY_YEN),			NAME_ELEMENT(KEY_LEFTMETA),
        NAME_ELEMENT(KEY_RIGHTMETA),		NAME_ELEMENT(KEY_COMPOSE),
        NAME_ELEMENT(KEY_STOP),			NAME_ELEMENT(KEY_AGAIN),
        NAME_ELEMENT(KEY_PROPS),		NAME_ELEMENT(KEY_UNDO),
        NAME_ELEMENT(KEY_FRONT),		NAME_ELEMENT(KEY_COPY),
        NAME_ELEMENT(KEY_OPEN),			NAME_ELEMENT(KEY_PASTE),
        NAME_ELEMENT(KEY_FIND),			NAME_ELEMENT(KEY_CUT),
        NAME_ELEMENT(KEY_HELP),			NAME_ELEMENT(KEY_MENU),
        NAME_ELEMENT(KEY_CALC),			NAME_ELEMENT(KEY_SETUP),
        NAME_ELEMENT(KEY_SLEEP),		NAME_ELEMENT(KEY_WAKEUP),
        NAME_ELEMENT(KEY_FILE),			NAME_ELEMENT(KEY_SENDFILE),
        NAME_ELEMENT(KEY_DELETEFILE),		NAME_ELEMENT(KEY_XFER),
        NAME_ELEMENT(KEY_PROG1),		NAME_ELEMENT(KEY_PROG2),
        NAME_ELEMENT(KEY_WWW),			NAME_ELEMENT(KEY_MSDOS),
        NAME_ELEMENT(KEY_COFFEE),		NAME_ELEMENT(KEY_DIRECTION),
        NAME_ELEMENT(KEY_CYCLEWINDOWS),		NAME_ELEMENT(KEY_MAIL),
        NAME_ELEMENT(KEY_BOOKMARKS),		NAME_ELEMENT(KEY_COMPUTER),
        NAME_ELEMENT(KEY_BACK),			NAME_ELEMENT(KEY_FORWARD),
        NAME_ELEMENT(KEY_CLOSECD),		NAME_ELEMENT(KEY_EJECTCD),
        NAME_ELEMENT(KEY_EJECTCLOSECD),		NAME_ELEMENT(KEY_NEXTSONG),
        NAME_ELEMENT(KEY_PLAYPAUSE),		NAME_ELEMENT(KEY_PREVIOUSSONG),
        NAME_ELEMENT(KEY_STOPCD),		NAME_ELEMENT(KEY_RECORD),
        NAME_ELEMENT(KEY_REWIND),		NAME_ELEMENT(KEY_PHONE),
        NAME_ELEMENT(KEY_ISO),			NAME_ELEMENT(KEY_CONFIG),
        NAME_ELEMENT(KEY_HOMEPAGE),		NAME_ELEMENT(KEY_REFRESH),
        NAME_ELEMENT(KEY_EXIT),			NAME_ELEMENT(KEY_MOVE),
        NAME_ELEMENT(KEY_EDIT),			NAME_ELEMENT(KEY_SCROLLUP),
        NAME_ELEMENT(KEY_SCROLLDOWN),		NAME_ELEMENT(KEY_KPLEFTPAREN),
        NAME_ELEMENT(KEY_KPRIGHTPAREN), 	NAME_ELEMENT(KEY_F13),
        NAME_ELEMENT(KEY_F14),			NAME_ELEMENT(KEY_F15),
        NAME_ELEMENT(KEY_F16),			NAME_ELEMENT(KEY_F17),
        NAME_ELEMENT(KEY_F18),			NAME_ELEMENT(KEY_F19),
        NAME_ELEMENT(KEY_F20),			NAME_ELEMENT(KEY_F21),
        NAME_ELEMENT(KEY_F22),			NAME_ELEMENT(KEY_F23),
        NAME_ELEMENT(KEY_F24),			NAME_ELEMENT(KEY_PLAYCD),
        NAME_ELEMENT(KEY_PAUSECD),		NAME_ELEMENT(KEY_PROG3),
        NAME_ELEMENT(KEY_PROG4),		NAME_ELEMENT(KEY_SUSPEND),
        NAME_ELEMENT(KEY_CLOSE),		NAME_ELEMENT(KEY_PLAY),
        NAME_ELEMENT(KEY_FASTFORWARD),		NAME_ELEMENT(KEY_BASSBOOST),
        NAME_ELEMENT(KEY_PRINT),		NAME_ELEMENT(KEY_HP),
        NAME_ELEMENT(KEY_CAMERA),		NAME_ELEMENT(KEY_SOUND),
        NAME_ELEMENT(KEY_QUESTION),		NAME_ELEMENT(KEY_EMAIL),
        NAME_ELEMENT(KEY_CHAT),			NAME_ELEMENT(KEY_SEARCH),
        NAME_ELEMENT(KEY_CONNECT),		NAME_ELEMENT(KEY_FINANCE),
        NAME_ELEMENT(KEY_SPORT),		NAME_ELEMENT(KEY_SHOP),
        NAME_ELEMENT(KEY_ALTERASE),		NAME_ELEMENT(KEY_CANCEL),
        NAME_ELEMENT(KEY_BRIGHTNESSDOWN),	NAME_ELEMENT(KEY_BRIGHTNESSUP),
        NAME_ELEMENT(KEY_MEDIA),		NAME_ELEMENT(KEY_UNKNOWN),
        NAME_ELEMENT(KEY_OK),
        NAME_ELEMENT(KEY_SELECT),		NAME_ELEMENT(KEY_GOTO),
        NAME_ELEMENT(KEY_CLEAR),		NAME_ELEMENT(KEY_POWER2),
        NAME_ELEMENT(KEY_OPTION),		NAME_ELEMENT(KEY_INFO),
        NAME_ELEMENT(KEY_TIME),			NAME_ELEMENT(KEY_VENDOR),
        NAME_ELEMENT(KEY_ARCHIVE),		NAME_ELEMENT(KEY_PROGRAM),
        NAME_ELEMENT(KEY_CHANNEL),		NAME_ELEMENT(KEY_FAVORITES),
        NAME_ELEMENT(KEY_EPG),			NAME_ELEMENT(KEY_PVR),
        NAME_ELEMENT(KEY_MHP),			NAME_ELEMENT(KEY_LANGUAGE),
        NAME_ELEMENT(KEY_TITLE),		NAME_ELEMENT(KEY_SUBTITLE),
        NAME_ELEMENT(KEY_ANGLE),		NAME_ELEMENT(KEY_ZOOM),
        NAME_ELEMENT(KEY_MODE),			NAME_ELEMENT(KEY_KEYBOARD),
        NAME_ELEMENT(KEY_SCREEN),		NAME_ELEMENT(KEY_PC),
        NAME_ELEMENT(KEY_TV),			NAME_ELEMENT(KEY_TV2),
        NAME_ELEMENT(KEY_VCR),			NAME_ELEMENT(KEY_VCR2),
        NAME_ELEMENT(KEY_SAT),			NAME_ELEMENT(KEY_SAT2),
        NAME_ELEMENT(KEY_CD),			NAME_ELEMENT(KEY_TAPE),
        NAME_ELEMENT(KEY_RADIO),		NAME_ELEMENT(KEY_TUNER),
        NAME_ELEMENT(KEY_PLAYER),		NAME_ELEMENT(KEY_TEXT),
        NAME_ELEMENT(KEY_DVD),			NAME_ELEMENT(KEY_AUX),
        NAME_ELEMENT(KEY_MP3),			NAME_ELEMENT(KEY_AUDIO),
        NAME_ELEMENT(KEY_VIDEO),		NAME_ELEMENT(KEY_DIRECTORY),
        NAME_ELEMENT(KEY_LIST),			NAME_ELEMENT(KEY_MEMO),
        NAME_ELEMENT(KEY_CALENDAR),		NAME_ELEMENT(KEY_RED),
        NAME_ELEMENT(KEY_GREEN),		NAME_ELEMENT(KEY_YELLOW),
        NAME_ELEMENT(KEY_BLUE),			NAME_ELEMENT(KEY_CHANNELUP),
        NAME_ELEMENT(KEY_CHANNELDOWN),		NAME_ELEMENT(KEY_FIRST),
        NAME_ELEMENT(KEY_LAST),			NAME_ELEMENT(KEY_AB),
        NAME_ELEMENT(KEY_NEXT),			NAME_ELEMENT(KEY_RESTART),
        NAME_ELEMENT(KEY_SLOW),			NAME_ELEMENT(KEY_SHUFFLE),
        NAME_ELEMENT(KEY_BREAK),		NAME_ELEMENT(KEY_PREVIOUS),
        NAME_ELEMENT(KEY_DIGITS),		NAME_ELEMENT(KEY_TEEN),
        NAME_ELEMENT(KEY_TWEN),			NAME_ELEMENT(KEY_DEL_EOL),
        NAME_ELEMENT(KEY_DEL_EOS),		NAME_ELEMENT(KEY_INS_LINE),
        NAME_ELEMENT(KEY_DEL_LINE),
        NAME_ELEMENT(KEY_VIDEOPHONE),		NAME_ELEMENT(KEY_GAMES),
        NAME_ELEMENT(KEY_ZOOMIN),		NAME_ELEMENT(KEY_ZOOMOUT),
        NAME_ELEMENT(KEY_ZOOMRESET),		NAME_ELEMENT(KEY_WORDPROCESSOR),
        NAME_ELEMENT(KEY_EDITOR),		NAME_ELEMENT(KEY_SPREADSHEET),
        NAME_ELEMENT(KEY_GRAPHICSEDITOR), 	NAME_ELEMENT(KEY_PRESENTATION),
        NAME_ELEMENT(KEY_DATABASE),		NAME_ELEMENT(KEY_NEWS),
        NAME_ELEMENT(KEY_VOICEMAIL),		NAME_ELEMENT(KEY_ADDRESSBOOK),
        NAME_ELEMENT(KEY_MESSENGER),		NAME_ELEMENT(KEY_DISPLAYTOGGLE),
#ifdef KEY_SPELLCHECK
        NAME_ELEMENT(KEY_SPELLCHECK),
#endif
#ifdef KEY_LOGOFF
        NAME_ELEMENT(KEY_LOGOFF),
#endif
#ifdef KEY_DOLLAR
        NAME_ELEMENT(KEY_DOLLAR),
#endif
#ifdef KEY_EURO
        NAME_ELEMENT(KEY_EURO),
#endif
#ifdef KEY_FRAMEBACK
        NAME_ELEMENT(KEY_FRAMEBACK),
#endif
#ifdef KEY_FRAMEFORWARD
        NAME_ELEMENT(KEY_FRAMEFORWARD),
#endif
#ifdef KEY_CONTEXT_MENU
        NAME_ELEMENT(KEY_CONTEXT_MENU),
#endif
#ifdef KEY_MEDIA_REPEAT
        NAME_ELEMENT(KEY_MEDIA_REPEAT),
#endif
#ifdef KEY_10CHANNELSUP
        NAME_ELEMENT(KEY_10CHANNELSUP),
#endif
#ifdef KEY_10CHANNELSDOWN
        NAME_ELEMENT(KEY_10CHANNELSDOWN),
#endif
#ifdef KEY_IMAGES
        NAME_ELEMENT(KEY_IMAGES),
#endif
        NAME_ELEMENT(KEY_DEL_EOL),		NAME_ELEMENT(KEY_DEL_EOS),
        NAME_ELEMENT(KEY_INS_LINE),	 	NAME_ELEMENT(KEY_DEL_LINE),
        NAME_ELEMENT(KEY_FN),			NAME_ELEMENT(KEY_FN_ESC),
        NAME_ELEMENT(KEY_FN_F1),		NAME_ELEMENT(KEY_FN_F2),
        NAME_ELEMENT(KEY_FN_F3),		NAME_ELEMENT(KEY_FN_F4),
        NAME_ELEMENT(KEY_FN_F5),		NAME_ELEMENT(KEY_FN_F6),
        NAME_ELEMENT(KEY_FN_F7),		NAME_ELEMENT(KEY_FN_F8),
        NAME_ELEMENT(KEY_FN_F9),		NAME_ELEMENT(KEY_FN_F10),
        NAME_ELEMENT(KEY_FN_F11),		NAME_ELEMENT(KEY_FN_F12),
        NAME_ELEMENT(KEY_FN_1),			NAME_ELEMENT(KEY_FN_2),
        NAME_ELEMENT(KEY_FN_D),			NAME_ELEMENT(KEY_FN_E),
        NAME_ELEMENT(KEY_FN_F),			NAME_ELEMENT(KEY_FN_S),
        NAME_ELEMENT(KEY_FN_B),
        NAME_ELEMENT(KEY_BRL_DOT1),		NAME_ELEMENT(KEY_BRL_DOT2),
        NAME_ELEMENT(KEY_BRL_DOT3),		NAME_ELEMENT(KEY_BRL_DOT4),
        NAME_ELEMENT(KEY_BRL_DOT5),		NAME_ELEMENT(KEY_BRL_DOT6),
        NAME_ELEMENT(KEY_BRL_DOT7),		NAME_ELEMENT(KEY_BRL_DOT8),
        NAME_ELEMENT(KEY_BRL_DOT9),		NAME_ELEMENT(KEY_BRL_DOT10),
#ifdef KEY_NUMERIC_0
        NAME_ELEMENT(KEY_NUMERIC_0),		NAME_ELEMENT(KEY_NUMERIC_1),
        NAME_ELEMENT(KEY_NUMERIC_2),		NAME_ELEMENT(KEY_NUMERIC_3),
        NAME_ELEMENT(KEY_NUMERIC_4),		NAME_ELEMENT(KEY_NUMERIC_5),
        NAME_ELEMENT(KEY_NUMERIC_6),		NAME_ELEMENT(KEY_NUMERIC_7),
        NAME_ELEMENT(KEY_NUMERIC_8),		NAME_ELEMENT(KEY_NUMERIC_9),
        NAME_ELEMENT(KEY_NUMERIC_STAR),		NAME_ELEMENT(KEY_NUMERIC_POUND),
#endif
#ifdef KEY_NUMERIC_11
        NAME_ELEMENT(KEY_NUMERIC_11),		NAME_ELEMENT(KEY_NUMERIC_12),
#endif
        NAME_ELEMENT(KEY_BATTERY),
        NAME_ELEMENT(KEY_BLUETOOTH),		NAME_ELEMENT(KEY_BRIGHTNESS_CYCLE),
        NAME_ELEMENT(KEY_BRIGHTNESS_ZERO),
#ifdef KEY_DASHBOARD
        NAME_ELEMENT(KEY_DASHBOARD),
#endif
        NAME_ELEMENT(KEY_DISPLAY_OFF),		NAME_ELEMENT(KEY_DOCUMENTS),
        NAME_ELEMENT(KEY_FORWARDMAIL),		NAME_ELEMENT(KEY_NEW),
        NAME_ELEMENT(KEY_KBDILLUMDOWN),		NAME_ELEMENT(KEY_KBDILLUMUP),
        NAME_ELEMENT(KEY_KBDILLUMTOGGLE), 	NAME_ELEMENT(KEY_REDO),
        NAME_ELEMENT(KEY_REPLY),		NAME_ELEMENT(KEY_SAVE),
#ifdef KEY_SCALE
        NAME_ELEMENT(KEY_SCALE),
#endif
        NAME_ELEMENT(KEY_SEND),
        NAME_ELEMENT(KEY_SCREENLOCK),		NAME_ELEMENT(KEY_SWITCHVIDEOMODE),
#ifdef KEY_UWB
        NAME_ELEMENT(KEY_UWB),
#endif
#ifdef KEY_VIDEO_NEXT
        NAME_ELEMENT(KEY_VIDEO_NEXT),
#endif
#ifdef KEY_VIDEO_PREV
        NAME_ELEMENT(KEY_VIDEO_PREV),
#endif
#ifdef KEY_WIMAX
        NAME_ELEMENT(KEY_WIMAX),
#endif
#ifdef KEY_WLAN
        NAME_ELEMENT(KEY_WLAN),
#endif
#ifdef KEY_RFKILL
        NAME_ELEMENT(KEY_RFKILL),
#endif
#ifdef KEY_MICMUTE
        NAME_ELEMENT(KEY_MICMUTE),
#endif
#ifdef KEY_CAMERA_FOCUS
        NAME_ELEMENT(KEY_CAMERA_FOCUS),
#endif
#ifdef KEY_WPS_BUTTON
        NAME_ELEMENT(KEY_WPS_BUTTON),
#endif
#ifdef KEY_TOUCHPAD_TOGGLE
        NAME_ELEMENT(KEY_TOUCHPAD_TOGGLE),
        NAME_ELEMENT(KEY_TOUCHPAD_ON),
        NAME_ELEMENT(KEY_TOUCHPAD_OFF),
#endif
#ifdef KEY_CAMERA_ZOOMIN
        NAME_ELEMENT(KEY_CAMERA_ZOOMIN),	NAME_ELEMENT(KEY_CAMERA_ZOOMOUT),
        NAME_ELEMENT(KEY_CAMERA_UP),		NAME_ELEMENT(KEY_CAMERA_DOWN),
        NAME_ELEMENT(KEY_CAMERA_LEFT),		NAME_ELEMENT(KEY_CAMERA_RIGHT),
#endif
#ifdef KEY_ATTENDANT_ON
        NAME_ELEMENT(KEY_ATTENDANT_ON),		NAME_ELEMENT(KEY_ATTENDANT_OFF),
        NAME_ELEMENT(KEY_ATTENDANT_TOGGLE),	NAME_ELEMENT(KEY_LIGHTS_TOGGLE),
#endif

        NAME_ELEMENT(BTN_0),			NAME_ELEMENT(BTN_1),
        NAME_ELEMENT(BTN_2),			NAME_ELEMENT(BTN_3),
        NAME_ELEMENT(BTN_4),			NAME_ELEMENT(BTN_5),
        NAME_ELEMENT(BTN_6),			NAME_ELEMENT(BTN_7),
        NAME_ELEMENT(BTN_8),			NAME_ELEMENT(BTN_9),
        NAME_ELEMENT(BTN_LEFT),			NAME_ELEMENT(BTN_RIGHT),
        NAME_ELEMENT(BTN_MIDDLE),		NAME_ELEMENT(BTN_SIDE),
        NAME_ELEMENT(BTN_EXTRA),		NAME_ELEMENT(BTN_FORWARD),
        NAME_ELEMENT(BTN_BACK),			NAME_ELEMENT(BTN_TASK),
        NAME_ELEMENT(BTN_TRIGGER),		NAME_ELEMENT(BTN_THUMB),
        NAME_ELEMENT(BTN_THUMB2),		NAME_ELEMENT(BTN_TOP),
        NAME_ELEMENT(BTN_TOP2),			NAME_ELEMENT(BTN_PINKIE),
        NAME_ELEMENT(BTN_BASE),			NAME_ELEMENT(BTN_BASE2),
        NAME_ELEMENT(BTN_BASE3),		NAME_ELEMENT(BTN_BASE4),
        NAME_ELEMENT(BTN_BASE5),		NAME_ELEMENT(BTN_BASE6),
        NAME_ELEMENT(BTN_DEAD),			NAME_ELEMENT(BTN_C),
#ifdef BTN_SOUTH
        NAME_ELEMENT(BTN_SOUTH),		NAME_ELEMENT(BTN_EAST),
        NAME_ELEMENT(BTN_NORTH),		NAME_ELEMENT(BTN_WEST),
#else
        NAME_ELEMENT(BTN_A),			NAME_ELEMENT(BTN_B),
        NAME_ELEMENT(BTN_X),			NAME_ELEMENT(BTN_Y),
#endif
        NAME_ELEMENT(BTN_Z),			NAME_ELEMENT(BTN_TL),
        NAME_ELEMENT(BTN_TR),			NAME_ELEMENT(BTN_TL2),
        NAME_ELEMENT(BTN_TR2),			NAME_ELEMENT(BTN_SELECT),
        NAME_ELEMENT(BTN_START),		NAME_ELEMENT(BTN_MODE),
        NAME_ELEMENT(BTN_THUMBL),		NAME_ELEMENT(BTN_THUMBR),
        NAME_ELEMENT(BTN_TOOL_PEN),		NAME_ELEMENT(BTN_TOOL_RUBBER),
        NAME_ELEMENT(BTN_TOOL_BRUSH),		NAME_ELEMENT(BTN_TOOL_PENCIL),
        NAME_ELEMENT(BTN_TOOL_AIRBRUSH),	NAME_ELEMENT(BTN_TOOL_FINGER),
        NAME_ELEMENT(BTN_TOOL_MOUSE),		NAME_ELEMENT(BTN_TOOL_LENS),
#ifdef BTN_STYLUS3
        NAME_ELEMENT(BTN_STYLUS3),
#endif
        NAME_ELEMENT(BTN_TOUCH),		NAME_ELEMENT(BTN_STYLUS),
        NAME_ELEMENT(BTN_STYLUS2),		NAME_ELEMENT(BTN_TOOL_DOUBLETAP),
        NAME_ELEMENT(BTN_TOOL_TRIPLETAP),
#ifdef BTN_TOOL_QUADTAP
        NAME_ELEMENT(BTN_TOOL_QUADTAP),
#endif
        NAME_ELEMENT(BTN_GEAR_DOWN),
        NAME_ELEMENT(BTN_GEAR_UP),

#ifdef BTN_DPAD_UP
        NAME_ELEMENT(BTN_DPAD_UP),		NAME_ELEMENT(BTN_DPAD_DOWN),
        NAME_ELEMENT(BTN_DPAD_LEFT),		NAME_ELEMENT(BTN_DPAD_RIGHT),
#endif
#ifdef KEY_ALS_TOGGLE
        NAME_ELEMENT(KEY_ALS_TOGGLE),
#endif
#ifdef KEY_BUTTONCONFIG
        NAME_ELEMENT(KEY_BUTTONCONFIG),
#endif
#ifdef KEY_TASKMANAGER
        NAME_ELEMENT(KEY_TASKMANAGER),
#endif
#ifdef KEY_JOURNAL
        NAME_ELEMENT(KEY_JOURNAL),
#endif
#ifdef KEY_CONTROLPANEL
        NAME_ELEMENT(KEY_CONTROLPANEL),
#endif
#ifdef KEY_APPSELECT
        NAME_ELEMENT(KEY_APPSELECT),
#endif
#ifdef KEY_SCREENSAVER
        NAME_ELEMENT(KEY_SCREENSAVER),
#endif
#ifdef KEY_VOICECOMMAND
        NAME_ELEMENT(KEY_VOICECOMMAND),
#endif
#ifdef KEY_ASSISTANT
        NAME_ELEMENT(KEY_ASSISTANT),
#endif
#ifdef KEY_BRIGHTNESS_MIN
        NAME_ELEMENT(KEY_BRIGHTNESS_MIN),
#endif
#ifdef KEY_BRIGHTNESS_MAX
        NAME_ELEMENT(KEY_BRIGHTNESS_MAX),
#endif
#ifdef KEY_KBDINPUTASSIST_PREV
        NAME_ELEMENT(KEY_KBDINPUTASSIST_PREV),
#endif
#ifdef KEY_KBDINPUTASSIST_NEXT
        NAME_ELEMENT(KEY_KBDINPUTASSIST_NEXT),
#endif
#ifdef KEY_KBDINPUTASSIST_PREVGROUP
        NAME_ELEMENT(KEY_KBDINPUTASSIST_PREVGROUP),
#endif
#ifdef KEY_KBDINPUTASSIST_NEXTGROUP
        NAME_ELEMENT(KEY_KBDINPUTASSIST_NEXTGROUP),
#endif
#ifdef KEY_KBDINPUTASSIST_ACCEPT
        NAME_ELEMENT(KEY_KBDINPUTASSIST_ACCEPT),
#endif
#ifdef KEY_KBDINPUTASSIST_CANCEL
        NAME_ELEMENT(KEY_KBDINPUTASSIST_CANCEL),
#endif

#ifdef KEY_RIGHT_UP
        NAME_ELEMENT(KEY_RIGHT_UP),		NAME_ELEMENT(KEY_RIGHT_DOWN),
        NAME_ELEMENT(KEY_LEFT_UP),		NAME_ELEMENT(KEY_LEFT_DOWN),
#endif

#ifdef KEY_ROOT_MENU
        NAME_ELEMENT(KEY_ROOT_MENU),
        NAME_ELEMENT(KEY_MEDIA_TOP_MENU),
        NAME_ELEMENT(KEY_AUDIO_DESC),
        NAME_ELEMENT(KEY_3D_MODE),
        NAME_ELEMENT(KEY_NEXT_FAVORITE),
        NAME_ELEMENT(KEY_STOP_RECORD),
        NAME_ELEMENT(KEY_PAUSE_RECORD),
        NAME_ELEMENT(KEY_VOD),
        NAME_ELEMENT(KEY_UNMUTE),
        NAME_ELEMENT(KEY_FASTREVERSE),
        NAME_ELEMENT(KEY_SLOWREVERSE),
#endif

#ifdef KEY_DATA
        NAME_ELEMENT(KEY_DATA),
#endif

#ifdef KEY_ONSCREEN_KEYBOARD
        NAME_ELEMENT(KEY_ONSCREEN_KEYBOARD),
#endif

#ifdef BTN_TRIGGER_HAPPY
        NAME_ELEMENT(BTN_TRIGGER_HAPPY1),	NAME_ELEMENT(BTN_TRIGGER_HAPPY11),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY2),	NAME_ELEMENT(BTN_TRIGGER_HAPPY12),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY3),	NAME_ELEMENT(BTN_TRIGGER_HAPPY13),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY4),	NAME_ELEMENT(BTN_TRIGGER_HAPPY14),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY5),	NAME_ELEMENT(BTN_TRIGGER_HAPPY15),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY6),	NAME_ELEMENT(BTN_TRIGGER_HAPPY16),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY7),	NAME_ELEMENT(BTN_TRIGGER_HAPPY17),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY8),	NAME_ELEMENT(BTN_TRIGGER_HAPPY18),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY9),	NAME_ELEMENT(BTN_TRIGGER_HAPPY19),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY10),	NAME_ELEMENT(BTN_TRIGGER_HAPPY20),

        NAME_ELEMENT(BTN_TRIGGER_HAPPY21),	NAME_ELEMENT(BTN_TRIGGER_HAPPY31),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY22),	NAME_ELEMENT(BTN_TRIGGER_HAPPY32),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY23),	NAME_ELEMENT(BTN_TRIGGER_HAPPY33),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY24),	NAME_ELEMENT(BTN_TRIGGER_HAPPY34),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY25),	NAME_ELEMENT(BTN_TRIGGER_HAPPY35),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY26),	NAME_ELEMENT(BTN_TRIGGER_HAPPY36),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY27),	NAME_ELEMENT(BTN_TRIGGER_HAPPY37),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY28),	NAME_ELEMENT(BTN_TRIGGER_HAPPY38),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY29),	NAME_ELEMENT(BTN_TRIGGER_HAPPY39),
        NAME_ELEMENT(BTN_TRIGGER_HAPPY30),	NAME_ELEMENT(BTN_TRIGGER_HAPPY40),
#endif
#ifdef BTN_TOOL_QUINTTAP
        NAME_ELEMENT(BTN_TOOL_QUINTTAP),
#endif
};

static const char * const absval[6] = { "Value", "Min  ", "Max  ", "Fuzz ", "Flat ", "Resolution "};

static const char * const relatives[REL_MAX + 1] = {
        [0 ... REL_MAX] = NULL,
        NAME_ELEMENT(REL_X),			NAME_ELEMENT(REL_Y),
        NAME_ELEMENT(REL_Z),			NAME_ELEMENT(REL_RX),
        NAME_ELEMENT(REL_RY),			NAME_ELEMENT(REL_RZ),
        NAME_ELEMENT(REL_HWHEEL),
        NAME_ELEMENT(REL_DIAL),			NAME_ELEMENT(REL_WHEEL),
        NAME_ELEMENT(REL_MISC),
#ifdef REL_WHEEL_HI_RES
        NAME_ELEMENT(REL_WHEEL_HI_RES),
        NAME_ELEMENT(REL_HWHEEL_HI_RES),
#endif
};

static const char * const absolutes[ABS_MAX + 1] = {
        [0 ... ABS_MAX] = NULL,
        NAME_ELEMENT(ABS_X),			NAME_ELEMENT(ABS_Y),
        NAME_ELEMENT(ABS_Z),			NAME_ELEMENT(ABS_RX),
        NAME_ELEMENT(ABS_RY),			NAME_ELEMENT(ABS_RZ),
        NAME_ELEMENT(ABS_THROTTLE),		NAME_ELEMENT(ABS_RUDDER),
        NAME_ELEMENT(ABS_WHEEL),		NAME_ELEMENT(ABS_GAS),
        NAME_ELEMENT(ABS_BRAKE),		NAME_ELEMENT(ABS_HAT0X),
        NAME_ELEMENT(ABS_HAT0Y),		NAME_ELEMENT(ABS_HAT1X),
        NAME_ELEMENT(ABS_HAT1Y),		NAME_ELEMENT(ABS_HAT2X),
        NAME_ELEMENT(ABS_HAT2Y),		NAME_ELEMENT(ABS_HAT3X),
        NAME_ELEMENT(ABS_HAT3Y),		NAME_ELEMENT(ABS_PRESSURE),
        NAME_ELEMENT(ABS_DISTANCE),		NAME_ELEMENT(ABS_TILT_X),
        NAME_ELEMENT(ABS_TILT_Y),		NAME_ELEMENT(ABS_TOOL_WIDTH),
        NAME_ELEMENT(ABS_VOLUME),		NAME_ELEMENT(ABS_MISC),
#ifdef ABS_MT_BLOB_ID
        NAME_ELEMENT(ABS_MT_TOUCH_MAJOR),
        NAME_ELEMENT(ABS_MT_TOUCH_MINOR),
        NAME_ELEMENT(ABS_MT_WIDTH_MAJOR),
        NAME_ELEMENT(ABS_MT_WIDTH_MINOR),
        NAME_ELEMENT(ABS_MT_ORIENTATION),
        NAME_ELEMENT(ABS_MT_POSITION_X),
        NAME_ELEMENT(ABS_MT_POSITION_Y),
        NAME_ELEMENT(ABS_MT_TOOL_TYPE),
        NAME_ELEMENT(ABS_MT_BLOB_ID),
#endif
#ifdef ABS_MT_TRACKING_ID
        NAME_ELEMENT(ABS_MT_TRACKING_ID),
#endif
#ifdef ABS_MT_PRESSURE
        NAME_ELEMENT(ABS_MT_PRESSURE),
#endif
#ifdef ABS_MT_SLOT
        NAME_ELEMENT(ABS_MT_SLOT),
#endif
#ifdef ABS_MT_TOOL_X
        NAME_ELEMENT(ABS_MT_TOOL_X),
        NAME_ELEMENT(ABS_MT_TOOL_Y),
        NAME_ELEMENT(ABS_MT_DISTANCE),
#endif

};

static const char * const misc[MSC_MAX + 1] = {
        [ 0 ... MSC_MAX] = NULL,
        NAME_ELEMENT(MSC_SERIAL),		NAME_ELEMENT(MSC_PULSELED),
        NAME_ELEMENT(MSC_GESTURE),		NAME_ELEMENT(MSC_RAW),
        NAME_ELEMENT(MSC_SCAN),
#ifdef MSC_TIMESTAMP
        NAME_ELEMENT(MSC_TIMESTAMP),
#endif
};

static const char * const leds[LED_MAX + 1] = {
        [0 ... LED_MAX] = NULL,
        NAME_ELEMENT(LED_NUML),			NAME_ELEMENT(LED_CAPSL),
        NAME_ELEMENT(LED_SCROLLL),		NAME_ELEMENT(LED_COMPOSE),
        NAME_ELEMENT(LED_KANA),			NAME_ELEMENT(LED_SLEEP),
        NAME_ELEMENT(LED_SUSPEND),		NAME_ELEMENT(LED_MUTE),
        NAME_ELEMENT(LED_MISC),
#ifdef LED_MAIL
        NAME_ELEMENT(LED_MAIL),
#endif
#ifdef LED_CHARGING
        NAME_ELEMENT(LED_CHARGING),
#endif
};

static const char * const repeats[REP_MAX + 1] = {
        [0 ... REP_MAX] = NULL,
        NAME_ELEMENT(REP_DELAY),		NAME_ELEMENT(REP_PERIOD)
};

static const char * const sounds[SND_MAX + 1] = {
        [0 ... SND_MAX] = NULL,
        NAME_ELEMENT(SND_CLICK),		NAME_ELEMENT(SND_BELL),
        NAME_ELEMENT(SND_TONE)
};

static const char * const syns[SYN_MAX + 1] = {
        [0 ... SYN_MAX] = NULL,
        NAME_ELEMENT(SYN_REPORT),
        NAME_ELEMENT(SYN_CONFIG),
        NAME_ELEMENT(SYN_MT_REPORT),
        NAME_ELEMENT(SYN_DROPPED)
};

static const char * const switches[SW_MAX + 1] = {
        [0 ... SW_MAX] = NULL,
        NAME_ELEMENT(SW_LID),
        NAME_ELEMENT(SW_TABLET_MODE),
        NAME_ELEMENT(SW_HEADPHONE_INSERT),
#ifdef SW_RFKILL_ALL
        NAME_ELEMENT(SW_RFKILL_ALL),
#endif
#ifdef SW_MICROPHONE_INSERT
        NAME_ELEMENT(SW_MICROPHONE_INSERT),
#endif
#ifdef SW_DOCK
        NAME_ELEMENT(SW_DOCK),
#endif
#ifdef SW_LINEOUT_INSERT
        NAME_ELEMENT(SW_LINEOUT_INSERT),
#endif
#ifdef SW_JACK_PHYSICAL_INSERT
        NAME_ELEMENT(SW_JACK_PHYSICAL_INSERT),
#endif
#ifdef SW_VIDEOOUT_INSERT
        NAME_ELEMENT(SW_VIDEOOUT_INSERT),
#endif
#ifdef SW_CAMERA_LENS_COVER
        NAME_ELEMENT(SW_CAMERA_LENS_COVER),
        NAME_ELEMENT(SW_KEYPAD_SLIDE),
        NAME_ELEMENT(SW_FRONT_PROXIMITY),
#endif
#ifdef SW_ROTATE_LOCK
        NAME_ELEMENT(SW_ROTATE_LOCK),
#endif
#ifdef SW_LINEIN_INSERT
        NAME_ELEMENT(SW_LINEIN_INSERT),
#endif
#ifdef SW_MUTE_DEVICE
        NAME_ELEMENT(SW_MUTE_DEVICE),
#endif
#ifdef SW_PEN_INSERTED
        NAME_ELEMENT(SW_PEN_INSERTED),
#endif
};

static const char * const force[FF_MAX + 1] = {
        [0 ... FF_MAX] = NULL,
        NAME_ELEMENT(FF_RUMBLE),		NAME_ELEMENT(FF_PERIODIC),
        NAME_ELEMENT(FF_CONSTANT),		NAME_ELEMENT(FF_SPRING),
        NAME_ELEMENT(FF_FRICTION),		NAME_ELEMENT(FF_DAMPER),
        NAME_ELEMENT(FF_INERTIA),		NAME_ELEMENT(FF_RAMP),
        NAME_ELEMENT(FF_SQUARE),		NAME_ELEMENT(FF_TRIANGLE),
        NAME_ELEMENT(FF_SINE),			NAME_ELEMENT(FF_SAW_UP),
        NAME_ELEMENT(FF_SAW_DOWN),		NAME_ELEMENT(FF_CUSTOM),
        NAME_ELEMENT(FF_GAIN),			NAME_ELEMENT(FF_AUTOCENTER),
};

static const char * const forcestatus[FF_STATUS_MAX + 1] = {
        [0 ... FF_STATUS_MAX] = NULL,
        NAME_ELEMENT(FF_STATUS_STOPPED),	NAME_ELEMENT(FF_STATUS_PLAYING),
};

static const char * const * const names[EV_MAX + 1] = {
        [0 ... EV_MAX] = NULL,
        [EV_SYN] = syns,			[EV_KEY] = keys,
        [EV_REL] = relatives,			[EV_ABS] = absolutes,
        [EV_MSC] = misc,			[EV_LED] = leds,
        [EV_SND] = sounds,			[EV_REP] = repeats,
        [EV_SW] = switches,
        [EV_FF] = force,			[EV_FF_STATUS] = forcestatus,
};

/**
 * Convert a string to a specific key/snd/led/sw code. The string can either
 * be the name of the key in question (e.g. "SW_DOCK") or the numerical
 * value, either as decimal (e.g. "5") or as hex (e.g. "0x5").
 *
 * @param mode The mode being queried (key, snd, led, sw)
 * @param kstr The string to parse and convert
 *
 * @return The requested code's numerical value, or negative on error.
 */
static int get_keycode(const struct query_mode *query_mode, const char *kstr)
{
        if (isdigit(kstr[0])) {
                unsigned long val;
                errno = 0;
                val = strtoul(kstr, NULL, 0);
                if (errno) {
                        fprintf(stderr, "Could not interpret value %s\n", kstr);
                        return -1;
                }
                return (int) val;
        } else {
                const char * const *keynames = names[query_mode->event_type];
                int i;

                for (i = 0; i < query_mode->max; i++) {
                        const char *name = keynames[i];
                        if (name && strcmp(name, kstr) == 0)
                                return i;
                }

                return -1;
        }
}

/**
 * Filter for the AutoDevProbe scandir on /dev/input.
 *
 * @param dir The current directory entry provided by scandir.
 *
 * @return Non-zero if the given directory entry starts with "event", or zero
 * otherwise.
 */
static int is_event_device(const struct dirent *dir) {
        return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
}

/**
 * Scans all /dev/input/event*, display them and ask the user which one to
 * open.
 *
 * @return The event device file name of the device file selected. This
 * string is allocated and must be freed by the caller.
 */
static char* scan_devices(void)
{
        struct dirent **namelist;
        int i, ndev, devnum, match;
        char *filename;
        int max_device = 0;

        ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort);
        if (ndev <= 0)
                return NULL;

        fprintf(stderr, "Available devices:\n");

        for (i = 0; i < ndev; i++)
        {
                char fname[4096];
                int fd = -1;
                char name[256] = "???";

                snprintf(fname, sizeof(fname),
                         "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
                fd = open(fname, O_RDONLY);
                if (fd < 0)
                        continue;
                ioctl(fd, EVIOCGNAME(sizeof(name)), name);

                fprintf(stderr, "%s:	%s\n", fname, name);
                close(fd);

                match = sscanf(namelist[i]->d_name, "event%d", &devnum);
                if (match >= 1 && devnum > max_device)
                        max_device = devnum;

                free(namelist[i]);
        }

        fprintf(stderr, "Select the device event number [0-%d]: ", max_device);

        //match = scanf("%d", &devnum);

        //if (match < 1 || devnum > max_device || devnum < 0)
        //	return NULL;


        // force set value
        devnum = 1;

        if (asprintf(&filename, "%s/%s%d",
                     DEV_INPUT_EVENT, EVENT_DEV_NAME,
                     devnum) < 0)
                return NULL;

        return filename;
}

static int version(void)
{
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION "<version undefined>"
#endif
        printf("%s %s\n", progname, PACKAGE_VERSION);
        return EXIT_SUCCESS;
}


/**
 * Print usage information.
 */
static int usage(void)
{
        printf("USAGE:\n");
        printf(" Capture mode:\n");
        printf("   %s [--grab] /dev/input/eventX\n", progname);
        printf("     --grab  grab the device for exclusive access\n");
        printf("\n");
        printf(" Query mode: (check exit code)\n");
        printf("   %s --query /dev/input/eventX <type> <value>\n", progname);

        printf("\n");
        printf("<type> is one of: EV_KEY, EV_SW, EV_LED, EV_SND\n");
        printf("<value> can either be a numerical value, or the textual name of the\n");
        printf("key/switch/LED/sound being queried (e.g. SW_DOCK).\n");

        return EXIT_FAILURE;
}

/**
 * Print additional information for absolute axes (min/max, current value,
 * etc.).
 *
 * @param fd The file descriptor to the device.
 * @param axis The axis identifier (e.g. ABS_X).
 */
static void print_absdata(int fd, int axis)
{
        int abs[6] = {0};
        int k;

        ioctl(fd, EVIOCGABS(axis), abs);
        for (k = 0; k < 6; k++)
                if ((k < 3) || abs[k])
                        printf("      %s %6d\n", absval[k], abs[k]);
}

static void print_repdata(int fd)
{
        int i;
        unsigned int rep[2];

        ioctl(fd, EVIOCGREP, rep);

        for (i = 0; i <= REP_MAX; i++) {
                printf("    Repeat code %d (%s)\n", i, names[EV_REP] ? (names[EV_REP][i] ? names[EV_REP][i] : "?") : "?");
                printf("      Value %6d\n", rep[i]);
        }

}

static inline const char* typename(unsigned int type)
{
        return (type <= EV_MAX && events[type]) ? events[type] : "?";
}

static inline const char* codename(unsigned int type, unsigned int code)
{
        return (type <= EV_MAX && code <= maxval[type] && names[type] && names[type][code]) ? names[type][code] : "?";
}

#ifdef INPUT_PROP_SEMI_MT
static inline const char* propname(unsigned int prop)
{
        return (prop <= INPUT_PROP_MAX && props[prop]) ? props[prop] : "?";
}
#endif

static int get_state(int fd, unsigned int type, unsigned long *array, size_t size)
{
        int rc;

        switch(type) {
        case EV_LED:
                rc = ioctl(fd, EVIOCGLED(size), array);
                break;
        case EV_SND:
                rc = ioctl(fd, EVIOCGSND(size), array);
                break;
        case EV_SW:
                rc = ioctl(fd, EVIOCGSW(size), array);
                break;
        case EV_KEY:
                /* intentionally not printing the value for EV_KEY, let the
                 * repeat handle this */
        default:
                return 1;
        }
        if (rc == -1)
                return 1;

        return 0;
}

/**
 * Print static device information (no events). This information includes
 * version numbers, device name and all bits supported by this device.
 *
 * @param fd The file descriptor to the device.
 * @return 0 on success or 1 otherwise.
 */
static int print_device_info(int fd)
{
        unsigned int type, code;
        int version;
        unsigned short id[4];
        char name[256] = "Unknown";
        unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
        unsigned long state[KEY_CNT] = {0};
#ifdef INPUT_PROP_SEMI_MT
        unsigned int prop;
        unsigned long propbits[INPUT_PROP_MAX];
#endif
        int stateval;
        int have_state;

        if (ioctl(fd, EVIOCGVERSION, &version)) {
                perror("evtest: can't get version");
                return 1;
        }

        printf("Input driver version is %d.%d.%d\n",
                version >> 16, (version >> 8) & 0xff, version & 0xff);

        ioctl(fd, EVIOCGID, id);
        printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n",
                id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]);

        ioctl(fd, EVIOCGNAME(sizeof(name)), name);
        printf("Input device name: \"%s\"\n", name);

        memset(bit, 0, sizeof(bit));
        ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);
        printf("Supported events:\n");

        for (type = 0; type < EV_MAX; type++) {
                if (test_bit(type, bit[0]) && type != EV_REP) {
                        have_state = (get_state(fd, type, state, sizeof(state)) == 0);

                        printf("  Event type %d (%s)\n", type, typename(type));
                        if (type == EV_SYN) continue;
                        ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]);
                        for (code = 0; code < KEY_MAX; code++)
                                if (test_bit(code, bit[type])) {
                                        if (have_state) {
                                                stateval = test_bit(code, state);
                                                printf("    Event code %d (%s) state %d\n",
                                                       code, codename(type, code), stateval);
                                        } else {
                                                printf("    Event code %d (%s)\n", code, codename(type, code));
                                        }
                                        if (type == EV_ABS)
                                                print_absdata(fd, code);
                                }
                }
        }

        if (test_bit(EV_REP, bit[0])) {
                printf("Key repeat handling:\n");
                printf("  Repeat type %d (%s)\n", EV_REP, events[EV_REP] ?  events[EV_REP] : "?");
                print_repdata(fd);
        }
#ifdef INPUT_PROP_SEMI_MT
        memset(propbits, 0, sizeof(propbits));
        ioctl(fd, EVIOCGPROP(sizeof(propbits)), propbits);
        printf("Properties:\n");
        for (prop = 0; prop < INPUT_PROP_MAX; prop++) {
                if (test_bit(prop, propbits))
                        printf("  Property type %d (%s)\n", prop, propname(prop));
        }
#endif

        return 0;
}

/**
 * Print device events as they come in.
 *
 * @param fd The file descriptor to the device.
 * @return 0 on success or 1 otherwise.
 */
static int print_events(int fd)
{
        struct input_event ev[64];
        int i, rd;
        fd_set rdfs;

        FD_ZERO(&rdfs);
        FD_SET(fd, &rdfs);

        while (!stop) {
                select(fd + 1, &rdfs, NULL, NULL, NULL);
                if (stop)
                        break;
                rd = read(fd, ev, sizeof(ev));

                if (rd < (int) sizeof(struct input_event)) {
                        printf("expected %d bytes, got %d\n", (int) sizeof(struct input_event), rd);
                        perror("\nevtest: error reading");
                        return 1;
                }

                for (i = 0; i < rd / sizeof(struct input_event); i++) {
                        unsigned int type, code;

                        type = ev[i].type;
                        code = ev[i].code;

                        /* decode here */
                        code = libinput_enhance_decode_keycode(code);

                        printf("Event: time %ld.%06ld, ", ev[i].input_event_sec, ev[i].input_event_usec);

                        if (type == EV_SYN) {
                                if (code == SYN_MT_REPORT)
                                        printf("++++++++++++++ %s ++++++++++++\n", codename(type, code));
                                else if (code == SYN_DROPPED)
                                        printf(">>>>>>>>>>>>>> %s <<<<<<<<<<<<\n", codename(type, code));
                                else
                                        printf("-------------- %s ------------\n", codename(type, code));
                        } else {
                                printf("type %d (%s), code %d (%s), ",
                                        type, typename(type),
                                        code, codename(type, code));
                                if (type == EV_MSC && (code == MSC_RAW || code == MSC_SCAN))
                                        printf("value %02x\n", ev[i].value);
                                else
                                        printf("value %d\n", ev[i].value);
                        }
                }

        }

        ioctl(fd, EVIOCGRAB, (void*)0);
        return EXIT_SUCCESS;
}

/**
 * Grab and immediately ungrab the device.
 *
 * @param fd The file descriptor to the device.
 * @return 0 if the grab was successful, or 1 otherwise.
 */
static int test_grab(int fd, int grab_flag)
{
        int rc;

        rc = ioctl(fd, EVIOCGRAB, (void*)1);

        if (rc == 0 && !grab_flag)
                ioctl(fd, EVIOCGRAB, (void*)0);

        return rc;
}

/**
 * Enter capture mode. The requested event device will be monitored, and any
 * captured events will be decoded and printed on the console.
 *
 * @param device The device to monitor, or NULL if the user should be prompted.
 * @return 0 on success, non-zero on error.
 */
static int do_capture(const char *device, int grab_flag)
{
        int fd;
        char *filename = NULL;

        if (!device) {
                fprintf(stderr, "No device specified, trying to scan all of %s/%s*\n",
                        DEV_INPUT_EVENT, EVENT_DEV_NAME);

                if (getuid() != 0)
                        fprintf(stderr, "Not running as root, no devices may be available.\n");

                filename = scan_devices();
                if (!filename)
                        return usage();
        } else
                filename = strdup(device);

        if (!filename)
                return EXIT_FAILURE;

        if ((fd = open(filename, O_RDONLY)) < 0) {
                perror("evtest");
                if (errno == EACCES && getuid() != 0)
                        fprintf(stderr, "You do not have access to %s. Try "
                                        "running as root instead.\n",
                                        filename);
                goto error;
        }

        if (!isatty(fileno(stdout)))
                setbuf(stdout, NULL);

        if (print_device_info(fd))
                goto error;

        printf("Testing ... (interrupt to exit)\n");

        if (test_grab(fd, grab_flag))
        {
                printf("***********************************************\n");
                printf("  This device is grabbed by another process.\n");
                printf("  No events are available to evtest while the\n"
                       "  other grab is active.\n");
                printf("  In most cases, this is caused by an X driver,\n"
                       "  try VT-switching and re-run evtest again.\n");
                printf("  Run the following command to see processes with\n"
                       "  an open fd on this device\n"
                       " \"fuser -v %s\"\n", filename);
                printf("***********************************************\n");
        }

        if (grab_flag) {
                signal(SIGINT, interrupt_handler);
                signal(SIGTERM, interrupt_handler);
        }

        free(filename);

        return print_events(fd);

error:
        free(filename);
        return EXIT_FAILURE;
}

/**
 * Perform a one-shot state query on a specific device. The query can be of
 * any known mode, on any valid keycode.
 *
 * @param device Path to the evdev device node that should be queried.
 * @param query_mode The event type that is being queried (e.g. key, switch)
 * @param keycode The code of the key/switch/sound/LED to be queried
 * @return 0 if the state bit is unset, 10 if the state bit is set, 1 on error.
 */
static int query_device(const char *device, const struct query_mode *query_mode, int keycode)
{
        int fd;
        int r;
        unsigned long state[NBITS(query_mode->max)];

        fd = open(device, O_RDONLY);
        if (fd < 0) {
                perror("open");
                return EXIT_FAILURE;
        }
        memset(state, 0, sizeof(state));
        r = ioctl(fd, query_mode->rq, state);
        close(fd);

        if (r == -1) {
                perror("ioctl");
                return EXIT_FAILURE;
        }

        if (test_bit(keycode, state))
                return 10; /* different from EXIT_FAILURE */
        else
                return 0;
}

/**
 * Enter query mode. The requested event device will be queried for the state
 * of a particular switch/key/sound/LED.
 *
 * @param device The device to query.
 * @param mode The mode (event type) that is to be queried (snd, sw, key, led)
 * @param keycode The key code to query the state of.
 * @return 0 if the state bit is unset, 10 if the state bit is set.
 */
static int do_query(const char *device, const char *event_type, const char *keyname)
{
        const struct query_mode *query_mode;
        int keycode;

        if (!device) {
                fprintf(stderr, "Device argument is required for query.\n");
                return usage();
        }

        query_mode = find_query_mode(event_type);
        if (!query_mode) {
                fprintf(stderr, "Unrecognised event type: %s\n", event_type);
                return usage();
        }

        keycode = get_keycode(query_mode, keyname);
        if (keycode < 0) {
                fprintf(stderr, "Unrecognised key name: %s\n", keyname);
                return usage();
        } else if (keycode > query_mode->max) {
                fprintf(stderr, "Key %d is out of bounds.\n", keycode);
                return EXIT_FAILURE;
        }

        return query_device(device, query_mode, keycode);
}

static const struct option long_options[] = {
        { "grab", no_argument, &grab_flag, 1 },
        { "query", no_argument, NULL, MODE_QUERY },
        { "version", no_argument, NULL, MODE_VERSION },
        { 0, },
};

int main (int argc, char **argv)
{
        const char *device = NULL;
        const char *keyname;
        const char *event_type;
        enum evtest_mode mode = MODE_CAPTURE;

        progname = argv[0];

        char yorn;

        printf("open input enhance (Y/N)? ");
        scanf("%c",&yorn);
        if(yorn == 'Y' || yorn == 'y')
        {
                int ret = libinput_enhance_start_or_stop_enhance(true);
                if (ret) {
                        printf("ioctl error, ret=%d\n", ret);
                        return ret;
                }
        }
        else if (yorn == 'N' || yorn == 'n')
        {
                int ret = libinput_enhance_start_or_stop_enhance(false);
                if (ret) {
                        printf("ioctl error, ret=%d\n", ret);
                        return ret;
                }
        }
        else
        {
                puts("can only be: Y or N ");
        }

        while (1) {
                int option_index = 0;
                int c = getopt_long(argc, argv, "", long_options, &option_index);
                if (c == -1)
                        break;
                switch (c) {
                case 0:
                        break;
                case MODE_QUERY:
                        mode = c;
                        break;
                case MODE_VERSION:
                        return version();
                default:
                        return usage();
                }
        }

        if (optind < argc)
                device = argv[optind++];

        if (mode == MODE_CAPTURE)
                return do_capture(device, grab_flag);

        if ((argc - optind) < 2) {
                fprintf(stderr, "Query mode requires device, type and key parameters\n");
                return usage();
        }

        event_type = argv[optind++];
        keyname = argv[optind++];
        return do_query(device, event_type, keyname);
}

编译

gcc demo.c -o demo -L . -l input_enhance

查看效果

#运行程序
./demo
#输入y

#此时在任何输入端都可以看到输入的内容和显示的内容不一致。

退出

远程ssh到该机器上,使用kill杀死./demo程序
再次运行./demo,选择n

二期

开会讨论使用的算法。最后决定使用 XOR 算法。

之前预留的是 char * 类型的 key ,现在其实用 uint16_t 就行,结构体是要改的,可以把之前的 char *public_key; 保留下来,新增一个 uint16_t *xor_key; 这就行了,首先写一个测试用例。

#include <stdio.h>
#include <stdint.h>

void xor_encrypt_decrypt(uint16_t *data, uint16_t key) {
    *data ^= key;  // 对数据进行 XOR 操作
}

int main() {
    uint16_t data = 0xABCD;  // 要加密的数据
    uint16_t key = 0x1234;   // 密钥

    printf("Original data: 0x%04X\n", data);

    // 加密
    xor_encrypt_decrypt(&data, key);
    printf("Encrypted data: 0x%04X\n", data);

    // 解密
    xor_encrypt_decrypt(&data, key);
    printf("Decrypted data: 0x%04X\n", data);

    return 0;
}

demo 运行无误。

加密部分有一点点小思考,鼠标的左中右三个键是不变的,和之前一样,是的无需加密。解密的时候也要先判断是不是那三个键,同样,是的话,也不需要解密。

内核修改

内核的修改非常少:

diff --git a/drivers/input/input-enhance.c b/drivers/input/input-enhance.c
index a3416368679b..86b2708e3858 100644
--- a/drivers/input/input-enhance.c
+++ b/drivers/input/input-enhance.c
@@ -23,6 +23,7 @@ static struct   device* enhance_module_device = NULL;
 struct enhance_param enhance_param_data = {
        0,
        0,
+       0x1234, // default xor_key
 };
 EXPORT_SYMBOL(enhance_param_data);

diff --git a/drivers/input/input-enhance.h b/drivers/input/input-enhance.h
index de168472a4c2..9eec09478c91 100644
--- a/drivers/input/input-enhance.h
+++ b/drivers/input/input-enhance.h
@@ -8,6 +8,7 @@
 struct enhance_param {
        int enhance_state;
        int encrypt_type;
+       uint16_t xor_key;
        char *public_key;

 };
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ee82d94cc68e..3c0092f6d119 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -410,6 +410,10 @@ void input_handle_event(struct input_dev *dev,
        }
 }

+void xor_encrypt_decrypt(uint16_t *data, uint16_t key) {
+    *data ^= key;
+}
+
 /**
  * input_event() - report new input event
  * @dev: device that generated the event
@@ -434,7 +438,7 @@ void input_event(struct input_dev *dev,

        if (enhance_param_data.enhance_state == 1 && type == 0x01
                && code != 272 && code != 273 && code != 274) {
-               code = code +1;
+               xor_encrypt_decrypt((uint16_t *)&code, enhance_param_data.xor_key);
        }

        if (is_event_supported(type, dev->evbit, EV_MAX)) {

直接编译一下应该就可以了。

用户态库的修改

先想一想要改的地方有哪些?一是增加一个设置 xor_key 的函数。二是增加一个 xor 的解密函数。之前的函数都不要删。后续还有可能修改。那这块也非常地简单。

64,90d63
< /**
<  * @ingroup config
<  *
<  * Xor set key let kernel encrypt keycode
<  *
<  * @param type algrithm type
<  * @param pkey optional public key for some algrithms
<  * @return 0 is success
<  */
< int libinput_enhance_set_xor_key(uint16_t xor_key);
<
<
< /**
<  * @ingroup config
<  *
<  * Decrypt the reported code value with xor algrithm
<  *
<  * @param keycode The encryted code
<  * @return The decrypt code value
<  */
< // 注意,因为库不是写在 libinput 当中的,不好判断类型是否是 EV_KEY
< // 在是 EV_KEY 且 keycode 的值不是 272 273 274 才需要调用此函数解密
< // 目的是防止还没有被 treeland接管的其他应用鼠标的三个键混乱造成不必
< // 要的演示麻烦
< unsigned short libinput_enhance_xor_decode_keycode(unsigned short keycode);
14d13
< 	uint16_t xor_key;
22,23d20
< uint16_t global_xor_key=0x1234;
<
80,107d76
< }
<
< int
< libinput_enhance_set_xor_key(uint16_t xor_key)
< {
< 	int fd;
<         struct enhance_param p;
<         fd = open("/dev/input_enhance", O_RDWR);
<         p.xor_key = xor_key;
<         if (fd < 0)
<                 return 1;
<         int ret = ioctl(fd, CMD_IOC_1, &p);
<         close(fd);
< 	if (ret == 0)
< 		global_xor_key = xor_key;
<         return ret;
< }
<
< void xor_encrypt_decrypt(uint16_t *data) {
<     *data ^= global_xor_key;
< }
<
< unsigned short
< libinput_enhance_xor_decode_keycode(unsigned short keycode)
< {
< 	unsigned short retcode = keycode;
< 	xor_encrypt_decrypt(&retcode);
< 	ret retcode;

编译,测试。