/*
 * Copyright © 2015 Red Hat, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "config.h"

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <libudev.h>
#include <linux/hidraw.h>
#include <string.h>

#include "libratbag-hidraw.h"
#include "libratbag-private.h"

#ifndef KEY_SCREENSAVER
#define KEY_SCREENSAVER		0x245
#endif
#ifndef KEY_VOICECOMMAND
#define KEY_VOICECOMMAND	0x246
#endif

/* defined in include/linux.hid.h in the kernel, but not exported */
#ifndef HID_MAX_BUFFER_SIZE
#define HID_MAX_BUFFER_SIZE	4096		/* 4kb */
#endif

#define HID_REPORT_ID		0b10000100
#define HID_COLLECTION		0b10100000
#define HID_USAGE_PAGE		0b00000100
#define HID_USAGE		0b00001000

#define HID_PHYSICAL		0
#define HID_APPLICATION		1
#define HID_LOGICAL		2

#define HID_KEY_RESERVED			0x00	/* Reserved (no event indicated) */
#define HID_KEY_ERRORROLLOVER			0x01	/* ErrorRollOver */
#define HID_KEY_POSTFAIL			0x02	/* POSTFail */
#define HID_KEY_ERRORUNDEFINE			0x03	/* ErrorUndefine */
#define HID_KEY_A				0x04	/* a and A */
#define HID_KEY_B				0x05	/* b and B */
#define HID_KEY_C				0x06	/* c and C */
#define HID_KEY_D				0x07	/* d and D */
#define HID_KEY_E				0x08	/* e and E */
#define HID_KEY_F				0x09	/* f and F */
#define HID_KEY_G				0x0A	/* g and G */
#define HID_KEY_H				0x0B	/* h and H */
#define HID_KEY_I				0x0C	/* i and I */
#define HID_KEY_J				0x0D	/* j and J */
#define HID_KEY_K				0x0E	/* k and K */
#define HID_KEY_L				0x0F	/* l and L */
#define HID_KEY_M				0x10	/* m and M */
#define HID_KEY_N				0x11	/* n and N */
#define HID_KEY_O				0x12	/* o and O */
#define HID_KEY_P				0x13	/* p and P */
#define HID_KEY_Q				0x14	/* q and Q */
#define HID_KEY_R				0x15	/* r and R */
#define HID_KEY_S				0x16	/* s and S */
#define HID_KEY_T				0x17	/* t and T */
#define HID_KEY_U				0x18	/* u and U */
#define HID_KEY_V				0x19	/* v and V */
#define HID_KEY_W				0x1A	/* w and W */
#define HID_KEY_X				0x1B	/* x and X */
#define HID_KEY_Y				0x1C	/* y and Y */
#define HID_KEY_Z				0x1D	/* z and Z */
#define HID_KEY_1				0x1E	/* 1 and ! */
#define HID_KEY_2				0x1F	/* 2 and @ */
#define HID_KEY_3				0x20	/* 3 and # */
#define HID_KEY_4				0x21	/* 4 and $ */
#define HID_KEY_5				0x22	/* 5 and % */
#define HID_KEY_6				0x23	/* 6 and ^ */
#define HID_KEY_7				0x24	/* 7 and & */
#define HID_KEY_8				0x25	/* 8 and * */
#define HID_KEY_9				0x26	/* 9 and ( */
#define HID_KEY_0				0x27	/* 0 and ) */
#define HID_KEY_RETURN_ENTER			0x28	/* Return (ENTER) */
#define HID_KEY_ESCAPE				0x29	/* ESCAPE */
#define HID_KEY_DELETE_BACKSPACE		0x2A	/* DELETE (Backspace) */
#define HID_KEY_TAB				0x2B	/* Tab */
#define HID_KEY_SPACEBAR			0x2C	/* Spacebar */
#define HID_KEY_MINUS_AND_UNDERSCORE		0x2D	/* - and (underscore) */
#define HID_KEY_EQUAL_AND_PLUS			0x2E	/* = and + */
#define HID_KEY_CLOSE_BRACKET			0x2F	/* [ and { */
#define HID_KEY_OPEN_BRACKET			0x30	/* ] and } */
#define HID_KEY_BACK_SLASH_AND_PIPE		0x31	/* \ and | */
#define HID_KEY_NON_US_HASH_AND_TILDE		0x32	/* Non-US # and ~ */
#define HID_KEY_SEMICOLON_AND_COLON		0x33	/* ; and : */
#define HID_KEY_QUOTE_AND_DOUBLEQUOTE		0x34	/* ' and " */
#define HID_KEY_GRAVE_ACCENT_AND_TILDE		0x35	/* Grave Accent and Tilde */
#define HID_KEY_COMMA_AND_LESSER_THAN		0x36	/* Keyboard, and < */
#define HID_KEY_PERIOD_AND_GREATER_THAN		0x37	/* . and > */
#define HID_KEY_SLASH_AND_QUESTION_MARK		0x38	/* / and ? */
#define HID_KEY_CAPS_LOCK			0x39	/* Caps Lock */
#define HID_KEY_F1				0x3A	/* F1 */
#define HID_KEY_F2				0x3B	/* F2 */
#define HID_KEY_F3				0x3C	/* F3 */
#define HID_KEY_F4				0x3D	/* F4 */
#define HID_KEY_F5				0x3E	/* F5 */
#define HID_KEY_F6				0x3F	/* F6 */
#define HID_KEY_F7				0x40	/* F7 */
#define HID_KEY_F8				0x41	/* F8 */
#define HID_KEY_F9				0x42	/* F9 */
#define HID_KEY_F10				0x43	/* F10 */
#define HID_KEY_F11				0x44	/* F11 */
#define HID_KEY_F12				0x45	/* F12 */
#define HID_KEY_PRINTSCREEN			0x46	/* PrintScreen */
#define HID_KEY_SCROLL_LOCK			0x47	/* Scroll Lock */
#define HID_KEY_PAUSE				0x48	/* Pause */
#define HID_KEY_INSERT				0x49	/* Insert */
#define HID_KEY_HOME				0x4A	/* Home */
#define HID_KEY_PAGEUP				0x4B	/* PageUp */
#define HID_KEY_DELETE_FORWARD			0x4C	/* Delete Forward */
#define HID_KEY_END				0x4D	/* End */
#define HID_KEY_PAGEDOWN			0x4E	/* PageDown */
#define HID_KEY_RIGHTARROW			0x4F	/* RightArrow */
#define HID_KEY_LEFTARROW			0x50	/* LeftArrow */
#define HID_KEY_DOWNARROW			0x51	/* DownArrow */
#define HID_KEY_UPARROW				0x52	/* UpArrow */
#define HID_KEY_KEYPAD_NUM_LOCK_AND_CLEAR	0x53	/* Keypad Num Lock and Clear */
#define HID_KEY_KEYPAD_SLASH			0x54	/* Keypad / */
#define HID_KEY_KEYPAD_ASTERISK			0x55	/* Keypad * */
#define HID_KEY_KEYPAD_MINUS			0x56	/* Keypad - */
#define HID_KEY_KEYPAD_PLUS			0x57	/* Keypad + */
#define HID_KEY_KEYPAD_ENTER			0x58	/* Keypad ENTER */
#define HID_KEY_KEYPAD_1_AND_END		0x59	/* Keypad 1 and End */
#define HID_KEY_KEYPAD_2_AND_DOWN_ARROW		0x5A	/* Keypad 2 and Down Arrow */
#define HID_KEY_KEYPAD_3_AND_PAGEDN		0x5B	/* Keypad 3 and PageDn */
#define HID_KEY_KEYPAD_4_AND_LEFT_ARROW		0x5C	/* Keypad 4 and Left Arrow */
#define HID_KEY_KEYPAD_5			0x5D	/* Keypad 5 */
#define HID_KEY_KEYPAD_6_AND_RIGHT_ARROW	0x5E	/* Keypad 6 and Right Arrow */
#define HID_KEY_KEYPAD_7_AND_HOME		0x5F	/* Keypad 7 and Home */
#define HID_KEY_KEYPAD_8_AND_UP_ARROW		0x60	/* Keypad 8 and Up Arrow */
#define HID_KEY_KEYPAD_9_AND_PAGEUP		0x61	/* Keypad 9 and PageUp */
#define HID_KEY_KEYPAD_0_AND_INSERT		0x62	/* Keypad 0 and Insert */
#define HID_KEY_KEYPAD_PERIOD_AND_DELETE	0x63	/* Keypad . and Delete */
#define HID_KEY_NON_US_BACKSLASH_AND_PIPE	0x64	/* Non-US \ and | */
#define HID_KEY_APPLICATION			0x65	/* Application */
#define HID_KEY_POWER				0x66	/* Power */
#define HID_KEY_KEYPAD_EQUAL			0x67	/* Keypad = */
#define HID_KEY_F13				0x68	/* F13 */
#define HID_KEY_F14				0x69	/* F14 */
#define HID_KEY_F15				0x6A	/* F15 */
#define HID_KEY_F16				0x6B	/* F16 */
#define HID_KEY_F17				0x6C	/* F17 */
#define HID_KEY_F18				0x6D	/* F18 */
#define HID_KEY_F19				0x6E	/* F19 */
#define HID_KEY_F20				0x6F	/* F20 */
#define HID_KEY_F21				0x70	/* F21 */
#define HID_KEY_F22				0x71	/* F22 */
#define HID_KEY_F23				0x72	/* F23 */
#define HID_KEY_F24				0x73	/* F24 */
#define HID_KEY_EXECUTE				0x74	/* Execute */
#define HID_KEY_HELP				0x75	/* Help */
#define HID_KEY_MENU				0x76	/* Menu */
#define HID_KEY_SELECT				0x77	/* Select */
#define HID_KEY_STOP				0x78	/* Stop */
#define HID_KEY_AGAIN				0x79	/* Again */
#define HID_KEY_UNDO				0x7A	/* Undo */
#define HID_KEY_CUT				0x7B	/* Cut */
#define HID_KEY_COPY				0x7C	/* Copy */
#define HID_KEY_PASTE				0x7D	/* Paste */
#define HID_KEY_FIND				0x7E	/* Find */
#define HID_KEY_MUTE				0x7F	/* Mute */
#define HID_KEY_VOLUME_UP			0x80	/* Volume Up */
#define HID_KEY_VOLUME_DOWN			0x81	/* Volume Down */
#define HID_KEY_LOCKING_CAPS_LOCK		0x82	/* Locking Caps Lock */
#define HID_KEY_LOCKING_NUM_LOCK		0x83	/* Locking Num Lock */
#define HID_KEY_LOCKING_SCROLL_LOCK		0x84	/* Locking Scroll Lock */
#define HID_KEY_KEYPAD_COMMA			0x85	/* Keypad Comma */
#define HID_KEY_KEYPAD_EQUAL_SIGN		0x86	/* Keypad Equal Sign */
#define HID_KEY_KANJI1				0x87	/* Kanji1 */
#define HID_KEY_KANJI2				0x88	/* Kanji2 */
#define HID_KEY_KANJI3				0x89	/* Kanji3 */
#define HID_KEY_KANJI4				0x8A	/* Kanji4 */
#define HID_KEY_KANJI5				0x8B	/* Kanji5 */
#define HID_KEY_KANJI6				0x8C	/* Kanji6 */
#define HID_KEY_KANJI7				0x8D	/* Kanji7 */
#define HID_KEY_KANJI8				0x8E	/* Kanji8 */
#define HID_KEY_KANJI9				0x8F	/* Kanji9 */
#define HID_KEY_LANG1				0x90	/* LANG1 */
#define HID_KEY_LANG2				0x91	/* LANG2 */
#define HID_KEY_LANG3				0x92	/* LANG3 */
#define HID_KEY_LANG4				0x93	/* LANG4 */
#define HID_KEY_LANG5				0x94	/* LANG5 */
#define HID_KEY_LANG6				0x95	/* LANG6 */
#define HID_KEY_LANG7				0x96	/* LANG7 */
#define HID_KEY_LANG8				0x97	/* LANG8 */
#define HID_KEY_LANG9				0x98	/* LANG9 */
#define HID_KEY_ALTERNATE_ERASE			0x99	/* Alternate Erase */
#define HID_KEY_SYSREQ_ATTENTION		0x9A	/* SysReq/Attention */
#define HID_KEY_CANCEL				0x9B	/* Cancel */
#define HID_KEY_CLEAR				0x9C	/* Clear */
#define HID_KEY_PRIOR				0x9D	/* Prior */
#define HID_KEY_RETURN				0x9E	/* Return */
#define HID_KEY_SEPARATOR			0x9F	/* Separator */
#define HID_KEY_OUT				0xA0	/* Out */
#define HID_KEY_OPER				0xA1	/* Oper */
#define HID_KEY_CLEAR_AGAIN			0xA2	/* Clear/Again */
#define HID_KEY_CRSEL_PROPS			0xA3	/* CrSel/Props */
#define HID_KEY_EXSEL				0xA4	/* ExSel */
/* RESERVED					0xA5-DF	*/ /* Reserved */
#define HID_KEY_LEFTCONTROL			0xE0	/* LeftControl */
#define HID_KEY_LEFTSHIFT			0xE1	/* LeftShift */
#define HID_KEY_LEFTALT				0xE2	/* LeftAlt */
#define HID_KEY_LEFT_GUI			0xE3	/* Left GUI */
#define HID_KEY_RIGHTCONTROL			0xE4	/* RightControl */
#define HID_KEY_RIGHTSHIFT			0xE5	/* RightShift */
#define HID_KEY_RIGHTALT			0xE6	/* RightAlt */
#define HID_KEY_RIGHT_GUI			0xE7	/* Right GUI */

