From 166a7de4cf94a78c34040b47a929a72d12f2945f Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 13 Jan 2012 07:38:40 +0100 Subject: input: allow unicode keys and reassign internal key codes This moves all key codes above the highest valid unicode code point (which is 0x10FFFF). All key codes below MP_KEY_BASE now directly map to unicode (KEY_ENTER is 13, carriage return). Configuration files (input.conf) can contain unicode characters in UTF-8 to map non-ASCII characters/keys. This shouldn't change anything user visible, except that "direct key codes" (as used in input.conf) will change their meaning. Parts of the bstr functions taken from libavutil's GET_UTF8 and slightly modified. --- bstr.c | 32 ++++++++++++++++++++++++++++++++ bstr.h | 13 +++++++++++++ input/input.c | 32 +++++++++++++++++++++++++------- input/keycodes.h | 38 +++++++++++++++++++------------------- mp_fifo.c | 10 ++++++++++ mp_fifo.h | 3 +++ osdep/getch2.c | 2 +- 7 files changed, 103 insertions(+), 27 deletions(-) diff --git a/bstr.c b/bstr.c index 219c136d7c..0c46b1d9b0 100644 --- a/bstr.c +++ b/bstr.c @@ -201,3 +201,35 @@ int bstr_sscanf(struct bstr str, const char *format, ...) talloc_free(ptr); return ret; } + +int bstr_parse_utf8_code_length(unsigned char b) +{ + if (b < 128) + return 1; + int bytes = 7 - av_log2(b ^ 255); + return (bytes >= 2 && bytes <= 4) ? bytes : -1; +} + +int bstr_decode_utf8(struct bstr s, struct bstr *out_next) +{ + if (s.len == 0) + return -1; + unsigned int codepoint = s.start[0]; + s.start++; s.len--; + if (codepoint >= 128) { + int bytes = bstr_parse_utf8_code_length(codepoint); + if (bytes < 0 || s.len < bytes - 1) + return -1; + codepoint &= 127 >> bytes; + for (int n = 1; n < bytes; n++) { + int tmp = s.start[0]; + if ((tmp & 0xC0) != 0x80) + return -1; + codepoint = (codepoint << 6) | (tmp & ~0xC0); + s.start++; s.len--; + } + } + if (out_next) + *out_next = s; + return codepoint; +} diff --git a/bstr.h b/bstr.h index 1344f0d443..8b1644cac0 100644 --- a/bstr.h +++ b/bstr.h @@ -69,6 +69,19 @@ double bstrtod(struct bstr str, struct bstr *rest); void bstr_lower(struct bstr str); int bstr_sscanf(struct bstr str, const char *format, ...); +// Decode the UTF-8 code point at the start of the string,, and return the +// character. +// After calling this function, *out_next will point to the next character. +// out_next can be NULL. +// On error, -1 is returned, and *out_next is not modified. +int bstr_decode_utf8(struct bstr str, struct bstr *out_next); + +// Return the length of the UTF-8 sequence that starts with the given byte. +// Given a string char *s, the next UTF-8 code point is to be expected at +// s + bstr_parse_utf8_code_length(s[0]) +// On error, -1 is returned. On success, it returns a value in the range [1, 4]. +int bstr_parse_utf8_code_length(unsigned char b); + static inline struct bstr bstr_cut(struct bstr str, int n) { if (n > str.len) diff --git a/input/input.c b/input/input.c index cde1b5e027..cc967bb4fa 100644 --- a/input/input.c +++ b/input/input.c @@ -38,6 +38,7 @@ #include "keycodes.h" #include "osdep/timer.h" #include "libavutil/avstring.h" +#include "libavutil/common.h" #include "mp_msg.h" #include "m_config.h" #include "m_option.h" @@ -649,6 +650,17 @@ static const m_option_t mp_input_opts[] = { static int default_cmd_func(int fd, char *buf, int l); +// Encode the unicode codepoint as UTF-8, and append to the end of the +// talloc'ed buffer. +static char *append_utf8_buffer(char *buffer, uint32_t codepoint) +{ + char data[8]; + uint8_t tmp; + char *output = data; + PUT_UTF8(codepoint, tmp, *output++ = tmp;); + return talloc_strndup_append_buffer(buffer, data, output - data); +} + static char *get_key_name(int key, char *ret) { for (int i = 0; modifier_names[i].name; i++) { @@ -663,8 +675,9 @@ static char *get_key_name(int key, char *ret) return talloc_asprintf_append_buffer(ret, "%s", key_names[i].name); } - if (isascii(key)) - return talloc_asprintf_append_buffer(ret, "%c", key); + // printable, and valid unicode range + if (key >= 32 && key <= 0x10FFFF) + return append_utf8_buffer(ret, key); // Print the hex key code return talloc_asprintf_append_buffer(ret, "%#-8x", key); @@ -1173,7 +1186,7 @@ static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) * shift modifier is still kept for special keys like arrow keys. */ int unmod = code & ~KEY_MODIFIER_MASK; - if (unmod < 256 && unmod != KEY_ENTER && unmod != KEY_TAB) + if (unmod >= 32 && unmod < MP_KEY_BASE) code &= ~KEY_MODIFIER_SHIFT; if (code & MP_KEY_DOWN) { @@ -1491,10 +1504,15 @@ int mp_input_get_key_from_name(const char *name) found: name = p + 1; } - int len = strlen(name); - if (len == 1) // Direct key code - return (unsigned char)name[0] + modifiers; - else if (len > 2 && strncasecmp("0x", name, 2) == 0) + + struct bstr bname = bstr(name); + + struct bstr rest; + int code = bstr_decode_utf8(bname, &rest); + if (code >= 0 && rest.len == 0) + return code + modifiers; + + if (bstr_startswith0(bname, "0x")) return strtol(name, NULL, 16) + modifiers; for (int i = 0; key_names[i].name != NULL; i++) { diff --git a/input/keycodes.h b/input/keycodes.h index 45e7ec7d4b..2467f31685 100644 --- a/input/keycodes.h +++ b/input/keycodes.h @@ -21,19 +21,16 @@ #ifndef MPLAYER_KEYCODES_H #define MPLAYER_KEYCODES_H +#define MP_KEY_BASE (1<<21) + // For appleir.c which includes another header with KEY_ENTER etc defines #ifndef AR_DEFINES_ONLY #define KEY_ENTER 13 #define KEY_TAB 9 -#define KEY_BASE 0x100 - -/* Function keys */ -#define KEY_F (KEY_BASE+64) - /* Control keys */ -#define KEY_CTRL (KEY_BASE) +#define KEY_CTRL (MP_KEY_BASE) #define KEY_BACKSPACE (KEY_CTRL+0) #define KEY_DELETE (KEY_CTRL+1) #define KEY_INSERT (KEY_CTRL+2) @@ -52,14 +49,14 @@ #define KEY_PGDWN KEY_PAGE_DOWN /* Cursor movement */ -#define KEY_CRSR (KEY_BASE+16) +#define KEY_CRSR (MP_KEY_BASE+0x10) #define KEY_RIGHT (KEY_CRSR+0) #define KEY_LEFT (KEY_CRSR+1) #define KEY_DOWN (KEY_CRSR+2) #define KEY_UP (KEY_CRSR+3) /* Multimedia keyboard/remote keys */ -#define KEY_MM_BASE (0x100+384) +#define KEY_MM_BASE (MP_KEY_BASE+0x20) #define KEY_POWER (KEY_MM_BASE+0) #define KEY_MENU (KEY_MM_BASE+1) #define KEY_PLAY (KEY_MM_BASE+2) @@ -74,8 +71,11 @@ #define KEY_VOLUME_DOWN (KEY_MM_BASE+11) #define KEY_MUTE (KEY_MM_BASE+12) +/* Function keys */ +#define KEY_F (MP_KEY_BASE+0x40) + /* Keypad keys */ -#define KEY_KEYPAD (KEY_BASE+32) +#define KEY_KEYPAD (MP_KEY_BASE+0x60) #define KEY_KP0 (KEY_KEYPAD+0) #define KEY_KP1 (KEY_KEYPAD+1) #define KEY_KP2 (KEY_KEYPAD+2) @@ -93,7 +93,7 @@ // Joystick input module -#define JOY_BASE (0x100+128) +#define JOY_BASE (MP_KEY_BASE+0x70) #define JOY_AXIS0_PLUS (JOY_BASE+0) #define JOY_AXIS0_MINUS (JOY_BASE+1) #define JOY_AXIS1_PLUS (JOY_BASE+2) @@ -115,7 +115,7 @@ #define JOY_AXIS9_PLUS (JOY_BASE+18) #define JOY_AXIS9_MINUS (JOY_BASE+19) -#define JOY_BTN_BASE ((0x100+148)|MP_NO_REPEAT_KEY) +#define JOY_BTN_BASE ((MP_KEY_BASE+0x90)|MP_NO_REPEAT_KEY) #define JOY_BTN0 (JOY_BTN_BASE+0) #define JOY_BTN1 (JOY_BTN_BASE+1) #define JOY_BTN2 (JOY_BTN_BASE+2) @@ -129,7 +129,7 @@ // Mouse events from VOs -#define MOUSE_BASE ((0x100+256)|MP_NO_REPEAT_KEY) +#define MOUSE_BASE ((MP_KEY_BASE+0xA0)|MP_NO_REPEAT_KEY) #define MOUSE_BTN0 (MOUSE_BASE+0) #define MOUSE_BTN1 (MOUSE_BASE+1) #define MOUSE_BTN2 (MOUSE_BASE+2) @@ -152,7 +152,7 @@ #define MOUSE_BTN19 (MOUSE_BASE+19) #define MOUSE_BTN_END (MOUSE_BASE+20) -#define MOUSE_BASE_DBL (0x300|MP_NO_REPEAT_KEY) +#define MOUSE_BASE_DBL ((MP_KEY_BASE+0xC0)|MP_NO_REPEAT_KEY) #define MOUSE_BTN0_DBL (MOUSE_BASE_DBL+0) #define MOUSE_BTN1_DBL (MOUSE_BASE_DBL+1) #define MOUSE_BTN2_DBL (MOUSE_BASE_DBL+2) @@ -179,7 +179,7 @@ #endif // AR_DEFINES_ONLY // Apple Remote input module -#define AR_BASE 0x500 +#define AR_BASE (MP_KEY_BASE+0xE0) #define AR_PLAY (AR_BASE + 0) #define AR_PLAY_HOLD (AR_BASE + 1) #define AR_NEXT (AR_BASE + 2) @@ -195,14 +195,14 @@ /* Special keys */ -#define KEY_INTERN (0x1000) +#define KEY_INTERN (MP_KEY_BASE+0x1000) #define KEY_CLOSE_WIN (KEY_INTERN+0) /* Modifiers added to individual keys */ -#define KEY_MODIFIER_SHIFT 0x2000 -#define KEY_MODIFIER_CTRL 0x4000 -#define KEY_MODIFIER_ALT 0x8000 -#define KEY_MODIFIER_META 0x10000 +#define KEY_MODIFIER_SHIFT (1<<22) +#define KEY_MODIFIER_CTRL (1<<23) +#define KEY_MODIFIER_ALT (1<<24) +#define KEY_MODIFIER_META (1<<25) #endif // AR_DEFINES_ONLY diff --git a/mp_fifo.c b/mp_fifo.c index ffb3608fbf..701b7a0bc3 100644 --- a/mp_fifo.c +++ b/mp_fifo.c @@ -67,3 +67,13 @@ void mplayer_put_key(struct mp_fifo *fifo, int code) fifo->last_down_time = now; } } + +void mplayer_put_key_utf8(struct mp_fifo *fifo, int mods, struct bstr t) +{ + while (t.len) { + int code = bstr_decode_utf8(t, &t); + if (code < 0) + break; + mplayer_put_key(fifo, code | mods); + } +} diff --git a/mp_fifo.h b/mp_fifo.h index 01c1fb0c37..aa7fde0f29 100644 --- a/mp_fifo.h +++ b/mp_fifo.h @@ -19,8 +19,11 @@ #ifndef MPLAYER_MP_FIFO_H #define MPLAYER_MP_FIFO_H +#include "bstr.h" + struct mp_fifo; void mplayer_put_key(struct mp_fifo *fifo, int code); +void mplayer_put_key_utf8(struct mp_fifo *fifo, int mods, struct bstr code); // Can be freed with talloc_free() struct input_ctx; struct MPOpts; diff --git a/osdep/getch2.c b/osdep/getch2.c index 81d13d9d7b..f421bdea7e 100644 --- a/osdep/getch2.c +++ b/osdep/getch2.c @@ -225,7 +225,7 @@ void getch2(struct mp_fifo *fifo) } if ((c == '[' || c == 'O') && getch2_len >= 3) { int c = getch2_buf[2]; - const short ctable[] = { + const int ctable[] = { KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, 0, KEY_END, KEY_PGDWN, KEY_HOME, KEY_PGUP, 0, 0, KEY_INS, 0, 0, 0, KEY_F+1, KEY_F+2, KEY_F+3, KEY_F+4}; -- cgit v1.2.3