/*
 * This file is part of roccat-tools.
 *
 * roccat-tools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * roccat-tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with roccat-tools. If not, see <http://www.gnu.org/licenses/>.
 */

#include <gaminggear/hid_uid.h>
#include <gaminggear/gdk_key_translations.h>
#include "ryosconfig_keyboard_selector.h"
#include "ryosconfig_key_button.h"
#include "ryosconfig_fn_selector.h"
#include "ryosconfig_standard_selector.h"
#include "ryosconfig_capslock_selector.h"
#include "ryosconfig_illumination_frame.h"
#include "ryosconfig_key_illumination_selector.h"
#include "roccat_multiwidget.h"
#include "roccat_helper.h"
#include "ryos_rkp_accessors.h"
#include "g_cclosure_roccat_marshaller.h"

#define RYOSCONFIG_KEYBOARD_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RYOSCONFIG_KEYBOARD_SELECTOR_TYPE, RyosconfigKeyboardSelectorClass))
#define IS_RYOSCONFIG_KEYBOARD_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RYOSCONFIG_KEYBOARD_SELECTOR_TYPE))
#define RYOSCONFIG_KEYBOARD_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RYOSCONFIG_KEYBOARD_SELECTOR_TYPE, RyosconfigKeyboardSelectorClass))
#define RYOSCONFIG_KEYBOARD_SELECTOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), RYOSCONFIG_KEYBOARD_SELECTOR_TYPE, RyosconfigKeyboardSelectorPrivate))

typedef struct _RyosconfigKeyboardSelectorClass RyosconfigKeyboardSelectorClass;
typedef struct _RyosconfigKeyboardSelectorPrivate RyosconfigKeyboardSelectorPrivate;
typedef struct _RyosconfigKeyboardSelectorPrivateData RyosconfigKeyboardSelectorPrivateData;
typedef struct _RyosKeytable RyosKeytable;

struct _RyosconfigKeyboardSelector {
	GtkFrame parent;
	RyosconfigKeyboardSelectorPrivate *priv;
};

struct _RyosconfigKeyboardSelectorClass {
	GtkFrameClass parent_class;
};

enum {
	KEYS_NUM = 119,
	INDEX_INVALID = 0xff,
	TABLE_WIDTH = 23,
	TABLE_HEIGHT = 72,
};

static gchar const * const index_key = "index";

struct _RyosconfigKeyboardSelectorPrivate {
	RyosconfigKeyButton *keys[KEYS_NUM];
	GtkScrolledWindow *scroll_window;

	RyosconfigIlluminationFrame *illumination_frame;
	GtkLabel *label;
	guint actual_index;

	RoccatMultiwidget *key_type_multiwidget;
	RyosconfigFnSelector *fn_selector;
	RyosconfigCapslockSelector *capslock_selector;
	RyosconfigStandardSelector *standard_selector;
	GtkWidget *nothing_selector;

	RoccatMultiwidget *key_illumination_multiwidget;
	RyosconfigKeyIlluminationSelector *key_illumination_selector;
	GtkWidget *key_illumination_box;
	GtkWidget *key_illumination_nothing;

	/* private object data can only be 64kb in size */
	RyosconfigKeyboardSelectorPrivateData *data;

	gboolean periodic_blink_state;
	guint blink_timeout;
};

struct _RyosconfigKeyboardSelectorPrivateData {
	RyosconfigKeyComboBoxData standard_datas[KEYS_NUM];
	RyosconfigKeyComboBoxData easyshift_datas[KEYS_NUM];
	RyosStoredLights lights_automatic;
	RyosStoredLights lights_manual;
};

static void toggled_cb(GtkToggleButton *button, gpointer user_data);

G_DEFINE_TYPE(RyosconfigKeyboardSelector, ryosconfig_keyboard_selector, GTK_TYPE_FRAME);

enum {
	LAYER_EDITOR,
	LAST_SIGNAL,
};

static guint signals[LAST_SIGNAL] = { 0 };

struct _RyosKeytable {
	guint8 primary;
	guint8 row;
	guint8 height;
	guint8 column;
	guint8 width;
	guint8 talk_index;
	guint8 macro_index; /* values range from 0x00-0x6f */
	guint8 macro_index_easyshift;
	guint8 primary_index; /* extended with thumbster keys */
	guint8 keys_type;
	guint8 keys_index;
	guint8 keys_index_easyshift;
	guint mask;
	guint mask_easyshift;
	guint8 default_normal;
	guint8 default_easyshift;
};

enum {
	KEYS_TYPE_NOTHING,
	KEYS_TYPE_FN,
	KEYS_TYPE_CAPSLOCK,
	KEYS_TYPE_MACRO,
	KEYS_TYPE_THUMBSTER,
	KEYS_TYPE_FUNCTION,
	KEYS_TYPE_EASYZONE,
};