static const unsigned int hid_keyboard_mapping[] = {
	[HID_KEY_RESERVED			] = 0,
	[HID_KEY_ERRORROLLOVER			] = 0,
	[HID_KEY_POSTFAIL			] = 0,
	[HID_KEY_ERRORUNDEFINE			] = 0,
	[HID_KEY_A				] = KEY_A,
	[HID_KEY_B				] = KEY_B,
	[HID_KEY_C				] = KEY_C,
	[HID_KEY_D				] = KEY_D,
	[HID_KEY_E				] = KEY_E,
	[HID_KEY_F				] = KEY_F,
	[HID_KEY_G				] = KEY_G,
	[HID_KEY_H				] = KEY_H,
	[HID_KEY_I				] = KEY_I,
	[HID_KEY_J				] = KEY_J,
	[HID_KEY_K				] = KEY_K,
	[HID_KEY_L				] = KEY_L,
	[HID_KEY_M				] = KEY_M,
	[HID_KEY_N				] = KEY_N,
	[HID_KEY_O				] = KEY_O,
	[HID_KEY_P				] = KEY_P,
	[HID_KEY_Q				] = KEY_Q,
	[HID_KEY_R				] = KEY_R,
	[HID_KEY_S				] = KEY_S,
	[HID_KEY_T				] = KEY_T,
	[HID_KEY_U				] = KEY_U,
	[HID_KEY_V				] = KEY_V,
	[HID_KEY_W				] = KEY_W,
	[HID_KEY_X				] = KEY_X,
	[HID_KEY_Y				] = KEY_Y,
	[HID_KEY_Z				] = KEY_Z,
	[HID_KEY_1				] = KEY_1,
	[HID_KEY_2				] = KEY_2,
	[HID_KEY_3				] = KEY_3,
	[HID_KEY_4				] = KEY_4,
	[HID_KEY_5				] = KEY_5,
	[HID_KEY_6				] = KEY_6,
	[HID_KEY_7				] = KEY_7,
	[HID_KEY_8				] = KEY_8,
	[HID_KEY_9				] = KEY_9,
	[HID_KEY_0				] = KEY_0,
	[HID_KEY_RETURN_ENTER			] = KEY_ENTER,
	[HID_KEY_ESCAPE				] = KEY_ESC,
	[HID_KEY_DELETE_BACKSPACE		] = KEY_BACKSPACE,
	[HID_KEY_TAB				] = KEY_TAB,
	[HID_KEY_SPACEBAR			] = KEY_SPACE,
	[HID_KEY_MINUS_AND_UNDERSCORE		] = KEY_MINUS,
	[HID_KEY_EQUAL_AND_PLUS			] = KEY_EQUAL,
	[HID_KEY_CLOSE_BRACKET			] = KEY_LEFTBRACE,
	[HID_KEY_OPEN_BRACKET			] = KEY_RIGHTBRACE,
	[HID_KEY_BACK_SLASH_AND_PIPE		] = KEY_BACKSLASH,
	[HID_KEY_NON_US_HASH_AND_TILDE		] = KEY_BACKSLASH,
	[HID_KEY_SEMICOLON_AND_COLON		] = KEY_SEMICOLON,
	[HID_KEY_QUOTE_AND_DOUBLEQUOTE		] = KEY_APOSTROPHE,
	[HID_KEY_GRAVE_ACCENT_AND_TILDE		] = KEY_GRAVE,
	[HID_KEY_COMMA_AND_LESSER_THAN		] = KEY_COMMA,
	[HID_KEY_PERIOD_AND_GREATER_THAN	] = KEY_DOT,
	[HID_KEY_SLASH_AND_QUESTION_MARK	] = KEY_SLASH,
	[HID_KEY_CAPS_LOCK			] = KEY_CAPSLOCK,
	[HID_KEY_F1				] = KEY_F1,
	[HID_KEY_F2				] = KEY_F2,
	[HID_KEY_F3				] = KEY_F3,
	[HID_KEY_F4				] = KEY_F4,
	[HID_KEY_F5				] = KEY_F5,
	[HID_KEY_F6				] = KEY_F6,
	[HID_KEY_F7				] = KEY_F7,
	[HID_KEY_F8				] = KEY_F8,
	[HID_KEY_F9				] = KEY_F9,
	[HID_KEY_F10				] = KEY_F10,
	[HID_KEY_F11				] = KEY_F11,
	[HID_KEY_F12				] = KEY_F12,
	[HID_KEY_PRINTSCREEN			] = KEY_SYSRQ,
	[HID_KEY_SCROLL_LOCK			] = KEY_SCROLLLOCK,
	[HID_KEY_PAUSE				] = KEY_PAUSE,
	[HID_KEY_INSERT				] = KEY_INSERT,
	[HID_KEY_HOME				] = KEY_HOME,
	[HID_KEY_PAGEUP				] = KEY_PAGEUP,
	[HID_KEY_DELETE_FORWARD			] = KEY_DELETE,
	[HID_KEY_END				] = KEY_END,
	[HID_KEY_PAGEDOWN			] = KEY_PAGEDOWN,
	[HID_KEY_RIGHTARROW			] = KEY_RIGHT,
	[HID_KEY_LEFTARROW			] = KEY_LEFT,
	[HID_KEY_DOWNARROW			] = KEY_DOWN,
	[HID_KEY_UPARROW			] = KEY_UP,
	[HID_KEY_KEYPAD_NUM_LOCK_AND_CLEAR	] = KEY_NUMLOCK,
	[HID_KEY_KEYPAD_SLASH			] = KEY_KPSLASH,
	[HID_KEY_KEYPAD_ASTERISK		] = KEY_KPASTERISK,
	[HID_KEY_KEYPAD_MINUS			] = KEY_KPMINUS,
	[HID_KEY_KEYPAD_PLUS			] = KEY_KPPLUS,
	[HID_KEY_KEYPAD_ENTER			] = KEY_KPENTER,
	[HID_KEY_KEYPAD_1_AND_END		] = KEY_KP1,
	[HID_KEY_KEYPAD_2_AND_DOWN_ARROW	] = KEY_KP2,
	[HID_KEY_KEYPAD_3_AND_PAGEDN		] = KEY_KP3,
	[HID_KEY_KEYPAD_4_AND_LEFT_ARROW	] = KEY_KP4,
	[HID_KEY_KEYPAD_5			] = KEY_KP5,
	[HID_KEY_KEYPAD_6_AND_RIGHT_ARROW	] = KEY_KP6,
	[HID_KEY_KEYPAD_7_AND_HOME		] = KEY_KP7,
	[HID_KEY_KEYPAD_8_AND_UP_ARROW		] = KEY_KP8,
	[HID_KEY_KEYPAD_9_AND_PAGEUP		] = KEY_KP9,
	[HID_KEY_KEYPAD_0_AND_INSERT		] = KEY_KP0,
	[HID_KEY_KEYPAD_PERIOD_AND_DELETE	] = KEY_KPDOT,
	[HID_KEY_NON_US_BACKSLASH_AND_PIPE	] = KEY_102ND,
	[HID_KEY_APPLICATION			] = KEY_COMPOSE,
	[HID_KEY_POWER				] = KEY_POWER,
	[HID_KEY_KEYPAD_EQUAL			] = KEY_KPEQUAL,
	[HID_KEY_F13				] = KEY_F13,
	[HID_KEY_F14				] = KEY_F14,
	[HID_KEY_F15				] = KEY_F15,
	[HID_KEY_F16				] = KEY_F16,
	[HID_KEY_F17				] = KEY_F17,
	[HID_KEY_F18				] = KEY_F18,
	[HID_KEY_F19				] = KEY_F19,
	[HID_KEY_F20				] = KEY_F20,
	[HID_KEY_F21				] = KEY_F21,
	[HID_KEY_F22				] = KEY_F22,
	[HID_KEY_F23				] = KEY_F23,
	[HID_KEY_F24				] = KEY_F24,
	[HID_KEY_EXECUTE			] = 0,
	[HID_KEY_HELP				] = KEY_HELP,
	[HID_KEY_MENU				] = KEY_MENU,
	[HID_KEY_SELECT				] = KEY_SELECT,
	[HID_KEY_STOP				] = KEY_STOP,
	[HID_KEY_AGAIN				] = KEY_AGAIN,
	[HID_KEY_UNDO				] = KEY_UNDO,
	[HID_KEY_CUT				] = KEY_CUT,
	[HID_KEY_COPY				] = KEY_COPY,
	[HID_KEY_PASTE				] = KEY_PASTE,
	[HID_KEY_FIND				] = KEY_FIND,
	[HID_KEY_MUTE				] = KEY_MUTE,
	[HID_KEY_VOLUME_UP			] = KEY_VOLUMEUP,
	[HID_KEY_VOLUME_DOWN			] = KEY_VOLUMEDOWN,
	[HID_KEY_LOCKING_CAPS_LOCK		] = 0,
	[HID_KEY_LOCKING_NUM_LOCK		] = 0,
	[HID_KEY_LOCKING_SCROLL_LOCK		] = 0,
	[HID_KEY_KEYPAD_COMMA			] = KEY_KPCOMMA,
	[HID_KEY_KEYPAD_EQUAL_SIGN		] = KEY_KPEQUAL,
	[HID_KEY_KANJI1				] = 0,
	[HID_KEY_KANJI2				] = 0,
	[HID_KEY_KANJI3				] = 0,
	[HID_KEY_KANJI4				] = 0,
	[HID_KEY_KANJI5				] = 0,
	[HID_KEY_KANJI6				] = 0,
	[HID_KEY_KANJI7				] = 0,
	[HID_KEY_KANJI8				] = 0,
	[HID_KEY_KANJI9				] = 0,
	[HID_KEY_LANG1				] = 0,
	[HID_KEY_LANG2				] = 0,
	[HID_KEY_LANG3				] = 0,
	[HID_KEY_LANG4				] = 0,
	[HID_KEY_LANG5				] = 0,
	[HID_KEY_LANG6				] = 0,
	[HID_KEY_LANG7				] = 0,
	[HID_KEY_LANG8				] = 0,
	[HID_KEY_LANG9				] = 0,
	[HID_KEY_ALTERNATE_ERASE		] = 0,
	[HID_KEY_SYSREQ_ATTENTION		] = KEY_SYSRQ,
	[HID_KEY_CANCEL				] = KEY_CANCEL,
	[HID_KEY_CLEAR				] = KEY_CLEAR,
	[HID_KEY_PRIOR				] = 0,
	[HID_KEY_RETURN				] = 0,
	[HID_KEY_SEPARATOR			] = 0,
	[HID_KEY_OUT				] = 0,
	[HID_KEY_OPER				] = 0,
	[HID_KEY_CLEAR_AGAIN			] = 0,
	[HID_KEY_CRSEL_PROPS			] = 0,
	[HID_KEY_EXSEL				] = 0,
	[0xA5 ... 0xDF] = 0,
	[HID_KEY_LEFTCONTROL			] = KEY_LEFTCTRL,
	[HID_KEY_LEFTSHIFT			] = KEY_LEFTSHIFT,
	[HID_KEY_LEFTALT			] = KEY_LEFTALT,
	[HID_KEY_LEFT_GUI			] = KEY_LEFTMETA,
	[HID_KEY_RIGHTCONTROL			] = KEY_RIGHTCTRL,
	[HID_KEY_RIGHTSHIFT			] = KEY_RIGHTSHIFT,
	[HID_KEY_RIGHTALT			] = KEY_RIGHTALT,
	[HID_KEY_RIGHT_GUI			] = KEY_RIGHTMETA,
	[0xe8 ... 0xff] = 0,
};

