~mil/ppbbq10

815c0dbd4b773b484b7374bae3a05861b603474d — Miles Alan 3 years ago ec4348e
Implement tap modifiers
1 files changed, 86 insertions(+), 71 deletions(-)

M ppbbq10.c
M ppbbq10.c => ppbbq10.c +86 -71
@@ 49,9 49,12 @@

/* structs */
struct ppbbq10_data {
	unsigned int is_symed;
	unsigned short keymap_norm[NUM_KEYCODES];
	short keymap_sym[NUM_KEYCODES];
	unsigned short int mod_held;
	unsigned short int mod_tapmodifier; // TODO: []mod_tapmodifier for multiple prefixes
	unsigned int layer;
	short layer_0[NUM_KEYCODES];
	short layer_1[NUM_KEYCODES];

	struct i2c_client *client;
	struct input_dev *input;
};


@@ 73,7 76,7 @@ static int ppbbq10_write_reg(struct ppbbq10_data *drv_data, u8 reg);


/* variables */
static unsigned short keymap_norm[NUM_KEYCODES] = {
static unsigned short layer_0[NUM_KEYCODES] = {
	[0x01] = KEY_UP,
	[0x02] = KEY_DOWN,
	[0x03] = KEY_LEFT,


@@ 84,6 87,7 @@ static unsigned short keymap_norm[NUM_KEYCODES] = {
	[26] = KEY_LEFTALT,
	[27] = KEY_LEFTSHIFT,
	[28] = KEY_LEFTCTRL,
	[29] = KEY_YEN,
	['A'] = KEY_A,
	['B'] = KEY_B,
	['C'] = KEY_C,


@@ 111,12 115,12 @@ static unsigned short keymap_norm[NUM_KEYCODES] = {
	['Y'] = KEY_Y,
	['Z'] = KEY_Z,
	[' '] = KEY_SPACE,
	['~'] = KEY_0,
	['$'] = KEY_GRAVE,
	['~'] = KEY_ESC,
	['$'] = KEY_TAB,
	['\b'] = KEY_BACKSPACE,
	['\n'] = KEY_ENTER,
};
static short keymap_sym[NUM_KEYCODES] = {
static short layer_1[NUM_KEYCODES] = {
	[0x01] = KEY_UP,
	[0x02] = KEY_DOWN,
	[0x03] = KEY_LEFT,


@@ 127,37 131,39 @@ static short keymap_sym[NUM_KEYCODES] = {
	[26] = KEY_LEFTALT,
	[27] = KEY_LEFTSHIFT,
	[28] = KEY_LEFTCTRL,
	['A'] = KEY_A,
	[29] = KEY_YEN,
	['A'] = KEY_8 * -1, // (*)
	['B'] = KEY_1 * -1, // (!)
	['C'] = KEY_9,
	['D'] = KEY_5,
	['E'] = KEY_2,
	['F'] = KEY_6,
	['G'] = KEY_G,
	['H'] = KEY_H,
	['I'] = KEY_I,
	['J'] = KEY_J,
	['K'] = KEY_K,
	['L'] = KEY_L,
	['M'] = KEY_M,
	['N'] = KEY_N,
	['O'] = KEY_O,
	['P'] = KEY_P,
	['Q'] = KEY_Q,
	['G'] = KEY_SLASH,
	['H'] = KEY_SEMICOLON * -1, // (:)
	['I'] = KEY_MINUS,
	['J'] = KEY_SEMICOLON,
	['K'] = KEY_APOSTROPHE,
	['L'] = KEY_APOSTROPHE * -1, // (")
	['M'] = KEY_DOT,
	['N'] = KEY_COMMA,
	['O'] = KEY_EQUAL * -1, // (+)
	['P'] = KEY_2 * -1, // (@)
	['Q'] = KEY_3 * -1, // (#)
	['R'] = KEY_3,
	['S'] = KEY_4,
	['T'] = KEY_T,
	['U'] = KEY_U,
	['T'] = KEY_9 * -1, // (()
	['U'] = KEY_MINUS * -1, // (_)
	['W'] = KEY_1,
	['V'] = KEY_V,
	['V'] = KEY_SLASH * -1, // (?)
	['X'] = KEY_8,
	['Y'] = KEY_Y,
	['Y'] = KEY_0 * -1, // ())
	['Z'] = KEY_7,
	[' '] = KEY_SPACE,
	['~'] = KEY_0,
	['$'] = KEY_GRAVE,
	['\b'] = KEY_BACKSPACE,
	['\n'] = KEY_ENTER,

	[' '] = KEY_DOWN,
	['~'] = KEY_UP,
	['$'] = KEY_LEFT,
	['\b'] = KEY_TAB,
	['\n'] = KEY_RIGHT,
};
static struct i2c_board_info ppbbq10_i2c_board_info[] __initdata = {
	{ I2C_BOARD_INFO("ppbbq10", 0x1f), /*.irq = gpio_to_irq(11)*/ }


@@ 279,9 285,9 @@ ppbbq10_probe(struct i2c_client *client)
		return -ENOMEM;

	drv_data->client = client;
	memcpy(drv_data->keymap_norm, keymap_norm, sizeof(drv_data->keymap_norm));
	memcpy(drv_data->keymap_sym, keymap_sym, sizeof(drv_data->keymap_sym));
	drv_data->is_symed = 0;
	memcpy(drv_data->layer_0, layer_0, sizeof(drv_data->layer_0));
	memcpy(drv_data->layer_1, layer_1, sizeof(drv_data->layer_1));
	drv_data->layer = 0;

	error = ppbbq10_write_reg(drv_data, REG_RST);
	if (error)


@@ 318,20 324,23 @@ ppbbq10_probe(struct i2c_client *client)
		return -ENOMEM;

	drv_data->input = input;
	drv_data->mod_held = 0;
	drv_data->mod_tapmodifier = 0;
	drv_data->layer = 0;

	input->name = client->name;
	input->id.bustype = BUS_I2C;
	input->id.vendor  = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0001;
	input->keycode = drv_data->keymap_norm;
	input->keycodesize = sizeof(drv_data->keymap_norm[0]);
	input->keycodemax = ARRAY_SIZE(drv_data->keymap_norm) + ARRAY_SIZE(drv_data->keymap_sym) ;
	input->keycode = drv_data->layer_0;
	input->keycodesize = sizeof(drv_data->layer_0[0]);
	input->keycodemax = ARRAY_SIZE(drv_data->layer_0) + ARRAY_SIZE(drv_data->layer_1) ;

	for (i = 0; i < NUM_KEYCODES; i++)
		__set_bit(drv_data->keymap_norm[i], input->keybit);
		__set_bit(drv_data->layer_0[i], input->keybit);
	for (i = 0; i < NUM_KEYCODES; i++)
		__set_bit(drv_data->keymap_sym[i], input->keybit);
		__set_bit(drv_data->layer_1[i], input->keybit);

	__clear_bit(KEY_RESERVED, input->keybit);



@@ 363,7 372,6 @@ ppbbq10_read_fifo(struct ppbbq10_data *drv_data)
{
	struct input_dev *input = drv_data->input;
	struct i2c_client *client = drv_data->client;
	unsigned int keycode;
	u8 data[2];
	u8 count;
	int error;


@@ 387,6 395,9 @@ ppbbq10_read_fifo(struct ppbbq10_data *drv_data)
			return;
		}
		count -= 1;

		if (data[0] == STATE_PRESS || data[0] == STATE_RELEASE && data[1] != 29)
			input_event(input, EV_MSC, MSC_SCAN, data[1]);
		ppbbq10_report_keyevent(drv_data, data[0], data[1]);
	}



@@ 416,47 427,51 @@ ppbbq10_read_reg(struct ppbbq10_data *drv_data, u8 reg, u8 *buf, u8 len)
}

static void
ppbbq10_report_keyevent(struct ppbbq10_data *drv_data, u8 keystate, u8 keycode)
ppbbq10_report_keyevent(struct ppbbq10_data *drv_data, u8 key_state, u8 key_code)
{
	unsigned int key_mapped;
	int send_shift = 0;
	printk(KERN_INFO "%s key %d/%c, state: %d\n", __func__, key_code, key_code, key_state);

	printk(KERN_INFO "%s key %d/%c, state: %d\n", __func__, keycode, keycode, keystate);

	// Determine key_mapped
	if (drv_data->is_symed) {
		send_shift = drv_data->keymap_sym[keycode] < 0;
		key_mapped = abs(drv_data->keymap_sym[keycode]);
		if (drv_data->is_symed && keystate == STATE_RELEASE) drv_data->is_symed = 0;
		printk(KERN_INFO "Sending sym'd: %s key %d/%c, state: %d and !! %d and is_shifted %d\n", __func__, keycode, keycode, keystate, drv_data->keymap_sym[keycode], send_shift);
	// Map raw key_code to mapped key, if sym is tapped modifier or held,
	// prime shift as the tapped modifier is mapped key < 0
	if (drv_data->mod_held == KEY_YEN || drv_data->mod_tapmodifier == KEY_YEN) {
		key_mapped = abs(drv_data->layer_1[key_code]);
		drv_data->mod_tapmodifier = drv_data->layer_1[key_code] < 0 ? KEY_LEFTSHIFT : 0;
	} else {
		key_mapped = drv_data->keymap_norm[keycode];
		key_mapped = drv_data->layer_0[key_code];
	}

	// Reset is_symed after 1 keypress
	if (drv_data->is_symed && keystate == STATE_RELEASE) drv_data->is_symed = 0;

	// Symbol layer tap, activates symbol for next pressed key
	if (keycode == 29 && keystate == STATE_RELEASE) {
		printk(KERN_INFO "SYM press - next key symbol.\n");
		drv_data->is_symed = 1;
	} else if (keystate == STATE_PRESS || keystate == STATE_RELEASE) {
		input_event(drv_data->input, EV_MSC, MSC_SCAN, key_mapped);
		if (key_mapped == KEY_UNKNOWN) {
			pr_warn("%s code 0x%02X UNKNOWN\n", __func__, key_mapped);
		} else if (drv_data->is_symed && send_shift) {
			ppbbq10_report_keyevent(drv_data, STATE_PRESS, 27);
			usleep_range(10, 20);
			ppbbq10_report_keyevent(drv_data, STATE_HOLD, 27);
			usleep_range(10, 20);
			input_report_key(drv_data->input, key_mapped, keystate == STATE_PRESS);
			usleep_range(10, 20);
			input_report_key(drv_data->input, key_mapped, keystate == STATE_RELEASE);
			usleep_range(10, 20);
			ppbbq10_report_keyevent(drv_data, STATE_RELEASE, 27);
		} else if ((drv_data->is_symed&& !send_shift) || !drv_data->is_symed) {
			input_report_key(drv_data->input, key_mapped, keystate == STATE_PRESS);
	// If pressing a modifier
	if (key_mapped == KEY_UNKNOWN) {
		pr_warn("%s code 0x%02X UNKNOWN - not mapped\n", __func__, key_mapped);
	} else if (
		key_mapped == KEY_LEFTALT ||
		key_mapped == KEY_LEFTSHIFT ||
		key_mapped == KEY_LEFTCTRL ||
		key_mapped == KEY_YEN
	) {
		if (key_mapped != KEY_YEN && key_state != STATE_HOLD) {
			printk(KERN_INFO "Registering modifier key: [%c], e.g. keymapped [%d] with state [%d]\n", key_code, key_mapped, key_state);
			input_report_key(drv_data->input, key_mapped, key_state == STATE_PRESS);
		}

		if (key_state == STATE_HOLD) {
			drv_data->mod_held = key_mapped;
		} else if (key_state == STATE_RELEASE && drv_data->mod_held == 0) {
			drv_data->mod_tapmodifier = key_mapped;
		} else if (key_state == STATE_RELEASE) {
			drv_data->mod_held = 0;
		}
	} else if (drv_data->mod_tapmodifier && key_state == STATE_RELEASE) {
		printk(KERN_INFO "Registering key [%c] with tap modifier [%d]\n", key_code, drv_data->mod_tapmodifier);
		input_report_key(drv_data->input, drv_data->mod_tapmodifier, 1);
		input_report_key(drv_data->input, key_mapped, 1);
		input_report_key(drv_data->input, key_mapped, 0);
		input_report_key(drv_data->input, drv_data->mod_tapmodifier, 0);
		drv_data->mod_tapmodifier = 0;
	} else if (drv_data->mod_tapmodifier == 0 && key_state != STATE_HOLD) {
		printk(KERN_INFO "Registering key normally: [%c] w state [%d]\n", key_code, key_state);
		input_report_key(drv_data->input, key_mapped, key_state == STATE_PRESS);
	}
}