RyosKeytable keys[KEYS_NUM] = {
	/* keys_macro */
	{0xaa,  5, 4,  0, 4, 0, 0x00, 0x05, 0x00, KEYS_TYPE_MACRO, 0x00, 0x05, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_STANDARD_SHIFT_1, RYOS_KEY_TYPE_STANDARD_CTRL_1},
	{0xab,  9, 4,  0, 4, 1, 0x01, 0x06, 0x18, KEYS_TYPE_MACRO, 0x01, 0x06, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_STANDARD_SHIFT_2, RYOS_KEY_TYPE_STANDARD_CTRL_2},
	{0xac, 13, 4,  0, 4, 2, 0x02, 0x07, 0x30, KEYS_TYPE_MACRO, 0x02, 0x07, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_STANDARD_SHIFT_3, RYOS_KEY_TYPE_STANDARD_CTRL_3},
	{0xad, 17, 4,  0, 4, 3, 0x03, 0x08, 0x48, KEYS_TYPE_MACRO, 0x03, 0x08, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_STANDARD_SHIFT_4, RYOS_KEY_TYPE_STANDARD_CTRL_4},
	{0xae, 21, 4,  0, 4, 4, 0x04, 0x09, 0x60, KEYS_TYPE_MACRO, 0x04, 0x09, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_STANDARD_SHIFT_5, RYOS_KEY_TYPE_STANDARD_CTRL_5},

	/* keys_function */
	{0x3a,  0, 4, 13, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x02, KEYS_TYPE_FUNCTION, 0x00, 0x0f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F1, RYOS_KEY_TYPE_MULTIMEDIA_MUTE},
	{0x3b,  0, 4, 17, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x0e, KEYS_TYPE_FUNCTION, 0x01, 0x10, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F2, RYOS_KEY_TYPE_MULTIMEDIA_VOLUME_DOWN},
	{0x3c,  0, 4, 21, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x03, KEYS_TYPE_FUNCTION, 0x02, 0x11, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F3, RYOS_KEY_TYPE_MULTIMEDIA_VOLUME_UP},
	{0x3d,  0, 4, 25, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x0f, KEYS_TYPE_FUNCTION, 0x03, 0x12, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F4, RYOS_KEY_TYPE_APP_CALCULATOR},
	{0x3e,  0, 4, 31, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x04, KEYS_TYPE_FUNCTION, 0x04, 0x13, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F5, RYOS_KEY_TYPE_MULTIMEDIA_PLAY_PAUSE},
	{0x3f,  0, 4, 35, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x10, KEYS_TYPE_FUNCTION, 0x05, 0x14, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F6, RYOS_KEY_TYPE_MULTIMEDIA_STOP},
	{0x40,  0, 4, 39, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x05, KEYS_TYPE_FUNCTION, 0x06, 0x15, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F7, RYOS_KEY_TYPE_MULTIMEDIA_PREV_TRACK},
	{0x41,  0, 4, 43, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x11, KEYS_TYPE_FUNCTION, 0x07, 0x16, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F8, RYOS_KEY_TYPE_MULTIMEDIA_NEXT_TRACK},
	{0x42,  0, 4, 49, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x06, KEYS_TYPE_FUNCTION, 0x08, 0x17, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F9, RYOS_KEY_TYPE_APP_MY_COMPUTER},
	{0x43,  0, 4, 53, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x07, KEYS_TYPE_FUNCTION, 0x09, 0x18, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F10, RYOS_KEY_TYPE_APP_BROWSER},
	{0x44,  0, 4, 57, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x08, KEYS_TYPE_FUNCTION, 0x0a, 0x19, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F11, RYOS_KEY_TYPE_LIGHT},
	{0x45,  0, 4, 61, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x14, KEYS_TYPE_FUNCTION, 0x0b, 0x1a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_F12, RYOS_KEY_TYPE_RECORD},
	{0x46,  0, 4, 66, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x09, KEYS_TYPE_FUNCTION, 0x0c, 0x1b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_PRINT_SCREEN, RYOS_KEY_TYPE_DISABLED},
	{0x47,  0, 4, 70, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x15, KEYS_TYPE_FUNCTION, 0x0d, 0x1c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_SCROLL_LOCK, RYOS_KEY_TYPE_DISABLED},
	{0x48,  0, 4, 74, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x21, KEYS_TYPE_FUNCTION, 0x0e, 0x1d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_PAUSE, RYOS_KEY_TYPE_SYSTEM_SLEEP},

	/* keys_thumbster */
	/* primary values are artificial and need to be syncronized with ryosconfig_key_button.c:hid_to_beauty_keyname() */
	{0xf2, 26, 4, 26, 4, 5, 0x0a, 0x0d, 0x78, KEYS_TYPE_THUMBSTER, 0x00, 0x03, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOS_KEY_TYPE_PROFILE_DOWN, HID_UID_KB_CAPSLOCK},
	{0xf3, 26, 4, 30, 4, 6, 0x0b, 0x0e, 0x79, KEYS_TYPE_THUMBSTER, 0x01, 0x04, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOS_KEY_TYPE_OPEN_DRIVER, RYOS_KEY_TYPE_MULTIMEDIA_OPEN_PLAYER},
	{0xf4, 26, 4, 34, 4, 7, 0x0c, 0x0f, 0x7a, KEYS_TYPE_THUMBSTER, 0x02, 0x05, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY, RYOS_KEY_TYPE_PROFILE_UP, RYOS_KEY_TYPE_APP_EMAIL},

	/* keys_easyzone */
	{0x35,  5, 4,  5, 4, INDEX_INVALID, INDEX_INVALID, 0x10, 0x0c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x00, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x35, 0x35},
	{0x1e,  5, 4,  9, 4, INDEX_INVALID, INDEX_INVALID, 0x11, 0x0d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x01, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1e, 0x1e},
	{0x1f,  5, 4, 13, 4, INDEX_INVALID, INDEX_INVALID, 0x12, 0x19, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x02, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1f, 0x1f},
	{0x20,  5, 4, 17, 4, INDEX_INVALID, INDEX_INVALID, 0x13, 0x1a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x03, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x20, 0x20},
	{0x21,  5, 4, 21, 4, INDEX_INVALID, INDEX_INVALID, 0x14, 0x1b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x04, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x21, 0x21},
	{0x22,  5, 4, 25, 4, INDEX_INVALID, INDEX_INVALID, 0x15, 0x27, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x05, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x22, 0x22},
	{0x23,  5, 4, 29, 4, INDEX_INVALID, INDEX_INVALID, 0x16, 0x1c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x06, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x23, 0x23},
	{0x24,  5, 4, 33, 4, INDEX_INVALID, INDEX_INVALID, 0x17, 0x28, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x07, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x24, 0x24},
	{0x25,  5, 4, 37, 4, INDEX_INVALID, INDEX_INVALID, 0x18, 0x1d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x08, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x25, 0x25},
	{0x26,  5, 4, 41, 4, INDEX_INVALID, INDEX_INVALID, 0x19, 0x29, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x09, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x26, 0x26},
	{0x27,  5, 4, 45, 4, INDEX_INVALID, INDEX_INVALID, 0x1a, 0x12, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x27, 0x27},
	{0x2d,  5, 4, 49, 4, INDEX_INVALID, INDEX_INVALID, 0x1b, 0x1e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2d, 0x2d},
	{0x2e,  5, 4, 53, 4, INDEX_INVALID, INDEX_INVALID, 0x1c, 0x13, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2e, 0x2e},
	{0x89,  5, 4, 57, 4, INDEX_INVALID, INDEX_INVALID, 0x1d, 0x20, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x89, 0x89},
	{0x2a,  5, 4, 61, 4, INDEX_INVALID, INDEX_INVALID, 0x1e, 0x2c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0e, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2a, 0x2a},
	{0x49,  5, 4, 66, 4, INDEX_INVALID, INDEX_INVALID, 0x54, 0x2d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x44, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x49, 0x49},
	{0x4a,  5, 4, 70, 4, INDEX_INVALID, INDEX_INVALID, 0x55, 0x39, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x45, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4a, 0x4a},
	{0x4b,  5, 4, 74, 4, INDEX_INVALID, INDEX_INVALID, 0x56, 0x45, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x46, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4b, 0x4b},
	{0x53,  5, 4, 79, 4, INDEX_INVALID, INDEX_INVALID, 0x5e, 0x0a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4e, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x53, 0x53},
	{0x54,  5, 4, 83, 4, INDEX_INVALID, INDEX_INVALID, 0x5f, 0x16, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x54, 0x54},
	{0x55,  5, 4, 87, 4, INDEX_INVALID, INDEX_INVALID, 0x60, 0x0b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x50, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x55, 0x55},
	{0x56,  5, 4, 91, 4, INDEX_INVALID, INDEX_INVALID, 0x61, 0x17, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x51, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x56, 0x56},
	{0x2b,  9, 4,  5, 6, INDEX_INVALID, INDEX_INVALID, 0x1f, 0x24, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x0f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2b, 0x2b},
	{0x14,  9, 4, 11, 4, INDEX_INVALID, INDEX_INVALID, 0x20, 0x25, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x10, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x14, 0x14},
	{0x1a,  9, 4, 15, 4, INDEX_INVALID, INDEX_INVALID, 0x21, 0x31, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x11, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1a, 0x1a},
	{0x08,  9, 4, 19, 4, INDEX_INVALID, INDEX_INVALID, 0x22, 0x26, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x12, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x08, 0x08},
	{0x15,  9, 4, 23, 4, INDEX_INVALID, INDEX_INVALID, 0x23, 0x32, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x13, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x15, 0x15},
	{0x17,  9, 4, 27, 4, INDEX_INVALID, INDEX_INVALID, 0x24, 0x33, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x14, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x17, 0x17},
	{0x1c,  9, 4, 31, 4, INDEX_INVALID, INDEX_INVALID, 0x25, 0x34, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x15, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1c, 0x1c},
	{0x18,  9, 4, 35, 4, INDEX_INVALID, INDEX_INVALID, 0x26, 0x40, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x16, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x18, 0x18},
	{0x0c,  9, 4, 39, 4, INDEX_INVALID, INDEX_INVALID, 0x27, 0x35, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x17, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0c, 0x0c},
	{0x12,  9, 4, 43, 4, INDEX_INVALID, INDEX_INVALID, 0x28, 0x2a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x18, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x12, 0x12},
	{0x13,  9, 4, 47, 4, INDEX_INVALID, INDEX_INVALID, 0x29, 0x36, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x19, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x13, 0x13},
	{0x2f,  9, 4, 51, 4, INDEX_INVALID, INDEX_INVALID, 0x2a, 0x1f, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2f, 0x2f},
	{0x30,  9, 4, 55, 4, INDEX_INVALID, INDEX_INVALID, 0x2b, 0x2b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x30, 0x30},
	{0x31,  9, 4, 59, 6, INDEX_INVALID, INDEX_INVALID, 0x2c, 0x38, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x31, 0x31},
	{0x4c,  9, 4, 66, 4, INDEX_INVALID, INDEX_INVALID, 0x57, 0x51, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x47, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4c, 0x4c},
	{0x4d,  9, 4, 70, 4, INDEX_INVALID, INDEX_INVALID, 0x58, 0x5d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x48, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4d, 0x4d},
	{0x4e,  9, 4, 74, 4, INDEX_INVALID, INDEX_INVALID, 0x59, 0x69, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x49, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4e, 0x4e},
	{0x5f,  9, 4, 79, 4, INDEX_INVALID, INDEX_INVALID, 0x62, 0x22, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x52, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5f, 0x5f},
	{0x60,  9, 4, 83, 4, INDEX_INVALID, INDEX_INVALID, 0x63, 0x2e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x53, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x60, 0x60},
	{0x61,  9, 4, 87, 4, INDEX_INVALID, INDEX_INVALID, 0x64, 0x23, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x54, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x61, 0x61},
	{0x57,  9, 8, 91, 4, INDEX_INVALID, INDEX_INVALID, 0x65, 0x2f, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x55, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x57, 0x57},
	{0x04, 13, 4, 12, 4, INDEX_INVALID, INDEX_INVALID, 0x2d, 0x3d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x04, 0x04},
	{0x16, 13, 4, 16, 4, INDEX_INVALID, INDEX_INVALID, 0x2e, 0x49, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1e, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x16, 0x16},
	{0x07, 13, 4, 20, 4, INDEX_INVALID, INDEX_INVALID, 0x2f, 0x3e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x1f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x07, 0x07},
	{0x09, 13, 4, 24, 4, INDEX_INVALID, INDEX_INVALID, 0x30, 0x4a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x20, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x09, 0x09},
	{0x0a, 13, 4, 28, 4, INDEX_INVALID, INDEX_INVALID, 0x31, 0x3f, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x21, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0a, 0x0a},
	{0x0b, 13, 4, 32, 4, INDEX_INVALID, INDEX_INVALID, 0x32, 0x4b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x22, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0b, 0x0b},
	{0x0d, 13, 4, 36, 4, INDEX_INVALID, INDEX_INVALID, 0x33, 0x4c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x23, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0d, 0x0d},
	{0x0e, 13, 4, 40, 4, INDEX_INVALID, INDEX_INVALID, 0x34, 0x41, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x24, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0e, 0x0e},
	{0x0f, 13, 4, 44, 4, INDEX_INVALID, INDEX_INVALID, 0x35, 0x42, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x25, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x0f, 0x0f},
	{0x33, 13, 4, 48, 4, INDEX_INVALID, INDEX_INVALID, 0x36, 0x4e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x26, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x33, 0x33},
	{0x34, 13, 4, 52, 4, INDEX_INVALID, INDEX_INVALID, 0x37, 0x37, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x27, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x34, 0x34},
	{0x32, 13, 4, 56, 4, INDEX_INVALID, INDEX_INVALID, 0x38, 0x43, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x28, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x32, 0x32},
	{0x28, 13, 4, 60, 5, INDEX_INVALID, INDEX_INVALID, 0x39, 0x44, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x29, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x28, 0x28},
	{0x5c, 13, 4, 79, 4, INDEX_INVALID, INDEX_INVALID, 0x66, 0x3a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x56, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5c, 0x5c},
	{0x5d, 13, 4, 83, 4, INDEX_INVALID, INDEX_INVALID, 0x67, 0x46, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x57, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5d, 0x5d},
	{0x5e, 13, 4, 87, 4, INDEX_INVALID, INDEX_INVALID, 0x68, 0x3b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x58, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5e, 0x5e},
	{0xe1, 17, 4,  5, 5, INDEX_INVALID, INDEX_INVALID, 0x3a, 0x54, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe1, 0xe1},
	{0x64, 17, 4, 10, 4, INDEX_INVALID, INDEX_INVALID, 0x3b, 0x55, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x64, 0x64},
	{0x1d, 17, 4, 14, 4, INDEX_INVALID, INDEX_INVALID, 0x3c, 0x61, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1d, 0x1d},
	{0x1b, 17, 4, 18, 4, INDEX_INVALID, INDEX_INVALID, 0x3d, 0x56, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x1b, 0x1b},
	{0x06, 17, 4, 22, 4, INDEX_INVALID, INDEX_INVALID, 0x3e, 0x62, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2e, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x06, 0x06},
	{0x19, 17, 4, 26, 4, INDEX_INVALID, INDEX_INVALID, 0x3f, 0x57, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x2f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x19, 0x19},
	{0x05, 17, 4, 30, 4, INDEX_INVALID, INDEX_INVALID, 0x40, 0x63, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x30, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x05, 0x05},
	{0x11, 17, 4, 34, 4, INDEX_INVALID, INDEX_INVALID, 0x41, 0x58, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x31, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x11, 0x11},
	{0x10, 17, 4, 38, 4, INDEX_INVALID, INDEX_INVALID, 0x42, 0x4d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x32, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x10, 0x10},
	{0x36, 17, 4, 42, 4, INDEX_INVALID, INDEX_INVALID, 0x43, 0x59, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x33, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x36, 0x36},
	{0x37, 17, 4, 46, 4, INDEX_INVALID, INDEX_INVALID, 0x44, 0x5a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x34, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x37, 0x37},
	{0x38, 17, 4, 50, 4, INDEX_INVALID, INDEX_INVALID, 0x45, 0x4f, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x35, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x38, 0x38},
	{0x87, 17, 4, 54, 4, INDEX_INVALID, INDEX_INVALID, 0x46, 0x5b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x36, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x87, 0x87},
	{0xe5, 17, 4, 58, 7, INDEX_INVALID, INDEX_INVALID, 0x47, 0x50, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x37, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe5, 0xe5},
	{0x52, 17, 4, 70, 4, INDEX_INVALID, INDEX_INVALID, 0x5a, 0x75, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x52, 0x52},
	{0x59, 17, 4, 79, 4, INDEX_INVALID, INDEX_INVALID, 0x6a, 0x52, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x59, 0x59},
	{0x5a, 17, 4, 83, 4, INDEX_INVALID, INDEX_INVALID, 0x6b, 0x5e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5a, 0x5a},
	{0x5b, 17, 4, 87, 4, INDEX_INVALID, INDEX_INVALID, 0x6c, 0x53, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x5b, 0x5b},
	{0x58, 17, 8, 91, 4, INDEX_INVALID, INDEX_INVALID, 0x6d, 0x5f, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x58, 0x58},
	{0xe0, 21, 4,  5, 6, INDEX_INVALID, INDEX_INVALID, 0x48, 0x6c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x38, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe0, 0xe0},
	{0xe3, 21, 4, 11, 4, INDEX_INVALID, INDEX_INVALID, 0x49, 0x6d, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x39, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe3, 0xe3},
	{0xe2, 21, 4, 15, 5, INDEX_INVALID, INDEX_INVALID, 0x4a, 0x6e, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x3a, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe2, 0xe2},
	{0x8b, 21, 4, 20, 4, INDEX_INVALID, INDEX_INVALID, 0x4b, 0x64, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x3b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x8b, 0x8b},
	{0x2c, 21, 4, 24,14, INDEX_INVALID, INDEX_INVALID, 0x4d, 0x70, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x3d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x2c, 0x2c},
	{0x8a, 21, 4, 38, 4, INDEX_INVALID, INDEX_INVALID, 0x4f, 0x65, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x3f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x8a, 0x8a},
	{0x88, 21, 4, 42, 4, INDEX_INVALID, INDEX_INVALID, 0x50, 0x71, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x40, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x88, 0x88},
	{0xe6, 21, 4, 46, 5, INDEX_INVALID, INDEX_INVALID, 0x51, 0x72, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x41, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe6, 0xe6},
	{0x65, 21, 4, 55, 4, INDEX_INVALID, INDEX_INVALID, 0x52, 0x67, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x42, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x65, 0x65},
	{0xe4, 21, 4, 59, 6, INDEX_INVALID, INDEX_INVALID, 0x53, 0x5c, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x43, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0xe4, 0xe4},
	{0x50, 21, 4, 66, 4, INDEX_INVALID, INDEX_INVALID, 0x5b, 0x68, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4b, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x50, 0x50},
	{0x51, 21, 4, 70, 4, INDEX_INVALID, INDEX_INVALID, 0x5c, 0x74, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4c, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x51, 0x51},
	{0x4f, 21, 4, 74, 4, INDEX_INVALID, INDEX_INVALID, 0x5d, 0x76, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x4d, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x4f, 0x4f},
	{0x62, 21, 4, 79, 8, INDEX_INVALID, INDEX_INVALID, 0x6e, 0x6a, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5e, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x62, 0x62},
	{0x63, 21, 4, 87, 4, INDEX_INVALID, INDEX_INVALID, 0x6f, 0x6b, KEYS_TYPE_EASYZONE, INDEX_INVALID, 0x5f, RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, 0x63, 0x63},

	/* keys_extra */
	{0x39, 13, 4,  5, 7, 8, INDEX_INVALID, INDEX_INVALID, 0x3c, KEYS_TYPE_CAPSLOCK, INDEX_INVALID, INDEX_INVALID, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_EXTENDED | RYOSCONFIG_KEY_COMBO_BOX_GROUP_KEY, 0, HID_UID_KB_CAPSLOCK, HID_UID_KB_CAPSLOCK},
	{0xf1, 21, 4, 51, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x73, KEYS_TYPE_FN, INDEX_INVALID, INDEX_INVALID, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOS_KEY_TYPE_FN, RYOS_KEY_TYPE_FN},
	{0x29,  0, 4,  5, 4, INDEX_INVALID, INDEX_INVALID, INDEX_INVALID, 0x01, KEYS_TYPE_NOTHING, INDEX_INVALID, INDEX_INVALID, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, RYOSCONFIG_KEY_COMBO_BOX_GROUP_PRIMARY | RYOSCONFIG_KEY_COMBO_BOX_GROUP_TALK, HID_UID_KB_ESCAPE, HID_UID_KB_ESCAPE},

	/*
	 * primary_index
	 *   ambiguous
	 *     0x87, 0x88, 0x89, 0x8a, 0x90 0x91
	 *   unknown
	 *     0x47 = 0x85 (keypad ,)
	 *     0x77 = 0xe7 (right gui)
	 * macro_index
	 *   unknown
	 *     0x4c, 0x4e, 0x69, 0x77
	 * key_index_easyzone
	 *   unknown
	 */
};