#define HID_CC_CONSUMER_CONTROL				0x01
#define HID_CC_NUMERIC_KEY_PAD				0x02
#define HID_CC_PROGRAMMABLE_BUTTONS			0x03
#define HID_CC_MICROPHONE				0x04
#define HID_CC_HEADPHONE				0x05
#define HID_CC_GRAPHIC_EQUALIZER			0x06
#define HID_CC_PLUS_10					0x20
#define HID_CC_PLUS_100					0x21
#define HID_CC_AM_PM					0x22
#define HID_CC_POWER					0x30
#define HID_CC_RESET					0x31
#define HID_CC_SLEEP					0x32
#define HID_CC_SLEEP_AFTER				0x33
#define HID_CC_SLEEP_MODE				0x34
#define HID_CC_ILLUMINATION				0x35
#define HID_CC_FUNCTION_BUTTONS				0x36
#define HID_CC_MENU					0x40
#define HID_CC_MENU_PICK				0x41
#define HID_CC_MENU_UP					0x42
#define HID_CC_MENU_DOWN				0x43
#define HID_CC_MENU_LEFT				0x44
#define HID_CC_MENU_RIGHT				0x45
#define HID_CC_MENU_ESCAPE				0x46
#define HID_CC_MENU_VALUE_INCREASE			0x47
#define HID_CC_MENU_VALUE_DECREASE			0x48
#define HID_CC_DATA_ON_SCREEN				0x60
#define HID_CC_CLOSED_CAPTION				0x61
#define HID_CC_CLOSED_CAPTION_SELECT			0x62
#define HID_CC_VCR_TV					0x63
#define HID_CC_BROADCAST_MODE				0x64
#define HID_CC_SNAPSHOT					0x65
#define HID_CC_STILL					0x66
#define HID_CC_ASPECT					0x6D
#define HID_CC_3D_MODE_SELECT				0x6E
#define HID_CC_DISPLAY_BRIGHTNESS_INCREMENT		0x6F
#define HID_CC_DISPLAY_BRIGHTNESS_DECREMENT		0x70
#define HID_CC_DISPLAY_BRIGHTNESS			0x71
#define HID_CC_DISPLAY_BACKLIGHT_TOGGLE			0x72
#define HID_CC_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM	0x73
#define HID_CC_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM	0x74
#define HID_CC_DISPLAY_SET_AUTO_BRIGHTNESS		0x75
#define HID_CC_SELECTION				0x80
#define HID_CC_ASSIGN_SELECTION				0x81
#define HID_CC_MODE_STEP				0x82
#define HID_CC_RECALL_LAST				0x83
#define HID_CC_ENTER_CHANNEL				0x84
#define HID_CC_ORDER_MOVIE				0x85
#define HID_CC_CHANNEL					0x86
#define HID_CC_MEDIA_SELECTION				0x87
#define HID_CC_MEDIA_SELECT_COMPUTER			0x88
#define HID_CC_MEDIA_SELECT_TV				0x89
#define HID_CC_MEDIA_SELECT_WWW				0x8A
#define HID_CC_MEDIA_SELECT_DVD				0x8B
#define HID_CC_MEDIA_SELECT_TELEPHONE			0x8C
#define HID_CC_MEDIA_SELECT_PROGRAM_GUIDE		0x8D
#define HID_CC_MEDIA_SELECT_VIDEO_PHONE			0x8E
#define HID_CC_MEDIA_SELECT_GAMES			0x8F
#define HID_CC_MEDIA_SELECT_MESSAGES			0x90
#define HID_CC_MEDIA_SELECT_CD				0x91
#define HID_CC_MEDIA_SELECT_VCR				0x92
#define HID_CC_MEDIA_SELECT_TUNER			0x93
#define HID_CC_QUIT					0x94
#define HID_CC_HELP					0x95
#define HID_CC_MEDIA_SELECT_TAPE			0x96
#define HID_CC_MEDIA_SELECT_CABLE			0x97
#define HID_CC_MEDIA_SELECT_SATELLITE			0x98
#define HID_CC_MEDIA_SELECT_SECURITY			0x99
#define HID_CC_MEDIA_SELECT_HOME			0x9A
#define HID_CC_MEDIA_SELECT_CALL			0x9B
#define HID_CC_CHANNEL_INCREMENT			0x9C
#define HID_CC_CHANNEL_DECREMENT			0x9D
#define HID_CC_MEDIA_SELECT_SAP				0x9E
#define HID_CC_VCR_PLUS					0xA0
#define HID_CC_ONCE					0xA1
#define HID_CC_DAILY					0xA2
#define HID_CC_WEEKLY					0xA3
#define HID_CC_MONTHLY					0xA4
#define HID_CC_PLAY					0xB0
#define HID_CC_PAUSE					0xB1
#define HID_CC_RECORD					0xB2
#define HID_CC_FAST_FORWARD				0xB3
#define HID_CC_REWIND					0xB4
#define HID_CC_SCAN_NEXT_TRACK				0xB5
#define HID_CC_SCAN_PREVIOUS_TRACK			0xB6
#define HID_CC_STOP					0xB7
#define HID_CC_EJECT					0xB8
#define HID_CC_RANDOM_PLAY				0xB9
#define HID_CC_SELECT_DISC				0xBA
#define HID_CC_ENTER_DISC				0xBB
#define HID_CC_REPEAT					0xBC
#define HID_CC_TRACKING					0xBD
#define HID_CC_TRACK_NORMAL				0xBE
#define HID_CC_SLOW_TRACKING				0xBF
#define HID_CC_FRAME_FORWARD				0xC0
#define HID_CC_FRAME_BACK				0xC1
#define HID_CC_MARK					0xC2
#define HID_CC_CLEAR_MARK				0xC3
#define HID_CC_REPEAT_FROM_MARK				0xC4
#define HID_CC_RETURN_TO_MARK				0xC5
#define HID_CC_SEARCH_MARK_FORWARD			0xC6
#define HID_CC_SEARCH_MARK_BACKWARDS			0xC7
#define HID_CC_COUNTER_RESET				0xC8
#define HID_CC_SHOW_COUNTER				0xC9
#define HID_CC_TRACKING_INCREMENT			0xCA
#define HID_CC_TRACKING_DECREMENT			0xCB
#define HID_CC_STOP_EJECT				0xCC
#define HID_CC_PLAY_PAUSE				0xCD
#define HID_CC_PLAY_SKIP				0xCE
#define HID_CC_VOICE_COMMAND				0xCF
#define HID_CC_VOLUME					0xE0
#define HID_CC_BALANCE					0xE1
#define HID_CC_MUTE					0xE2
#define HID_CC_BASS					0xE3
#define HID_CC_TREBLE					0xE4
#define HID_CC_BASS_BOOST				0xE5
#define HID_CC_SURROUND_MODE				0xE6
#define HID_CC_LOUDNESS					0xE7
#define HID_CC_MPX					0xE8
#define HID_CC_VOLUME_UP				0xE9
#define HID_CC_VOLUME_DOWN				0xEA
#define HID_CC_SPEED_SELECT				0xF0
#define HID_CC_PLAYBACK_SPEED				0xF1
#define HID_CC_STANDARD_PLAY				0xF2
#define HID_CC_LONG_PLAY				0xF3
#define HID_CC_EXTENDED_PLAY				0xF4
#define HID_CC_SLOW					0xF5
#define HID_CC_FAN_ENABLE				0x100
#define HID_CC_FAN_SPEED				0x101
#define HID_CC_LIGHT_ENABLE				0x102
#define HID_CC_LIGHT_ILLUMINATION_LEVEL			0x103
#define HID_CC_CLIMATE_CONTROL_ENABLE			0x104
#define HID_CC_ROOM_TEMPERATURE				0x105
#define HID_CC_SECURITY_ENABLE				0x106
#define HID_CC_FIRE_ALARM				0x107
#define HID_CC_POLICE_ALARM				0x108
#define HID_CC_PROXIMITY				0x109
#define HID_CC_MOTION					0x10A
#define HID_CC_DURESS_ALARM				0x10B
#define HID_CC_HOLDUP_ALARM				0x10C
#define HID_CC_MEDICAL_ALARM				0x10D
#define HID_CC_BALANCE_RIGHT				0x150
#define HID_CC_BALANCE_LEFT				0x151
#define HID_CC_BASS_INCREMENT				0x152
#define HID_CC_BASS_DECREMENT				0x153
#define HID_CC_TREBLE_INCREMENT				0x154
#define HID_CC_TREBLE_DECREMENT				0x155
#define HID_CC_SPEAKER_SYSTEM				0x160
#define HID_CC_CHANNEL_LEFT				0x161
#define HID_CC_CHANNEL_RIGHT				0x162
#define HID_CC_CHANNEL_CENTER				0x163
#define HID_CC_CHANNEL_FRONT				0x164
#define HID_CC_CHANNEL_CENTER_FRONT			0x165
#define HID_CC_CHANNEL_SIDE				0x166
#define HID_CC_CHANNEL_SURROUND				0x167
#define HID_CC_CHANNEL_LOW_FREQ_ENHANCEMENT		0x168
#define HID_CC_CHANNEL_TOP				0x169
#define HID_CC_CHANNEL_UNKNOWN				0x16A
#define HID_CC_SUB_CHANNEL				0x170
#define HID_CC_SUB_CHANNEL_INCREMENT			0x171
#define HID_CC_SUB_CHANNEL_DECREMENT			0x172
#define HID_CC_ALTERNATE_AUDIO_INCREMENT		0x173
#define HID_CC_ALTERNATE_AUDIO_DECREMENT		0x174
#define HID_CC_APPLICATION_LAUNCH_BUTTONS		0x180
#define HID_CC_AL_LAUNCH_BUTTON_CONFIG_TOOL		0x181
#define HID_CC_AL_PROGRAMMABLE_BUTTON_CONFIG		0x182
#define HID_CC_AL_CONSUMER_CONTROL_CONFIG		0x183
#define HID_CC_AL_WORD_PROCESSOR			0x184
#define HID_CC_AL_TEXT_EDITOR				0x185
#define HID_CC_AL_SPREADSHEET				0x186
#define HID_CC_AL_GRAPHICS_EDITOR			0x187
#define HID_CC_AL_PRESENTATION_APP			0x188
#define HID_CC_AL_DATABASE_APP				0x189
#define HID_CC_AL_EMAIL_READER				0x18A
#define HID_CC_AL_NEWSREADER				0x18B
#define HID_CC_AL_VOICEMAIL				0x18C
#define HID_CC_AL_CONTACTS_ADDRESS_BOOK			0x18D
#define HID_CC_AL_CALENDAR_SCHEDULE			0x18E
#define HID_CC_AL_TASK_PROJECT_MANAGER			0x18F
#define HID_CC_AL_LOG_JOURNAL_TIMECARD			0x190
#define HID_CC_AL_CHECKBOOK_FINANCE			0x191
#define HID_CC_AL_CALCULATOR				0x192
#define HID_CC_AL_A_VCAPTURE_PLAYBACK			0x193
#define HID_CC_AL_LOCAL_MACHINE_BROWSER			0x194
#define HID_CC_AL_LAN_WANBROWSER			0x195
#define HID_CC_AL_INTERNET_BROWSER			0x196
#define HID_CC_AL_REMOTE_NETWORKING_ISPCONNECT		0x197
#define HID_CC_AL_NETWORK_CONFERENCE			0x198
#define HID_CC_AL_NETWORK_CHAT				0x199
#define HID_CC_AL_TELEPHONY_DIALER			0x19A
#define HID_CC_AL_LOGON					0x19B
#define HID_CC_AL_LOGOFF				0x19C
#define HID_CC_AL_LOGON_LOGOFF				0x19D
#define HID_CC_AL_TERMINAL_LOCK_SCREENSAVER		0x19E
#define HID_CC_AL_CONTROL_PANEL				0x19F
#define HID_CC_AL_COMMAND_LINE_PROCESSOR_RUN		0x1A0
#define HID_CC_AL_PROCESS_TASK_MANAGER			0x1A1
#define HID_CC_AL_SELECT_TASK_APPLICATION		0x1A2
#define HID_CC_AL_NEXT_TASK_APPLICATION			0x1A3
#define HID_CC_AL_PREVIOUS_TASK_APPLICATION		0x1A4
#define HID_CC_AL_PREEMPT_HALT_TASK_APPLICATION		0x1A5
#define HID_CC_AL_INTEGRATED_HELP_CENTER		0x1A6
#define HID_CC_AL_DOCUMENTS				0x1A7
#define HID_CC_AL_THESAURUS				0x1A8
#define HID_CC_AL_DICTIONARY				0x1A9
#define HID_CC_AL_DESKTOP				0x1AA
#define HID_CC_AL_SPELL_CHECK				0x1AB
#define HID_CC_AL_GRAMMAR_CHECK				0x1AC
#define HID_CC_AL_WIRELESS_STATUS			0x1AD
#define HID_CC_AL_KEYBOARD_LAYOUT			0x1AE
#define HID_CC_AL_VIRUS_PROTECTION			0x1AF
#define HID_CC_AL_ENCRYPTION				0x1B0
#define HID_CC_AL_SCREEN_SAVER				0x1B1
#define HID_CC_AL_ALARMS				0x1B2
#define HID_CC_AL_CLOCK					0x1B3
#define HID_CC_AL_FILE_BROWSER				0x1B4
#define HID_CC_AL_POWER_STATUS				0x1B5
#define HID_CC_AL_IMAGE_BROWSER				0x1B6
#define HID_CC_AL_AUDIO_BROWSER				0x1B7
#define HID_CC_AL_MOVIE_BROWSER				0x1B8
#define HID_CC_AL_DIGITAL_RIGHTS_MANAGER		0x1B9
#define HID_CC_AL_DIGITAL_WALLET			0x1BA
#define HID_CC_AL_INSTANT_MESSAGING			0x1BC
#define HID_CC_AL_OEMFEATURES_TIPS_TUTO_BROWSER		0x1BD
#define HID_CC_AL_OEMHELP				0x1BE
#define HID_CC_AL_ONLINE_COMMUNITY			0x1BF
#define HID_CC_AL_ENTERTAINMENT_CONTENT_BROWSER		0x1C0
#define HID_CC_AL_ONLINE_SHOPPING_BROWSER		0x1C1
#define HID_CC_AL_SMART_CARD_INFORMATION_HELP		0x1C2
#define HID_CC_AL_MARKET_MONITOR_FINANCE_BROWSER	0x1C3
#define HID_CC_AL_CUSTOMIZED_CORP_NEWS_BROWSER		0x1C4
#define HID_CC_AL_ONLINE_ACTIVITY_BROWSER		0x1C5
#define HID_CC_AL_RESEARCH_SEARCH_BROWSER		0x1C6
#define HID_CC_AL_AUDIO_PLAYER				0x1C7
#define HID_CC_GENERIC_GUIAPPLICATION_CONTROLS		0x200
#define HID_CC_AC_NEW					0x201
#define HID_CC_AC_OPEN					0x202
#define HID_CC_AC_CLOSE					0x203
#define HID_CC_AC_EXIT					0x204
#define HID_CC_AC_MAXIMIZE				0x205
#define HID_CC_AC_MINIMIZE				0x206
#define HID_CC_AC_SAVE					0x207
#define HID_CC_AC_PRINT					0x208
#define HID_CC_AC_PROPERTIES				0x209
#define HID_CC_AC_UNDO					0x21A
#define HID_CC_AC_COPY					0x21B
#define HID_CC_AC_CUT					0x21C
#define HID_CC_AC_PASTE					0x21D
#define HID_CC_AC_SELECT_ALL				0x21E
#define HID_CC_AC_FIND					0x21F
#define HID_CC_AC_FINDAND_REPLACE			0x220
#define HID_CC_AC_SEARCH				0x221
#define HID_CC_AC_GO_TO					0x222
#define HID_CC_AC_HOME					0x223
#define HID_CC_AC_BACK					0x224
#define HID_CC_AC_FORWARD				0x225
#define HID_CC_AC_STOP					0x226
#define HID_CC_AC_REFRESH				0x227
#define HID_CC_AC_PREVIOUS_LINK				0x228
#define HID_CC_AC_NEXT_LINK				0x229
#define HID_CC_AC_BOOKMARKS				0x22A
#define HID_CC_AC_HISTORY				0x22B
#define HID_CC_AC_SUBSCRIPTIONS				0x22C
#define HID_CC_AC_ZOOM_IN				0x22D
#define HID_CC_AC_ZOOM_OUT				0x22E
#define HID_CC_AC_ZOOM					0x22F
#define HID_CC_AC_FULL_SCREEN_VIEW			0x230
#define HID_CC_AC_NORMAL_VIEW				0x231
#define HID_CC_AC_VIEW_TOGGLE				0x232
#define HID_CC_AC_SCROLL_UP				0x233
#define HID_CC_AC_SCROLL_DOWN				0x234
#define HID_CC_AC_SCROLL				0x235
#define HID_CC_AC_PAN_LEFT				0x236
#define HID_CC_AC_PAN_RIGHT				0x237
#define HID_CC_AC_PAN					0x238
#define HID_CC_AC_NEW_WINDOW				0x239
#define HID_CC_AC_TILE_HORIZONTALLY			0x23A
#define HID_CC_AC_TILE_VERTICALLY			0x23B
#define HID_CC_AC_FORMAT				0x23C
#define HID_CC_AC_EDIT					0x23D
#define HID_CC_AC_BOLD					0x23E
#define HID_CC_AC_ITALICS				0x23F
#define HID_CC_AC_UNDERLINE				0x240
#define HID_CC_AC_STRIKETHROUGH				0x241
#define HID_CC_AC_SUBSCRIPT				0x242
#define HID_CC_AC_SUPERSCRIPT				0x243
#define HID_CC_AC_ALL_CAPS				0x244
#define HID_CC_AC_ROTATE				0x245
#define HID_CC_AC_RESIZE				0x246
#define HID_CC_AC_FLIPHORIZONTAL			0x247
#define HID_CC_AC_FLIP_VERTICAL				0x248
#define HID_CC_AC_MIRROR_HORIZONTAL			0x249
#define HID_CC_AC_MIRROR_VERTICAL			0x24A
#define HID_CC_AC_FONT_SELECT				0x24B
#define HID_CC_AC_FONT_COLOR				0x24C
#define HID_CC_AC_FONT_SIZE				0x24D
#define HID_CC_AC_JUSTIFY_LEFT				0x24E
#define HID_CC_AC_JUSTIFY_CENTER_H			0x24F
#define HID_CC_AC_JUSTIFY_RIGHT				0x250
#define HID_CC_AC_JUSTIFY_BLOCK_H			0x251
#define HID_CC_AC_JUSTIFY_TOP				0x252
#define HID_CC_AC_JUSTIFY_CENTER_V			0x253
#define HID_CC_AC_JUSTIFY_BOTTOM			0x254
#define HID_CC_AC_JUSTIFY_BLOCK_V			0x255
#define HID_CC_AC_INDENT_DECREASE			0x256
#define HID_CC_AC_INDENT_INCREASE			0x257
#define HID_CC_AC_NUMBERED_LIST				0x258
#define HID_CC_AC_RESTART_NUMBERING			0x259
#define HID_CC_AC_BULLETED_LIST				0x25A
#define HID_CC_AC_PROMOTE				0x25B
#define HID_CC_AC_DEMOTE				0x25C
#define HID_CC_AC_YES					0x25D
#define HID_CC_AC_NO					0x25E
#define HID_CC_AC_CANCEL				0x25F
#define HID_CC_AC_CATALOG				0x260
#define HID_CC_AC_BUY_CHECKOUT				0x261
#define HID_CC_AC_ADDTO_CART				0x262
#define HID_CC_AC_EXPAND				0x263
#define HID_CC_AC_EXPAND_ALL				0x264
#define HID_CC_AC_COLLAPSE				0x265
#define HID_CC_AC_COLLAPSE_ALL				0x266
#define HID_CC_AC_PRINT_PREVIEW				0x267
#define HID_CC_AC_PASTE_SPECIAL				0x268
#define HID_CC_AC_INSERT_MODE				0x269
#define HID_CC_AC_DELETE				0x26A
#define HID_CC_AC_LOCK					0x26B
#define HID_CC_AC_UNLOCK				0x26C
#define HID_CC_AC_PROTECT				0x26D
#define HID_CC_AC_UNPROTECT				0x26E
#define HID_CC_AC_ATTACH_COMMENT			0x26F
#define HID_CC_AC_DELETE_COMMENT			0x270
#define HID_CC_AC_VIEW_COMMENT				0x271
#define HID_CC_AC_SELECT_WORD				0x272
#define HID_CC_AC_SELECT_SENTENCE			0x273
#define HID_CC_AC_SELECT_PARAGRAPH			0x274
#define HID_CC_AC_SELECT_COLUMN				0x275
#define HID_CC_AC_SELECT_ROW				0x276
#define HID_CC_AC_SELECT_TABLE				0x277
#define HID_CC_AC_SELECT_OBJECT				0x278
#define HID_CC_AC_REDO_REPEAT				0x279
#define HID_CC_AC_SORT					0x27A
#define HID_CC_AC_SORT_ASCENDING			0x27B
#define HID_CC_AC_SORT_DESCENDING			0x27C
#define HID_CC_AC_FILTER				0x27D
#define HID_CC_AC_SET_CLOCK				0x27E
#define HID_CC_AC_VIEW_CLOCK				0x27F
#define HID_CC_AC_SELECT_TIME_ZONE			0x280
#define HID_CC_AC_EDIT_TIME_ZONES			0x281
#define HID_CC_AC_SET_ALARM				0x282
#define HID_CC_AC_CLEAR_ALARM				0x283
#define HID_CC_AC_SNOOZE_ALARM				0x284
#define HID_CC_AC_RESET_ALARM				0x285
#define HID_CC_AC_SYNCHRONIZE				0x286
#define HID_CC_AC_SEND_RECEIVE				0x287
#define HID_CC_AC_SEND_TO				0x288
#define HID_CC_AC_REPLY					0x289
#define HID_CC_AC_REPLY_ALL				0x28A
#define HID_CC_AC_FORWARD_MSG				0x28B
#define HID_CC_AC_SEND					0x28C
#define HID_CC_AC_ATTACH_FILE				0x28D
#define HID_CC_AC_UPLOAD				0x28E
#define HID_CC_AC_DOWNLOAD(SAVE_TARGET_AS)		0x28F
#define HID_CC_AC_SET_BORDERS				0x290
#define HID_CC_AC_INSERT_ROW				0x291
#define HID_CC_AC_INSERT_COLUMN				0x292
#define HID_CC_AC_INSERT_FILE				0x293
#define HID_CC_AC_INSERT_PICTURE			0x294
#define HID_CC_AC_INSERT_OBJECT				0x295
#define HID_CC_AC_INSERT_SYMBOL				0x296
#define HID_CC_AC_SAVEAND_CLOSE				0x297
#define HID_CC_AC_RENAME				0x298
#define HID_CC_AC_MERGE					0x299
#define HID_CC_AC_SPLIT					0x29A
#define HID_CC_AC_DISRIBUTE_HORIZONTALLY		0x29B
#define HID_CC_AC_DISTRIBUTE_VERTICALLY			0x29C