GtkWidget *ryosconfig_keyboard_selector_new(void) {
	return GTK_WIDGET(g_object_new(RYOSCONFIG_KEYBOARD_SELECTOR_TYPE,
			"label", "Keys",
			NULL));
}

static guint get_active_index(RyosconfigKeyboardSelector *selector) {
	return selector->priv->actual_index;
}

static void set_active_index(RyosconfigKeyboardSelector *selector, guint index) {
	selector->priv->actual_index = index;
}

static void selector_label_update(RyosconfigKeyboardSelector *selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	gchar *string;

	string = hid_to_beauty_keyname(keys[index].primary);
	gtk_label_set_text(priv->label, string);
	g_free(string);
}

static void selector_show(RyosconfigKeyboardSelector *selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;

	switch (keys[index].keys_type) {
	case KEYS_TYPE_CAPSLOCK:
		ryosconfig_capslock_selector_set_index(priv->capslock_selector, index, keys[index].mask, keys[index].default_normal);
		roccat_multiwidget_show(priv->key_type_multiwidget, GTK_WIDGET(priv->capslock_selector));
		break;
	case KEYS_TYPE_FN:
		roccat_multiwidget_show(priv->key_type_multiwidget, GTK_WIDGET(priv->fn_selector));
		break;
	case KEYS_TYPE_NOTHING:
		roccat_multiwidget_show(priv->key_type_multiwidget, priv->nothing_selector);
		break;
	case KEYS_TYPE_MACRO:
	case KEYS_TYPE_THUMBSTER:
	case KEYS_TYPE_FUNCTION:
	case KEYS_TYPE_EASYZONE:
		ryosconfig_standard_selector_set_index(priv->standard_selector, index,
				keys[index].mask, keys[index].default_normal, keys[index].mask_easyshift, keys[index].default_easyshift);
		roccat_multiwidget_show(priv->key_type_multiwidget, GTK_WIDGET(priv->standard_selector));
		break;
	default:
		// error
		break;
	}
}