static const unsigned int hid_consumer_mapping[] = {
	[0x00] = 0,
	[0x07 ... 0x1F] = 0,
	[0x23 ... 0x2F] = 0,
	[0x37 ... 0x3F] = 0,
	[0x49 ... 0x5F] = 0,
	[0x67 ... 0x6C] = 0,
	[0x76 ... 0x7F] = 0,
	[0x9F ... 0x9F] = 0,
	[0xA5 ... 0xAF] = 0,
	[0xD0 ... 0xDF] = 0,
	[0xEB ... 0xEF] = 0,
	[0xF6 ... 0xFF] = 0,
	[0x10E ... 0x14F] = 0,
	[0x156 ... 0x15F] = 0,
	[0x16B ... 0x16F] = 0,
	[0x175 ... 0x17F] = 0,
	[0x1BB ... 0x1BB] = 0,
	[0x1C8 ... 0x1FF] = 0,
	[0x20A ... 0x219] = 0,
	[0x29D ... 0xFFF] = 0,
	[HID_CC_CONSUMER_CONTROL			] = 0,
	[HID_CC_NUMERIC_KEY_PAD				] = 0,
	[HID_CC_PROGRAMMABLE_BUTTONS			] = 0,
	[HID_CC_MICROPHONE				] = 0,
	[HID_CC_HEADPHONE				] = 0,
	[HID_CC_GRAPHIC_EQUALIZER			] = 0,
	[HID_CC_PLUS_10					] = 0,
	[HID_CC_PLUS_100				] = 0,
	[HID_CC_AM_PM					] = 0,
	[HID_CC_POWER					] = KEY_POWER,
	[HID_CC_RESET					] = 0,
	[HID_CC_SLEEP					] = KEY_SLEEP,
	[HID_CC_SLEEP_AFTER				] = 0,
	[HID_CC_SLEEP_MODE				] = 0,
	[HID_CC_ILLUMINATION				] = 0,
	[HID_CC_FUNCTION_BUTTONS			] = 0,
	[HID_CC_MENU					] = KEY_MENU,
	[HID_CC_MENU_PICK				] = 0,
	[HID_CC_MENU_UP					] = 0,
	[HID_CC_MENU_DOWN				] = 0,
	[HID_CC_MENU_LEFT				] = 0,
	[HID_CC_MENU_RIGHT				] = 0,
	[HID_CC_MENU_ESCAPE				] = 0,
	[HID_CC_MENU_VALUE_INCREASE			] = 0,
	[HID_CC_MENU_VALUE_DECREASE			] = 0,
	[HID_CC_DATA_ON_SCREEN				] = 0,
	[HID_CC_CLOSED_CAPTION				] = 0,
	[HID_CC_CLOSED_CAPTION_SELECT			] = 0,
	[HID_CC_VCR_TV					] = 0,
	[HID_CC_BROADCAST_MODE				] = 0,
	[HID_CC_SNAPSHOT				] = 0,
	[HID_CC_STILL					] = 0,
	[HID_CC_ASPECT					] = 0,
	[HID_CC_3D_MODE_SELECT				] = 0,
	[HID_CC_DISPLAY_BRIGHTNESS_INCREMENT		] = 0,
	[HID_CC_DISPLAY_BRIGHTNESS_DECREMENT		] = 0,
	[HID_CC_DISPLAY_BRIGHTNESS			] = 0,
	[HID_CC_DISPLAY_BACKLIGHT_TOGGLE		] = 0,
	[HID_CC_DISPLAY_SET_BRIGHTNESS_TO_MINIMUM	] = 0,
	[HID_CC_DISPLAY_SET_BRIGHTNESS_TO_MAXIMUM	] = 0,
	[HID_CC_DISPLAY_SET_AUTO_BRIGHTNESS		] = 0,
	[HID_CC_SELECTION				] = 0,
	[HID_CC_ASSIGN_SELECTION			] = 0,
	[HID_CC_MODE_STEP				] = 0,
	[HID_CC_RECALL_LAST				] = 0,
	[HID_CC_ENTER_CHANNEL				] = 0,
	[HID_CC_ORDER_MOVIE				] = 0,
	[HID_CC_CHANNEL					] = 0,
	[HID_CC_MEDIA_SELECTION				] = 0,
	[HID_CC_MEDIA_SELECT_COMPUTER			] = 0,
	[HID_CC_MEDIA_SELECT_TV				] = 0,
	[HID_CC_MEDIA_SELECT_WWW			] = 0,
	[HID_CC_MEDIA_SELECT_DVD			] = 0,
	[HID_CC_MEDIA_SELECT_TELEPHONE			] = 0,
	[HID_CC_MEDIA_SELECT_PROGRAM_GUIDE		] = 0,
	[HID_CC_MEDIA_SELECT_VIDEO_PHONE		] = 0,
	[HID_CC_MEDIA_SELECT_GAMES			] = 0,
	[HID_CC_MEDIA_SELECT_MESSAGES			] = 0,
	[HID_CC_MEDIA_SELECT_CD				] = 0,
	[HID_CC_MEDIA_SELECT_VCR			] = 0,
	[HID_CC_MEDIA_SELECT_TUNER			] = 0,
	[HID_CC_QUIT					] = 0,
	[HID_CC_HELP					] = KEY_HELP,
	[HID_CC_MEDIA_SELECT_TAPE			] = 0,
	[HID_CC_MEDIA_SELECT_CABLE			] = 0,
	[HID_CC_MEDIA_SELECT_SATELLITE			] = 0,
	[HID_CC_MEDIA_SELECT_SECURITY			] = 0,
	[HID_CC_MEDIA_SELECT_HOME			] = 0,
	[HID_CC_MEDIA_SELECT_CALL			] = 0,
	[HID_CC_CHANNEL_INCREMENT			] = 0,
	[HID_CC_CHANNEL_DECREMENT			] = 0,
	[HID_CC_MEDIA_SELECT_SAP			] = 0,
	[HID_CC_VCR_PLUS				] = 0,
	[HID_CC_ONCE					] = 0,
	[HID_CC_DAILY					] = 0,
	[HID_CC_WEEKLY					] = 0,
	[HID_CC_MONTHLY					] = 0,
	[HID_CC_PLAY					] = KEY_PLAY,
	[HID_CC_PAUSE					] = KEY_PAUSE,
	[HID_CC_RECORD					] = KEY_RECORD,
	[HID_CC_FAST_FORWARD				] = KEY_FASTFORWARD,
	[HID_CC_REWIND					] = KEY_REWIND,
	[HID_CC_SCAN_NEXT_TRACK				] = KEY_NEXTSONG,
	[HID_CC_SCAN_PREVIOUS_TRACK			] = KEY_PREVIOUSSONG,
	[HID_CC_STOP					] = KEY_STOP,
	[HID_CC_EJECT					] = KEY_EJECTCD,
	[HID_CC_RANDOM_PLAY				] = 0,
	[HID_CC_SELECT_DISC				] = 0,
	[HID_CC_ENTER_DISC				] = 0,
	[HID_CC_REPEAT					] = 0,
	[HID_CC_TRACKING				] = 0,
	[HID_CC_TRACK_NORMAL				] = 0,
	[HID_CC_SLOW_TRACKING				] = 0,
	[HID_CC_FRAME_FORWARD				] = 0,
	[HID_CC_FRAME_BACK				] = 0,
	[HID_CC_MARK					] = 0,
	[HID_CC_CLEAR_MARK				] = 0,
	[HID_CC_REPEAT_FROM_MARK			] = 0,
	[HID_CC_RETURN_TO_MARK				] = 0,
	[HID_CC_SEARCH_MARK_FORWARD			] = 0,
	[HID_CC_SEARCH_MARK_BACKWARDS			] = 0,
	[HID_CC_COUNTER_RESET				] = 0,
	[HID_CC_SHOW_COUNTER				] = 0,
	[HID_CC_TRACKING_INCREMENT			] = 0,
	[HID_CC_TRACKING_DECREMENT			] = 0,
	[HID_CC_STOP_EJECT				] = 0,
	[HID_CC_PLAY_PAUSE				] = KEY_PLAYPAUSE,
	[HID_CC_PLAY_SKIP				] = 0,
	[HID_CC_VOICE_COMMAND				] = KEY_VOICECOMMAND,
	[HID_CC_VOLUME					] = 0,
	[HID_CC_BALANCE					] = 0,
	[HID_CC_MUTE					] = KEY_MUTE,
	[HID_CC_BASS					] = 0,
	[HID_CC_TREBLE					] = 0,
	[HID_CC_BASS_BOOST				] = KEY_BASSBOOST,
	[HID_CC_SURROUND_MODE				] = 0,
	[HID_CC_LOUDNESS				] = 0,
	[HID_CC_MPX					] = 0,
	[HID_CC_VOLUME_UP				] = KEY_VOLUMEUP,
	[HID_CC_VOLUME_DOWN				] = KEY_VOLUMEDOWN,
	[HID_CC_SPEED_SELECT				] = 0,
	[HID_CC_PLAYBACK_SPEED				] = 0,
	[HID_CC_STANDARD_PLAY				] = 0,
	[HID_CC_LONG_PLAY				] = 0,
	[HID_CC_EXTENDED_PLAY				] = 0,
	[HID_CC_SLOW					] = KEY_SLOW,
	[HID_CC_FAN_ENABLE				] = 0,
	[HID_CC_FAN_SPEED				] = 0,
	[HID_CC_LIGHT_ENABLE				] = 0,
	[HID_CC_LIGHT_ILLUMINATION_LEVEL		] = 0,
	[HID_CC_CLIMATE_CONTROL_ENABLE			] = 0,
	[HID_CC_ROOM_TEMPERATURE			] = 0,
	[HID_CC_SECURITY_ENABLE				] = 0,
	[HID_CC_FIRE_ALARM				] = 0,
	[HID_CC_POLICE_ALARM				] = 0,
	[HID_CC_PROXIMITY				] = 0,
	[HID_CC_MOTION					] = 0,
	[HID_CC_DURESS_ALARM				] = 0,
	[HID_CC_HOLDUP_ALARM				] = 0,
	[HID_CC_MEDICAL_ALARM				] = 0,
	[HID_CC_BALANCE_RIGHT				] = 0,
	[HID_CC_BALANCE_LEFT				] = 0,
	[HID_CC_BASS_INCREMENT				] = 0,
	[HID_CC_BASS_DECREMENT				] = 0,
	[HID_CC_TREBLE_INCREMENT			] = 0,
	[HID_CC_TREBLE_DECREMENT			] = 0,
	[HID_CC_SPEAKER_SYSTEM				] = 0,
	[HID_CC_CHANNEL_LEFT				] = 0,
	[HID_CC_CHANNEL_RIGHT				] = 0,
	[HID_CC_CHANNEL_CENTER				] = 0,
	[HID_CC_CHANNEL_FRONT				] = 0,
	[HID_CC_CHANNEL_CENTER_FRONT			] = 0,
	[HID_CC_CHANNEL_SIDE				] = 0,
	[HID_CC_CHANNEL_SURROUND			] = 0,
	[HID_CC_CHANNEL_LOW_FREQ_ENHANCEMENT		] = 0,
	[HID_CC_CHANNEL_TOP				] = 0,
	[HID_CC_CHANNEL_UNKNOWN				] = 0,
	[HID_CC_SUB_CHANNEL				] = 0,
	[HID_CC_SUB_CHANNEL_INCREMENT			] = 0,
	[HID_CC_SUB_CHANNEL_DECREMENT			] = 0,
	[HID_CC_ALTERNATE_AUDIO_INCREMENT		] = 0,
	[HID_CC_ALTERNATE_AUDIO_DECREMENT		] = 0,
	[HID_CC_APPLICATION_LAUNCH_BUTTONS		] = 0,
	[HID_CC_AL_LAUNCH_BUTTON_CONFIG_TOOL		] = 0,
	[HID_CC_AL_PROGRAMMABLE_BUTTON_CONFIG		] = 0,
	[HID_CC_AL_CONSUMER_CONTROL_CONFIG		] = KEY_CONFIG,
	[HID_CC_AL_WORD_PROCESSOR			] = KEY_WORDPROCESSOR,
	[HID_CC_AL_TEXT_EDITOR				] = KEY_EDITOR,
	[HID_CC_AL_SPREADSHEET				] = KEY_SPREADSHEET,
	[HID_CC_AL_GRAPHICS_EDITOR			] = KEY_GRAPHICSEDITOR,
	[HID_CC_AL_PRESENTATION_APP			] = KEY_PRESENTATION,
	[HID_CC_AL_DATABASE_APP				] = KEY_DATABASE,
	[HID_CC_AL_EMAIL_READER				] = KEY_EMAIL,
	[HID_CC_AL_NEWSREADER				] = KEY_NEWS,
	[HID_CC_AL_VOICEMAIL				] = KEY_VOICEMAIL,
	[HID_CC_AL_CONTACTS_ADDRESS_BOOK		] = KEY_ADDRESSBOOK,
	[HID_CC_AL_CALENDAR_SCHEDULE			] = 0,
	[HID_CC_AL_TASK_PROJECT_MANAGER			] = 0,
	[HID_CC_AL_LOG_JOURNAL_TIMECARD			] = 0,
	[HID_CC_AL_CHECKBOOK_FINANCE			] = KEY_FINANCE,
	[HID_CC_AL_CALCULATOR				] = KEY_CALC,
	[HID_CC_AL_A_VCAPTURE_PLAYBACK			] = 0,
	[HID_CC_AL_LOCAL_MACHINE_BROWSER		] = KEY_FILE,
	[HID_CC_AL_LAN_WANBROWSER			] = 0,
	[HID_CC_AL_INTERNET_BROWSER			] = KEY_WWW,
	[HID_CC_AL_REMOTE_NETWORKING_ISPCONNECT		] = 0,
	[HID_CC_AL_NETWORK_CONFERENCE			] = 0,
	[HID_CC_AL_NETWORK_CHAT				] = 0,
	[HID_CC_AL_TELEPHONY_DIALER			] = KEY_PHONE,
	[HID_CC_AL_LOGON				] = 0,
	[HID_CC_AL_LOGOFF				] = 0,
	[HID_CC_AL_LOGON_LOGOFF				] = 0,
	[HID_CC_AL_TERMINAL_LOCK_SCREENSAVER		] = KEY_COFFEE,
	[HID_CC_AL_CONTROL_PANEL			] = 0,
	[HID_CC_AL_COMMAND_LINE_PROCESSOR_RUN		] = 0,
	[HID_CC_AL_PROCESS_TASK_MANAGER			] = 0,
	[HID_CC_AL_SELECT_TASK_APPLICATION		] = 0,
	[HID_CC_AL_NEXT_TASK_APPLICATION		] = 0,
	[HID_CC_AL_PREVIOUS_TASK_APPLICATION		] = 0,
	[HID_CC_AL_PREEMPT_HALT_TASK_APPLICATION	] = 0,
	[HID_CC_AL_INTEGRATED_HELP_CENTER		] = KEY_HELP,
	[HID_CC_AL_DOCUMENTS				] = 0,
	[HID_CC_AL_THESAURUS				] = 0,
	[HID_CC_AL_DICTIONARY				] = 0,
	[HID_CC_AL_DESKTOP				] = 0,
	[HID_CC_AL_SPELL_CHECK				] = 0,
	[HID_CC_AL_GRAMMAR_CHECK			] = 0,
	[HID_CC_AL_WIRELESS_STATUS			] = 0,
	[HID_CC_AL_KEYBOARD_LAYOUT			] = 0,
	[HID_CC_AL_VIRUS_PROTECTION			] = 0,
	[HID_CC_AL_ENCRYPTION				] = 0,
	[HID_CC_AL_SCREEN_SAVER				] = KEY_SCREENSAVER,
	[HID_CC_AL_ALARMS				] = 0,
	[HID_CC_AL_CLOCK				] = 0,
	[HID_CC_AL_FILE_BROWSER				] = KEY_FILE,
	[HID_CC_AL_POWER_STATUS				] = 0,
	[HID_CC_AL_IMAGE_BROWSER			] = KEY_IMAGES,
	[HID_CC_AL_AUDIO_BROWSER			] = KEY_AUDIO,
	[HID_CC_AL_MOVIE_BROWSER			] = KEY_VIDEO,
	[HID_CC_AL_DIGITAL_RIGHTS_MANAGER		] = 0,
	[HID_CC_AL_DIGITAL_WALLET			] = 0,
	[HID_CC_AL_INSTANT_MESSAGING			] = KEY_MESSENGER,
	[HID_CC_AL_OEMFEATURES_TIPS_TUTO_BROWSER	] = KEY_INFO,
	[HID_CC_AL_OEMHELP				] = 0,
	[HID_CC_AL_ONLINE_COMMUNITY			] = 0,
	[HID_CC_AL_ENTERTAINMENT_CONTENT_BROWSER	] = 0,
	[HID_CC_AL_ONLINE_SHOPPING_BROWSER		] = 0,
	[HID_CC_AL_SMART_CARD_INFORMATION_HELP		] = 0,
	[HID_CC_AL_MARKET_MONITOR_FINANCE_BROWSER	] = 0,
	[HID_CC_AL_CUSTOMIZED_CORP_NEWS_BROWSER		] = 0,
	[HID_CC_AL_ONLINE_ACTIVITY_BROWSER		] = 0,
	[HID_CC_AL_RESEARCH_SEARCH_BROWSER		] = 0,
	[HID_CC_AL_AUDIO_PLAYER				] = 0,
	[HID_CC_GENERIC_GUIAPPLICATION_CONTROLS		] = 0,
	[HID_CC_AC_NEW					] = KEY_NEW,
	[HID_CC_AC_OPEN					] = KEY_OPEN,
	[HID_CC_AC_CLOSE				] = KEY_CLOSE,
	[HID_CC_AC_EXIT					] = KEY_EXIT,
	[HID_CC_AC_MAXIMIZE				] = 0,
	[HID_CC_AC_MINIMIZE				] = 0,
	[HID_CC_AC_SAVE					] = KEY_SAVE,
	[HID_CC_AC_PRINT				] = KEY_PRINT,
	[HID_CC_AC_PROPERTIES				] = KEY_PROPS,
	[HID_CC_AC_UNDO					] = KEY_UNDO,
	[HID_CC_AC_COPY					] = KEY_COPY,
	[HID_CC_AC_CUT					] = KEY_CUT,
	[HID_CC_AC_PASTE				] = KEY_PASTE,
	[HID_CC_AC_SELECT_ALL				] = KEY_SELECT,
	[HID_CC_AC_FIND					] = KEY_FIND,
	[HID_CC_AC_FINDAND_REPLACE			] = 0,
	[HID_CC_AC_SEARCH				] = KEY_SEARCH,
	[HID_CC_AC_GO_TO				] = KEY_GOTO,
	[HID_CC_AC_HOME					] = KEY_HOMEPAGE,
	[HID_CC_AC_BACK					] = KEY_BACK,
	[HID_CC_AC_FORWARD				] = KEY_FORWARD,
	[HID_CC_AC_STOP					] = KEY_STOP,
	[HID_CC_AC_REFRESH				] = KEY_REFRESH,
	[HID_CC_AC_PREVIOUS_LINK			] = KEY_PREVIOUS,
	[HID_CC_AC_NEXT_LINK				] = KEY_NEXT,
	[HID_CC_AC_BOOKMARKS				] = KEY_BOOKMARKS,
	[HID_CC_AC_HISTORY				] = 0,
	[HID_CC_AC_SUBSCRIPTIONS			] = 0,
	[HID_CC_AC_ZOOM_IN				] = KEY_ZOOMIN,
	[HID_CC_AC_ZOOM_OUT				] = KEY_ZOOMOUT,
	[HID_CC_AC_ZOOM					] = KEY_ZOOMRESET,
	[HID_CC_AC_FULL_SCREEN_VIEW			] = 0,
	[HID_CC_AC_NORMAL_VIEW				] = 0,
	[HID_CC_AC_VIEW_TOGGLE				] = 0,
	[HID_CC_AC_SCROLL_UP				] = KEY_SCROLLUP,
	[HID_CC_AC_SCROLL_DOWN				] = KEY_SCROLLDOWN,
	[HID_CC_AC_SCROLL				] = 0,
	[HID_CC_AC_PAN_LEFT				] = 0,
	[HID_CC_AC_PAN_RIGHT				] = 0,
	[HID_CC_AC_PAN					] = 0,
	[HID_CC_AC_NEW_WINDOW				] = 0,
	[HID_CC_AC_TILE_HORIZONTALLY			] = 0,
	[HID_CC_AC_TILE_VERTICALLY			] = 0,
	[HID_CC_AC_FORMAT				] = 0,
	[HID_CC_AC_EDIT					] = KEY_EDIT,
	[HID_CC_AC_BOLD					] = 0,
	[HID_CC_AC_ITALICS				] = 0,
	[HID_CC_AC_UNDERLINE				] = 0,
	[HID_CC_AC_STRIKETHROUGH			] = 0,
	[HID_CC_AC_SUBSCRIPT				] = 0,
	[HID_CC_AC_SUPERSCRIPT				] = 0,
	[HID_CC_AC_ALL_CAPS				] = 0,
	[HID_CC_AC_ROTATE				] = 0,
	[HID_CC_AC_RESIZE				] = 0,
	[HID_CC_AC_FLIPHORIZONTAL			] = 0,
	[HID_CC_AC_FLIP_VERTICAL			] = 0,
	[HID_CC_AC_MIRROR_HORIZONTAL			] = 0,
	[HID_CC_AC_MIRROR_VERTICAL			] = 0,
	[HID_CC_AC_FONT_SELECT				] = 0,
	[HID_CC_AC_FONT_COLOR				] = 0,
	[HID_CC_AC_FONT_SIZE				] = 0,
	[HID_CC_AC_JUSTIFY_LEFT				] = 0,
	[HID_CC_AC_JUSTIFY_CENTER_H			] = 0,
	[HID_CC_AC_JUSTIFY_RIGHT			] = 0,
	[HID_CC_AC_JUSTIFY_BLOCK_H			] = 0,
	[HID_CC_AC_JUSTIFY_TOP				] = 0,
	[HID_CC_AC_JUSTIFY_CENTER_V			] = 0,
	[HID_CC_AC_JUSTIFY_BOTTOM			] = 0,
	[HID_CC_AC_JUSTIFY_BLOCK_V			] = 0,
	[HID_CC_AC_INDENT_DECREASE			] = 0,
	[HID_CC_AC_INDENT_INCREASE			] = 0,
	[HID_CC_AC_NUMBERED_LIST			] = 0,
	[HID_CC_AC_RESTART_NUMBERING			] = 0,
	[HID_CC_AC_BULLETED_LIST			] = 0,
	[HID_CC_AC_PROMOTE				] = 0,
	[HID_CC_AC_DEMOTE				] = 0,
	[HID_CC_AC_YES					] = 0,
	[HID_CC_AC_NO					] = 0,
	[HID_CC_AC_CANCEL				] = KEY_CANCEL,
	[HID_CC_AC_CATALOG				] = 0,
	[HID_CC_AC_BUY_CHECKOUT				] = 0,
	[HID_CC_AC_ADDTO_CART				] = 0,
	[HID_CC_AC_EXPAND				] = 0,
	[HID_CC_AC_EXPAND_ALL				] = 0,
	[HID_CC_AC_COLLAPSE				] = 0,
	[HID_CC_AC_COLLAPSE_ALL				] = 0,
	[HID_CC_AC_PRINT_PREVIEW			] = 0,
	[HID_CC_AC_PASTE_SPECIAL			] = 0,
	[HID_CC_AC_INSERT_MODE				] = 0,
	[HID_CC_AC_DELETE				] = KEY_DELETE,
	[HID_CC_AC_LOCK					] = 0,
	[HID_CC_AC_UNLOCK				] = 0,
	[HID_CC_AC_PROTECT				] = 0,
	[HID_CC_AC_UNPROTECT				] = 0,
	[HID_CC_AC_ATTACH_COMMENT			] = 0,
	[HID_CC_AC_DELETE_COMMENT			] = 0,
	[HID_CC_AC_VIEW_COMMENT				] = 0,
	[HID_CC_AC_SELECT_WORD				] = 0,
	[HID_CC_AC_SELECT_SENTENCE			] = 0,
	[HID_CC_AC_SELECT_PARAGRAPH			] = 0,
	[HID_CC_AC_SELECT_COLUMN			] = 0,
	[HID_CC_AC_SELECT_ROW				] = 0,
	[HID_CC_AC_SELECT_TABLE				] = 0,
	[HID_CC_AC_SELECT_OBJECT			] = 0,
	[HID_CC_AC_REDO_REPEAT				] = KEY_REDO,
	[HID_CC_AC_SORT					] = 0,
	[HID_CC_AC_SORT_ASCENDING			] = 0,
	[HID_CC_AC_SORT_DESCENDING			] = 0,
	[HID_CC_AC_FILTER				] = 0,
	[HID_CC_AC_SET_CLOCK				] = 0,
	[HID_CC_AC_VIEW_CLOCK				] = 0,
	[HID_CC_AC_SELECT_TIME_ZONE			] = 0,
	[HID_CC_AC_EDIT_TIME_ZONES			] = 0,
	[HID_CC_AC_SET_ALARM				] = 0,
	[HID_CC_AC_CLEAR_ALARM				] = 0,
	[HID_CC_AC_SNOOZE_ALARM				] = 0,
	[HID_CC_AC_RESET_ALARM				] = 0,
	[HID_CC_AC_SYNCHRONIZE				] = 0,
	[HID_CC_AC_SEND_RECEIVE				] = 0,
	[HID_CC_AC_SEND_TO				] = 0,
	[HID_CC_AC_REPLY				] = KEY_REPLY,
	[HID_CC_AC_REPLY_ALL				] = 0,
	[HID_CC_AC_FORWARD_MSG				] = KEY_FORWARDMAIL,
	[HID_CC_AC_SEND					] = KEY_SEND,
	[HID_CC_AC_ATTACH_FILE				] = 0,
	[HID_CC_AC_UPLOAD				] = 0,
	[HID_CC_AC_DOWNLOAD(SAVE_TARGET_AS)		] = 0,
	[HID_CC_AC_SET_BORDERS				] = 0,
	[HID_CC_AC_INSERT_ROW				] = 0,
	[HID_CC_AC_INSERT_COLUMN			] = 0,
	[HID_CC_AC_INSERT_FILE				] = 0,
	[HID_CC_AC_INSERT_PICTURE			] = 0,
	[HID_CC_AC_INSERT_OBJECT			] = 0,
	[HID_CC_AC_INSERT_SYMBOL			] = 0,
	[HID_CC_AC_SAVEAND_CLOSE			] = 0,
	[HID_CC_AC_RENAME				] = 0,
	[HID_CC_AC_MERGE				] = 0,
	[HID_CC_AC_SPLIT				] = 0,
	[HID_CC_AC_DISRIBUTE_HORIZONTALLY		] = 0,
	[HID_CC_AC_DISTRIBUTE_VERTICALLY		] = 0,
};