static void button_deactivate_other(RyosconfigKeyboardSelector *selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	guint i;
	GtkToggleButton *toggle_button;

	for (i = 0; i < KEYS_NUM; ++i) {
		toggle_button = GTK_TOGGLE_BUTTON(priv->keys[i]);

		if (i != index) {
			if (gtk_toggle_button_get_active(toggle_button)) {
				g_signal_handlers_block_by_func(G_OBJECT(toggle_button), toggled_cb, selector);
				gtk_toggle_button_set_active(toggle_button, FALSE);
				g_signal_handlers_unblock_by_func(G_OBJECT(toggle_button), toggled_cb, selector);
			}
		}
	}
}

static RyosLightLayer *get_active_layer(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	guint layer = ryosconfig_illumination_frame_get_layer(priv->illumination_frame);
	guint mode = ryosconfig_illumination_frame_get_mode(priv->illumination_frame);

	if (!priv->data)
		return NULL;

	if (mode == RYOS_ILLUMINATION_MODE_AUTOMATIC)
		return &priv->data->lights_automatic.layers[layer];
	else
		return &priv->data->lights_manual.layers[layer];
}

static void update_key_illumination(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	RyosLightLayer *active_layer;
	guint index;
	guint value;

	index = get_active_index(keyboard_selector);
	active_layer = get_active_layer(keyboard_selector);
	value = active_layer->keys[keys[index].primary_index];
	ryosconfig_key_illumination_selector_set_value_blocked(priv->key_illumination_selector, value);
}

static void button_update_active(RyosconfigKeyboardSelector *keyboard_selector) {
	guint index = get_active_index(keyboard_selector);

	selector_label_update(keyboard_selector, index);
	selector_show(keyboard_selector, index);
	update_key_illumination(keyboard_selector);
}

static void button_set_active(RyosconfigKeyboardSelector *selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	GtkToggleButton *toggle_button;

	set_active_index(selector, index);
	button_deactivate_other(selector, index);

	toggle_button = GTK_TOGGLE_BUTTON(priv->keys[index]);

	if (!gtk_toggle_button_get_active(toggle_button)) {
		g_signal_handlers_block_by_func(G_OBJECT(toggle_button), toggled_cb, selector);
		gtk_toggle_button_set_active(toggle_button, TRUE);
		g_signal_handlers_unblock_by_func(G_OBJECT(toggle_button), toggled_cb, selector);
	}

	button_update_active(selector);
}

static void toggled_cb(GtkToggleButton *button, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	guint index;

	index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(button), index_key));
	set_active_index(keyboard_selector, index);

	button_deactivate_other(keyboard_selector, index);
	button_update_active(keyboard_selector);
}

/* Fixing size request width
 * AspectFrame forces Table to shape, but does not correct it's size_request,
 * leaving an empty stripe on the side.
 */
static void table_size_request_cb(GtkWidget *table, GtkRequisition *requisition, gpointer user_data) {
	requisition->width = (gfloat)TABLE_HEIGHT / (gfloat)TABLE_WIDTH * (gfloat)requisition->height;
}

static GtkWidget *create_keyboard(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	guint i;
	GtkWidget *frame;
	GtkWidget *table;

	frame = gtk_aspect_frame_new(NULL, 0.0, 0.0, (gfloat)TABLE_HEIGHT / (gfloat)TABLE_WIDTH, FALSE);
	gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);

	table = gtk_table_new(TABLE_WIDTH, TABLE_HEIGHT, TRUE);
	g_signal_connect(G_OBJECT(table), "size-request", G_CALLBACK(table_size_request_cb), NULL);
	gtk_container_add(GTK_CONTAINER(frame), table);

	for (i = 0; i < KEYS_NUM; ++i) {
		priv->keys[i] = RYOSCONFIG_KEY_BUTTON(ryosconfig_key_button_new(keys[i].primary));
		g_object_set_data(G_OBJECT(priv->keys[i]), index_key, GUINT_TO_POINTER(i));
		g_signal_connect(G_OBJECT(priv->keys[i]), "toggled", G_CALLBACK(toggled_cb), keyboard_selector);

		gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(priv->keys[i]), keys[i].column, keys[i].column + keys[i].width,
				keys[i].row, keys[i].row + keys[i].height, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
	}

	return frame;
}

static gint find_index_by_type(guint type) {
	guint i;

	for (i = 0; i < KEYS_NUM; ++i)
		if (keys[i].keys_type == type)
			return i;
	return -1;
}

static void set_fn_tooltip(RyosconfigKeyboardSelector *keyboard_selector, guint value) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	gchar *text;
	gint index;

	/* assuming there's only one */
	index = find_index_by_type(KEYS_TYPE_FN);
	if (index < 0)
		return;

	text = ryosconfig_fn_selector_get_text_for_value(priv->fn_selector, value);
	gtk_widget_set_tooltip_text(GTK_WIDGET(priv->keys[index]), text);
	g_free(text);
}

static void set_capslock_tooltip(RyosconfigKeyboardSelector *keyboard_selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	gchar *text;

	text = ryosconfig_capslock_selector_get_text_for_data(priv->capslock_selector, &priv->data->standard_datas[index]);
	gtk_widget_set_tooltip_text(GTK_WIDGET(priv->keys[index]), text);
	g_free(text);
}

static void set_standard_tooltip(RyosconfigKeyboardSelector *keyboard_selector, guint index) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	gchar *standard_text;
	gchar *easyshift_text;
	gchar *text;
	
	standard_text = ryosconfig_standard_selector_get_text_for_data(priv->standard_selector, &priv->data->standard_datas[index]);
	easyshift_text = ryosconfig_standard_selector_get_text_for_data(priv->standard_selector, &priv->data->easyshift_datas[index]);
	text = g_strdup_printf("Standard: %s\nEasyshift: %s", standard_text, easyshift_text);
	gtk_widget_set_tooltip_text(GTK_WIDGET(priv->keys[index]), text);
	g_free(standard_text);
	g_free(easyshift_text);
	g_free(text);
}

static void fn_key_changed_cb(RyosconfigFnSelector *fn_selector, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	guint value;
	value = ryosconfig_fn_selector_get_value(fn_selector);
	set_fn_tooltip(keyboard_selector, value);
}

static void capslock_key_changed_cb(RyosconfigCapslockSelector *capslock_selector, gint index, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	if (index >= 0)
		set_capslock_tooltip(keyboard_selector, index);
}

static void standard_key_changed_cb(RyosconfigStandardSelector *standard_selector, gint index, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	if (index >= 0)
		set_standard_tooltip(keyboard_selector, index);
}