unsigned int
ratbag_hidraw_get_keycode_from_keyboard_usage(const struct ratbag_device *device,
					      uint8_t hid_code)
{
	return hid_keyboard_mapping[hid_code];
}

uint8_t
ratbag_hidraw_get_keyboard_usage_from_keycode(const struct ratbag_device *device, unsigned keycode)
{
	unsigned int j;

	for (j = 0; j < ARRAY_LENGTH(hid_keyboard_mapping); j++) {
		if (hid_keyboard_mapping[j] == keycode)
			return j;
	}

	return 0;
}

unsigned int
ratbag_hidraw_get_keycode_from_consumer_usage(const struct ratbag_device *device,
					      uint16_t hid_code)
{
	return hid_consumer_mapping[hid_code];
}

uint16_t
ratbag_hidraw_get_consumer_usage_from_keycode(const struct ratbag_device *device, unsigned keycode)
{
	unsigned int j;

	for (j = 0; j < ARRAY_LENGTH(hid_consumer_mapping); j++) {
		if (hid_consumer_mapping[j] == keycode)
			return j;
	}

	return 0;
}

static int
ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device)
{
	int rc, desc_size = 0;
	struct ratbag_hidraw *hidraw = &device->hidraw[0];
	struct hidraw_report_descriptor report_desc = {0};
	unsigned int i, j;
	unsigned int usage_page, usage;

	hidraw->num_reports = 0;

	rc = ioctl(hidraw->fd, HIDIOCGRDESCSIZE, &desc_size);
	if (rc < 0)
		return rc;

	report_desc.size = desc_size;
	rc = ioctl(hidraw->fd, HIDIOCGRDESC, &report_desc);
	if (rc < 0)
		return rc;

	log_debug(device->ratbag, "Parsing HID report descriptor\n");

	i = 0;
	usage_page = 0;
	usage = 0;
	while (i < report_desc.size) {
		uint8_t value = report_desc.value[i];
		uint8_t hid = value & 0xfc;
		uint8_t size = value & 0x3;
		unsigned content = 0;

		if (size == 3)
			size = 4;

		if (i + size >= report_desc.size)
			return -EPROTO;

		for (j = 0; j < size; j++)
			content |= report_desc.value[i + j + 1] << (j * 8);

		switch (hid) {
		case HID_REPORT_ID:
			if (hidraw->reports) {
				log_debug(device->ratbag, "- HID report ID %02x\n", content);
				hidraw->reports[hidraw->num_reports].report_id = content;
				hidraw->reports[hidraw->num_reports].usage_page = usage_page;
				hidraw->reports[hidraw->num_reports].usage = usage;
			}
			hidraw->num_reports++;
			break;
		case HID_COLLECTION:
			if (content == HID_APPLICATION &&
			    hidraw->reports &&
			    !hidraw->num_reports &&
			    !hidraw->reports[0].report_id) {
				hidraw->reports[hidraw->num_reports].usage_page = usage_page;
				hidraw->reports[hidraw->num_reports].usage = usage;
			}
			break;
		case HID_USAGE_PAGE:
			usage_page = content;
			break;
		case HID_USAGE:
			usage = content;
			break;
		}

		i += 1 + size;
	}

	return 0;
}