static gint find_index_by_data_key_type(RyosconfigKeyComboBoxData *datas, guint type) {
	guint i;
	for (i = 0; i < KEYS_NUM; ++i)
		if (datas[i].key.type == type)
			return i;
	return -1;
}

static void remap_cb(RyosconfigStandardSelector *standard_selector, gint source_index, guint old_hid, guint new_hid, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	gint target_index;

	/* find target before changing anything */
	target_index = find_index_by_data_key_type(priv->data->standard_datas, new_hid);
	if (target_index >= 0) {
		ryos_key_set_to_normal(&priv->data->standard_datas[target_index].key, old_hid);
		set_standard_tooltip(keyboard_selector, target_index);
	} else
		g_warning("Remap: Can't find target key with hid %u: just setting the key, no swapping", new_hid);

	ryos_key_set_to_normal(&priv->data->standard_datas[source_index].key, new_hid);
	set_standard_tooltip(keyboard_selector, source_index);
	if (priv->actual_index == source_index)
		ryosconfig_standard_selector_update(standard_selector);
}

static void update_keyboard_illumination(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	guint i;
	RyosLightLayer *active_layer;
	gboolean on;
	gboolean blink;
	gboolean state;

	active_layer = get_active_layer(keyboard_selector);

	if (!active_layer)
		return;

	for (i = 0; i < KEYS_NUM; ++i) {
		on = roccat_get_bit(active_layer->keys[keys[i].primary_index], RYOS_LIGHT_LAYER_KEY_BIT_ON);
		blink = roccat_get_bit(active_layer->keys[keys[i].primary_index], RYOS_LIGHT_LAYER_KEY_BIT_BLINK);
		state = (blink && !priv->periodic_blink_state) ? FALSE : on;
		ryosconfig_key_button_set_light(priv->keys[i], state);
	}
}

static void change_illumination_pointer(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	RyosLightLayer *active_layer;

	active_layer = get_active_layer(keyboard_selector);
	ryosconfig_illumination_frame_set_pointer_blocked(priv->illumination_frame, active_layer);
	update_keyboard_illumination(keyboard_selector);
	update_key_illumination(keyboard_selector);
}

static void illumination_changed_cb(RyosconfigIlluminationFrame *illumination_frame, gpointer user_data) {
	change_illumination_pointer(RYOSCONFIG_KEYBOARD_SELECTOR(user_data));
}

static gboolean layer_editor_cb(RyosconfigIlluminationFrame *illumination_frame, gpointer light_layer, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	gboolean result;
	g_signal_emit((gpointer)keyboard_selector, signals[LAYER_EDITOR], 0, light_layer, &result);
	return result;
}

static void key_illumination_changed_cb(RyosconfigKeyIlluminationSelector *selector, gpointer user_data) {
	RyosconfigKeyboardSelector *keyboard_selector = RYOSCONFIG_KEYBOARD_SELECTOR(user_data);
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	guint index = get_active_index(keyboard_selector);
	RyosLightLayer *active_layer;
	guint value;
	gboolean on;

	value = ryosconfig_key_illumination_selector_get_value(priv->key_illumination_selector);

	active_layer = get_active_layer(keyboard_selector);
	active_layer->keys[keys[index].primary_index] = value;

	on = roccat_get_bit(value, RYOS_LIGHT_LAYER_KEY_BIT_ON);
	ryosconfig_key_button_set_light(priv->keys[index], on);
}

static void create_key_type_multiwidget(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;

	priv->key_type_multiwidget = ROCCAT_MULTIWIDGET(roccat_multiwidget_new());
	priv->fn_selector = RYOSCONFIG_FN_SELECTOR(ryosconfig_fn_selector_new());
	priv->capslock_selector = RYOSCONFIG_CAPSLOCK_SELECTOR(ryosconfig_capslock_selector_new(priv->data->standard_datas));
	priv->standard_selector = RYOSCONFIG_STANDARD_SELECTOR(ryosconfig_standard_selector_new(priv->data->standard_datas, priv->data->easyshift_datas));
	priv->nothing_selector = gtk_label_new("This key does not allow settings");

	gtk_label_set_line_wrap(GTK_LABEL(priv->nothing_selector), TRUE);

	g_signal_connect(G_OBJECT(priv->fn_selector), "key-changed", G_CALLBACK(fn_key_changed_cb), keyboard_selector);
	g_signal_connect(G_OBJECT(priv->capslock_selector), "key-changed", G_CALLBACK(capslock_key_changed_cb), keyboard_selector);
	g_signal_connect(G_OBJECT(priv->standard_selector), "key-changed", G_CALLBACK(standard_key_changed_cb), keyboard_selector);
	g_signal_connect(G_OBJECT(priv->standard_selector), "remap", G_CALLBACK(remap_cb), keyboard_selector);

	roccat_multiwidget_add(priv->key_type_multiwidget, GTK_WIDGET(priv->fn_selector));
	roccat_multiwidget_add(priv->key_type_multiwidget, GTK_WIDGET(priv->capslock_selector));
	roccat_multiwidget_add(priv->key_type_multiwidget, GTK_WIDGET(priv->standard_selector));
	roccat_multiwidget_add(priv->key_type_multiwidget, priv->nothing_selector);
}

static void create_key_illumination_multiwidget(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;

	priv->key_illumination_multiwidget = ROCCAT_MULTIWIDGET(roccat_multiwidget_new());
	priv->key_illumination_box = gtk_hbox_new(FALSE, 0);
	priv->key_illumination_selector = RYOSCONFIG_KEY_ILLUMINATION_SELECTOR(ryosconfig_key_illumination_selector_new());
	priv->key_illumination_nothing = gtk_label_new("This model does not support per-key light settings");

	gtk_label_set_line_wrap(GTK_LABEL(priv->key_illumination_nothing), TRUE);

	g_signal_connect(G_OBJECT(priv->key_illumination_selector), "changed", G_CALLBACK(key_illumination_changed_cb), keyboard_selector);

	gtk_box_pack_start(GTK_BOX(priv->key_illumination_box), gtk_label_new("Light"), FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(priv->key_illumination_box), GTK_WIDGET(priv->key_illumination_selector), TRUE, TRUE, 0);

	roccat_multiwidget_add(priv->key_illumination_multiwidget, priv->key_illumination_box);
	roccat_multiwidget_add(priv->key_illumination_multiwidget, priv->key_illumination_nothing);
}

static gboolean timeout_cb(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;

	priv->periodic_blink_state = !priv->periodic_blink_state;

	update_keyboard_illumination(keyboard_selector);

	return TRUE;
}

static void start_blinking(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	if (priv->blink_timeout)
		return;
	priv->blink_timeout = g_timeout_add_seconds(1, (GSourceFunc)timeout_cb, keyboard_selector);
}

static void stop_blinking(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = keyboard_selector->priv;
	if (!priv->blink_timeout)
		return;
	g_source_remove(priv->blink_timeout);
	priv->blink_timeout = 0;
}

static void ryosconfig_keyboard_selector_init(RyosconfigKeyboardSelector *keyboard_selector) {
	RyosconfigKeyboardSelectorPrivate *priv = RYOSCONFIG_KEYBOARD_SELECTOR_GET_PRIVATE(keyboard_selector);
	keyboard_selector->priv = priv;
	GtkWidget *keyboard;
	GtkWidget *vbox;
	GtkWidget *key_frame;
	GtkWidget *hbox;
	GtkWidget *key_vbox;

	priv->data = (RyosconfigKeyboardSelectorPrivateData *)g_malloc(sizeof(RyosconfigKeyboardSelectorPrivateData));
	priv->periodic_blink_state = FALSE;
	priv->blink_timeout = 0;
	
	vbox = gtk_vbox_new(FALSE, 0);

	gtk_container_add(GTK_CONTAINER(keyboard_selector), vbox);

	priv->scroll_window = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
	gtk_scrolled_window_set_policy(priv->scroll_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(priv->scroll_window), TRUE, TRUE, 0);

	keyboard = create_keyboard(keyboard_selector);
	gtk_scrolled_window_add_with_viewport(priv->scroll_window, keyboard);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	key_frame = gtk_frame_new(NULL);
	gtk_box_pack_start(GTK_BOX(hbox), key_frame, TRUE, TRUE, 0);

	key_vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(key_frame), key_vbox);

	priv->label = GTK_LABEL(gtk_label_new(NULL));
	gtk_frame_set_label_widget(GTK_FRAME(key_frame), GTK_WIDGET(priv->label));

	create_key_type_multiwidget(keyboard_selector);
	create_key_illumination_multiwidget(keyboard_selector);

	gtk_box_pack_start(GTK_BOX(key_vbox), GTK_WIDGET(priv->key_type_multiwidget), TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(key_vbox), GTK_WIDGET(priv->key_illumination_multiwidget), TRUE, TRUE, 0);

	priv->illumination_frame = RYOSCONFIG_ILLUMINATION_FRAME(ryosconfig_illumination_frame_new());
	g_signal_connect(G_OBJECT(priv->illumination_frame), "mode-changed", G_CALLBACK(illumination_changed_cb), keyboard_selector);
	g_signal_connect(G_OBJECT(priv->illumination_frame), "layer-changed", G_CALLBACK(illumination_changed_cb), keyboard_selector);
	g_signal_connect(G_OBJECT(priv->illumination_frame), "layer-editor", G_CALLBACK(layer_editor_cb), keyboard_selector);
	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(priv->illumination_frame), TRUE, TRUE, 0);

	gtk_widget_show_all(GTK_WIDGET(keyboard_selector));

	button_set_active(keyboard_selector, 0);
}

static void finalize(GObject *object) {
	RyosconfigKeyboardSelector *selector = RYOSCONFIG_KEYBOARD_SELECTOR(object);
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	G_OBJECT_CLASS(ryosconfig_keyboard_selector_parent_class)->finalize(object);
	stop_blinking(selector);
	g_free(priv->data);
}

static void ryosconfig_keyboard_selector_class_init(RyosconfigKeyboardSelectorClass *klass) {
	GObjectClass *gobject_class;

	gobject_class = (GObjectClass*)klass;
	gobject_class->finalize = finalize;

	g_type_class_add_private(klass, sizeof(RyosconfigKeyboardSelectorPrivate));

	signals[LAYER_EDITOR] = g_signal_new("layer-editor",
			G_TYPE_FROM_CLASS(klass),
			G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
			0, NULL, NULL, g_cclosure_roccat_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
}

void ryosconfig_keyboard_selector_set_from_rkp(RyosconfigKeyboardSelector *selector, RyosRkp const *rkp) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	RyosconfigKeyboardSelectorPrivateData *data = priv->data;
	RyosconfigKeyComboBoxData *standarddata;
	RyosconfigKeyComboBoxData *easyshiftdata;
	RyosRkpData const *rkpdata;
	guint i;
	RyosKeytable *key;

	rkpdata = &rkp->data;

	for (i = 0; i < KEYS_NUM; ++i) {
		standarddata = &data->standard_datas[i];
		easyshiftdata = &data->easyshift_datas[i];
		key = &keys[i];

		if (key->macro_index != INDEX_INVALID) {
			ryos_macro_copy(&standarddata->macro, &rkpdata->macros[key->macro_index]);
			ryos_rkp_quicklaunch_copy(&standarddata->quicklaunch, &rkpdata->launchers[key->macro_index]);
			ryos_rkp_timer_copy(&standarddata->timer, &rkpdata->timers[key->macro_index]);
		}

		if (key->macro_index_easyshift != INDEX_INVALID) {
			ryos_macro_copy(&easyshiftdata->macro, &rkpdata->macros[key->macro_index_easyshift]);
			ryos_rkp_quicklaunch_copy(&easyshiftdata->quicklaunch, &rkpdata->launchers[key->macro_index_easyshift]);
			ryos_rkp_timer_copy(&easyshiftdata->timer, &rkpdata->timers[key->macro_index_easyshift]);
		}

		switch (key->keys_type) {
		case KEYS_TYPE_MACRO:
			ryos_key_copy(&standarddata->key, &rkpdata->keys_macro.keys[key->keys_index]);
			ryos_key_copy(&easyshiftdata->key, &rkpdata->keys_macro.keys[key->keys_index_easyshift]);
			ryos_rkp_talk_copy(&standarddata->talk, &rkpdata->talks[key->talk_index]);
			set_standard_tooltip(selector, i);
			break;
		case KEYS_TYPE_EASYZONE:
			ryos_key_set_to_normal(&standarddata->key, rkpdata->keys_primary.keys[key->primary_index]);
			ryos_key_copy(&easyshiftdata->key, &rkpdata->keys_easyzone.keys[key->keys_index_easyshift]);
			set_standard_tooltip(selector, i);
			break;
		case KEYS_TYPE_FUNCTION:
			ryos_key_copy(&standarddata->key, &rkpdata->keys_function.keys[key->keys_index]);
			ryos_key_copy(&easyshiftdata->key, &rkpdata->keys_function.keys[key->keys_index_easyshift]);
			set_standard_tooltip(selector, i);
			break;
		case KEYS_TYPE_THUMBSTER:
			ryos_key_copy(&standarddata->key, &rkpdata->keys_thumbster.keys[key->keys_index]);
			ryos_key_copy(&easyshiftdata->key, &rkpdata->keys_thumbster.keys[key->keys_index_easyshift]);
			ryos_rkp_talk_copy(&standarddata->talk, &rkpdata->talks[key->talk_index]);
			set_standard_tooltip(selector, i);
			break;
		case KEYS_TYPE_CAPSLOCK:
			ryos_key_set_to_normal(&standarddata->key, rkpdata->keys_extra.capslock);
			ryos_rkp_talk_copy(&standarddata->talk, &rkpdata->talks[key->talk_index]);
			set_capslock_tooltip(selector, i);
			break;
		case KEYS_TYPE_FN:
			ryosconfig_fn_selector_set_value(RYOSCONFIG_FN_SELECTOR(priv->fn_selector), rkpdata->keys_extra.fn);
			set_fn_tooltip(selector, rkpdata->keys_extra.fn);
			break;
		default:
			break;
		};
	}

	ryos_stored_lights_copy(&data->lights_automatic, &rkpdata->lights_automatic);
	ryos_stored_lights_copy(&data->lights_manual, &rkpdata->lights_manual);

	ryosconfig_illumination_frame_set_mode_blocked(priv->illumination_frame, rkp->data.light.illumination_mode);
	change_illumination_pointer(selector);

	button_update_active(selector);
}