static int
ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw_udev, int idx)
{
	struct hidraw_devinfo info;
	struct ratbag_device *tmp_device;
	int fd, res;
	const char *devnode;
	const char *sysname;
	size_t reports_size;

	assert(idx >= 0 && idx < MAX_HIDRAW);

	device->hidraw[idx].fd = -1;

	sysname = udev_device_get_sysname(hidraw_udev);
	if (!strneq("hidraw", sysname, 6))
		return -ENODEV;

	list_for_each(tmp_device, &device->ratbag->devices, link) {
		if (tmp_device->hidraw[idx].sysname &&
		    streq(tmp_device->hidraw[idx].sysname, sysname)) {
			return -ENODEV;
		}
	}

	devnode = udev_device_get_devnode(hidraw_udev);
	fd = ratbag_open_path(device, devnode, O_RDWR);
	if (fd < 0)
		goto err;

	/* Get Raw Info */
	res = ioctl(fd, HIDIOCGRAWINFO, &info);
	if (res < 0) {
		log_error(device->ratbag,
			  "error while getting info from device");
		goto err;
	}

	log_debug(device->ratbag,
		  "hidraw info: bus %#04x vendor %#04x product %#04x\n",
		  info.bustype, info.vendor, info.product);

	/* check basic matching between the hidraw node and the ratbag device */
	if (info.bustype != device->ids.bustype ||
	    (info.vendor & 0xFFFF )!= device->ids.vendor ||
	    (info.product & 0xFFFF) != device->ids.product) {
		errno = ENODEV;
		goto err;
	}

	log_debug(device->ratbag,
		  "%s is device '%s'.\n",
		  device->name,
		  udev_device_get_devnode(hidraw_udev));

	device->hidraw[idx].fd = fd;

	/* parse first to count the number of reports */
	res = ratbag_hidraw_parse_report_descriptor(device);
	if (res) {
		log_error(device->ratbag,
			  "Error while parsing the report descriptor: '%s' (%d)\n",
			  strerror(-res),
			  res);
		device->hidraw[idx].fd = -1;
		goto err;
	}

	if (device->hidraw[idx].num_reports)
		reports_size = device->hidraw[idx].num_reports * sizeof(struct ratbag_hid_report);
	else
		reports_size = sizeof(struct ratbag_hid_report);

	device->hidraw[idx].reports = zalloc(reports_size);
	ratbag_hidraw_parse_report_descriptor(device);

	device->hidraw[idx].sysname = strdup_safe(sysname);
	return 0;

err:
	if (fd >= 0)
		ratbag_close_fd(device, fd);
	return -errno;
}