void ryosconfig_keyboard_selector_update_rkp(RyosconfigKeyboardSelector *selector, RyosRkp *rkp) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	RyosconfigKeyboardSelectorPrivateData *data = priv->data;
	RyosKeysPrimary *keys_primary;
	RyosKeysMacro *keys_macro;
	RyosKeysThumbster *keys_thumbster;
	RyosKeysEasyzone *keys_easyzone;
	RyosKeysFunction *keys_function;
	RyosKeysExtra *keys_extra;
	RyosconfigKeyComboBoxData *standarddata;
	RyosconfigKeyComboBoxData *easyshiftdata;
	guint i;
	RyosKeytable *key;

	keys_primary = ryos_rkp_get_keys_primary(rkp);
	keys_macro = ryos_rkp_get_keys_macro(rkp);
	keys_thumbster = ryos_rkp_get_keys_thumbster(rkp);
	keys_easyzone = ryos_rkp_get_keys_easyzone(rkp);
	keys_function = ryos_rkp_get_keys_function(rkp);
	keys_extra = ryos_rkp_get_keys_extra(rkp);

	for (i = 0; i < KEYS_NUM; ++i) {
		standarddata = &data->standard_datas[i];
		easyshiftdata = &data->easyshift_datas[i];
		key = &keys[i];

		switch (key->keys_type) {
		case KEYS_TYPE_MACRO:
			ryos_key_copy(&keys_macro->keys[key->keys_index], &standarddata->key);
			ryos_key_copy(&keys_macro->keys[key->keys_index_easyshift], &easyshiftdata->key);
			ryos_rkp_set_talk(rkp, key->talk_index, &standarddata->talk);
			break;
		case KEYS_TYPE_EASYZONE:
			keys_primary->keys[key->primary_index] = standarddata->key.type;
			ryos_key_copy(&keys_easyzone->keys[key->keys_index_easyshift], &easyshiftdata->key);
			break;
		case KEYS_TYPE_FUNCTION:
			ryos_key_copy(&keys_function->keys[key->keys_index], &standarddata->key);
			ryos_key_copy(&keys_function->keys[key->keys_index_easyshift], &easyshiftdata->key);
			break;
		case KEYS_TYPE_THUMBSTER:
			ryos_key_copy(&keys_thumbster->keys[key->keys_index], &standarddata->key);
			ryos_key_copy(&keys_thumbster->keys[key->keys_index_easyshift], &easyshiftdata->key);
			ryos_rkp_set_talk(rkp, key->talk_index, &standarddata->talk);
			break;
		case KEYS_TYPE_CAPSLOCK:
			keys_extra->capslock = standarddata->key.type;
			ryos_rkp_set_talk(rkp, key->talk_index, &standarddata->talk);
			break;
		case KEYS_TYPE_FN:
			keys_extra->fn = ryosconfig_fn_selector_get_value(RYOSCONFIG_FN_SELECTOR(priv->fn_selector));
			break;
		};

		if (key->macro_index != INDEX_INVALID) {
			ryos_rkp_set_macro(rkp, key->macro_index, &standarddata->macro);
			ryos_rkp_set_quicklaunch(rkp, key->macro_index, &standarddata->quicklaunch);
			ryos_rkp_set_timer(rkp, key->macro_index, &standarddata->timer);
		}

		if (key->macro_index_easyshift != INDEX_INVALID) {
			ryos_rkp_set_macro(rkp, key->macro_index_easyshift, &easyshiftdata->macro);
			ryos_rkp_set_quicklaunch(rkp, key->macro_index_easyshift, &easyshiftdata->quicklaunch);
			ryos_rkp_set_timer(rkp, key->macro_index_easyshift, &easyshiftdata->timer);
		}
	}

	ryos_rkp_set_keys_primary(rkp, keys_primary);
	ryos_rkp_set_keys_macro(rkp, keys_macro);
	ryos_rkp_set_keys_thumbster(rkp, keys_thumbster);
	ryos_rkp_set_keys_easyzone(rkp, keys_easyzone);
	ryos_rkp_set_keys_function(rkp, keys_function);
	ryos_rkp_set_keys_extra(rkp, keys_extra);

	g_free(keys_primary);
	g_free(keys_macro);
	g_free(keys_thumbster);
	g_free(keys_easyzone);
	g_free(keys_function);
	g_free(keys_extra);

	ryos_rkp_set_lights_automatic(rkp, &priv->data->lights_automatic);
	ryos_rkp_set_lights_manual(rkp, &priv->data->lights_manual);
	ryos_rkp_set_light_illumination_mode(rkp, ryosconfig_illumination_frame_get_mode(priv->illumination_frame));
}

void ryosconfig_keyboard_selector_set_macro(RyosconfigKeyboardSelector *selector, guint macro_index, RyosMacro *macro) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	guint i;
	for (i = 0; i < KEYS_NUM; ++i) {
		if (macro_index == keys[i].macro_index) {
			ryos_key_set_to_normal(&priv->data->standard_datas[i].key, RYOS_KEY_TYPE_MACRO);
			ryos_macro_copy(&priv->data->standard_datas[i].macro, macro);
			break;
		} else if (macro_index == keys[i].macro_index_easyshift) {
			ryos_key_set_to_normal(&priv->data->easyshift_datas[i].key, RYOS_KEY_TYPE_MACRO);
			ryos_macro_copy(&priv->data->easyshift_datas[i].macro, macro);
			break;
		}
	}

	if (i >= KEYS_NUM)
		return;

	set_standard_tooltip(selector, i);
	if (get_active_index(selector) == i)
		ryosconfig_standard_selector_update(priv->standard_selector);
}

void ryosconfig_keyboard_selector_set_device_type(RyosconfigKeyboardSelector *selector, RoccatDevice const *device) {
	RyosconfigKeyboardSelectorPrivate *priv = selector->priv;
	switch (gaminggear_device_get_product_id(GAMINGGEAR_DEVICE(device))) {
	case USB_DEVICE_ID_ROCCAT_RYOS_MK:
	case USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW:
		roccat_multiwidget_show(priv->key_illumination_multiwidget, GTK_WIDGET(priv->key_illumination_nothing));
		stop_blinking(selector);
		break;
	case USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO:
		roccat_multiwidget_show(priv->key_illumination_multiwidget, GTK_WIDGET(priv->key_illumination_box));
		start_blinking(selector);
		break;
	default:
		break;
	}
	ryosconfig_illumination_frame_set_device_type(selector->priv->illumination_frame, device);
}