static int
ratbag_find_hidraw_node(struct ratbag_device *device,
			int (*match)(struct ratbag_device *device),
			int use_usb_parent,
			int match_index, int hidraw_index)
{
	struct ratbag *ratbag = device->ratbag;
	_cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
	struct udev_list_entry *entry;
	const char *path;
	struct udev_device *hid_udev;
	struct udev_device *parent_udev;
	struct udev *udev = ratbag->udev;
	int rc = -ENODEV;
	int matched, endpoint_index = 0;

	assert(match);

	hid_udev = udev_device_get_parent_with_subsystem_devtype(device->udev_device, "hid", NULL);

	if (!hid_udev)
		return -ENODEV;

	if (use_usb_parent && device->ids.bustype == BUS_USB) {
		/* using the parent usb_device to match siblings */
		parent_udev = udev_device_get_parent(hid_udev);
		if (!streq("uhid", udev_device_get_sysname(parent_udev)))
			parent_udev = udev_device_get_parent_with_subsystem_devtype(hid_udev,
										    "usb",
										    "usb_device");
	} else {
		parent_udev = hid_udev;
	}

	e = udev_enumerate_new(udev);
	udev_enumerate_add_match_subsystem(e, "hidraw");
	udev_enumerate_add_match_parent(e, parent_udev);
	udev_enumerate_scan_devices(e);
	udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
		_cleanup_(udev_device_unrefp) struct udev_device *udev_device = NULL;

		path = udev_list_entry_get_name(entry);
		udev_device = udev_device_new_from_syspath(udev, path);
		if (!udev_device)
			continue;

		if (match_index > 0 && match_index != endpoint_index++)
			continue;

		rc = ratbag_open_hidraw_node(device, udev_device, hidraw_index);
		if (rc)
			goto skip;


		matched = match(device);
		rc = matched ? 0 : -ENODEV;
		if (matched == 1)
			return rc;

skip:
		ratbag_close_hidraw_index(device, hidraw_index);
	}

	return rc;
}

int
ratbag_find_hidraw(struct ratbag_device *device, int (*match)(struct ratbag_device *device))
{
	return ratbag_find_hidraw_node(device, match, true, -1, 0);
}

static int
hidraw_match_all(struct ratbag_device *device)
{
	return 1;
}

int
ratbag_open_hidraw(struct ratbag_device *device)
{
	return ratbag_find_hidraw_node(device, hidraw_match_all, false, -1, 0);
}

int
ratbag_open_hidraw_index(struct ratbag_device *device, int endpoint_index, int hidraw_index)
{
	return ratbag_find_hidraw_node(device, hidraw_match_all, true, endpoint_index, hidraw_index);
}

static struct ratbag_hid_report *
ratbag_hidraw_get_report(const struct ratbag_device *device, unsigned int report_id)
{
	unsigned i;

	if (report_id == 0) {
		if (device->hidraw[0].reports[0].report_id == report_id)
			return &device->hidraw[0].reports[0];
		else
			return NULL;
	}

	for (i = 0; i < device->hidraw[0].num_reports; i++) {
		if (device->hidraw[0].reports[i].report_id == report_id)
			return &device->hidraw[0].reports[i];
	}

	return NULL;
}


int
ratbag_hidraw_has_report(const struct ratbag_device *device, unsigned int report_id)
{
	return ratbag_hidraw_get_report(device, report_id) != NULL;
}

unsigned int
ratbag_hidraw_get_usage_page(const struct ratbag_device *device, unsigned int report_id)
{
	struct ratbag_hid_report *report;

	report = ratbag_hidraw_get_report(device, report_id);

	if (!report)
		return 0;

	return report->usage_page;
}

unsigned int
ratbag_hidraw_get_usage(const struct ratbag_device *device, unsigned int report_id)
{
	struct ratbag_hid_report *report;

	report = ratbag_hidraw_get_report(device, report_id);

	if (!report)
		return 0;

	return report->usage;
}

unsigned int
ratbag_hidraw_has_vendor_page(const struct ratbag_device *device)
{
	unsigned i;

	if (ratbag_hidraw_get_usage_page(device, 0) >= 0xff00)
		return 1;

	for (i = 0; i < device->hidraw[0].num_reports; i++) {
		if (ratbag_hidraw_get_usage_page(device, device->hidraw[0].reports[i].report_id) >= 0xff00)
			return 1;
	}
	return 0;
}

void
ratbag_close_hidraw(struct ratbag_device *device)
{
	ratbag_close_hidraw_index(device, 0);
}

void
ratbag_close_hidraw_index(struct ratbag_device *device, int idx)
{
	assert(idx >= 0 && idx < MAX_HIDRAW);

	if (device->hidraw[idx].fd < 0)
		return;

	if (device->hidraw[idx].sysname) {
		free(device->hidraw[idx].sysname);
		device->hidraw[idx].sysname = NULL;
	}

	ratbag_close_fd(device, device->hidraw[idx].fd);
	device->hidraw[idx].fd = -1;

	if (device->hidraw[idx].reports) {
		free(device->hidraw[idx].reports);
		device->hidraw[idx].reports = NULL;
	}
}

int
ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum,
			  uint8_t *buf, size_t len, unsigned char rtype, int reqtype)
{
	uint8_t tmp_buf[HID_MAX_BUFFER_SIZE];
	int rc;

	if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0)
		return -EINVAL;

	if (rtype != HID_FEATURE_REPORT)
		return -ENOTSUP;

	switch (reqtype) {
	case HID_REQ_GET_REPORT:
		memset(tmp_buf, 0, len);
		tmp_buf[0] = reportnum;

		rc = ioctl(device->hidraw[0].fd, HIDIOCGFEATURE(len), tmp_buf);
		if (rc < 0)
			return -errno;

		log_buf_raw(device->ratbag, "feature get:   ", tmp_buf, (unsigned)rc);

		memcpy(buf, tmp_buf, rc);
		return rc;
	case HID_REQ_SET_REPORT:
		buf[0] = reportnum;

		log_buf_raw(device->ratbag, "feature set:   ", buf, len);
		rc = ioctl(device->hidraw[0].fd, HIDIOCSFEATURE(len), buf);
		if (rc < 0)
			return -errno;

		return rc;
	}

	return -EINVAL;
}

int
ratbag_hidraw_get_feature_report(struct ratbag_device *device, unsigned char reportnum,
				 uint8_t *buf, size_t len)
{
	return ratbag_hidraw_raw_request(device, reportnum, buf, len,
					 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
}

int
ratbag_hidraw_set_feature_report(struct ratbag_device *device, unsigned char reportnum,
				 uint8_t *buf, size_t len)
{
	return ratbag_hidraw_raw_request(device, reportnum, buf, len,
					 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}


int
ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t len)
{
	int rc;

	if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0)
		return -EINVAL;

	log_buf_raw(device->ratbag, "output report: ", buf, len);

	rc = write(device->hidraw[0].fd, buf, len);

	if (rc < 0)
		return -errno;

	if (rc != (int)len)
		return -EIO;

	return 0;
}

int
ratbag_hidraw_read_input_report(const struct ratbag_device *device, uint8_t *buf, size_t len,
				 ratbagd_hidraw_filter_t filter)
{
	return ratbag_hidraw_read_input_report_index(device, buf, len, 0, filter);
}

int
ratbag_hidraw_read_input_report_index(const struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno,
				 ratbagd_hidraw_filter_t filter)
{
	int rc, nfds;
	struct pollfd fds;
	int ts, ts_end;

	assert(hidrawno >= 0 && hidrawno < MAX_HIDRAW);

	if (len < 1 || !buf || device->hidraw[hidrawno].fd < 0)
		return -EINVAL;

	fds.fd = device->hidraw[hidrawno].fd;
	fds.events = POLLIN;

	/* convert to ms */
	ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
	ts_end = ts + 1000; /* end in now + 1000ms */

	while (ts < ts_end) {
		nfds = poll(&fds, 1, ts_end - ts); /* poll for the remainder of timeout */

		if (nfds < 0)
			return -errno;

		if (nfds > 0) {
			rc = read(device->hidraw[hidrawno].fd, buf, len);

			if (rc < 0)
  				return -errno;

			if (rc > 0) {
				if(!filter || (filter && filter(buf, rc))) {
					log_buf_raw(device->ratbag, "input report:  ", buf, rc);
					return rc;
				}
			}
		}

		ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
	}

	return -ETIMEDOUT;
}
