diff options
| author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2006-04-02 00:10:28 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-02 00:10:28 -0500 |
| commit | b9ec4e109d7a342e83e1210e05797222e36555c3 (patch) | |
| tree | 47ff5cb19c3b43f9907006e7b491df547f29b71e | |
| parent | 53a2670cd9611cf7c3b3bf9875b0b4041160fa60 (diff) | |
Input: add support for Braille devices
- Add KEY_BRL_* input keys and K_BRL_* keycodes;
- Add emulation of how braille keyboards usually combine braille dots
to the console keyboard driver;
- Add handling of unicode U+28xy diacritics.
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
| -rw-r--r-- | drivers/char/keyboard.c | 118 | ||||
| -rw-r--r-- | include/linux/input.h | 9 | ||||
| -rw-r--r-- | include/linux/kbd_kern.h | 2 | ||||
| -rw-r--r-- | include/linux/keyboard.h | 13 |
4 files changed, 125 insertions, 17 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 8b603b2d1c42..935670a3cd98 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
| @@ -74,7 +74,7 @@ void compute_shiftstate(void); | |||
| 74 | k_self, k_fn, k_spec, k_pad,\ | 74 | k_self, k_fn, k_spec, k_pad,\ |
| 75 | k_dead, k_cons, k_cur, k_shift,\ | 75 | k_dead, k_cons, k_cur, k_shift,\ |
| 76 | k_meta, k_ascii, k_lock, k_lowercase,\ | 76 | k_meta, k_ascii, k_lock, k_lowercase,\ |
| 77 | k_slock, k_dead2, k_ignore, k_ignore | 77 | k_slock, k_dead2, k_brl, k_ignore |
| 78 | 78 | ||
| 79 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | 79 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, |
| 80 | char up_flag, struct pt_regs *regs); | 80 | char up_flag, struct pt_regs *regs); |
| @@ -100,7 +100,7 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | |||
| 100 | const int max_vals[] = { | 100 | const int max_vals[] = { |
| 101 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | 101 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, |
| 102 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | 102 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, |
| 103 | 255, NR_LOCK - 1, 255 | 103 | 255, NR_LOCK - 1, 255, NR_BRL - 1 |
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | const int NR_TYPES = ARRAY_SIZE(max_vals); | 106 | const int NR_TYPES = ARRAY_SIZE(max_vals); |
| @@ -126,7 +126,7 @@ static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ | |||
| 126 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 126 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
| 127 | static int dead_key_next; | 127 | static int dead_key_next; |
| 128 | static int npadch = -1; /* -1 or number assembled on pad */ | 128 | static int npadch = -1; /* -1 or number assembled on pad */ |
| 129 | static unsigned char diacr; | 129 | static unsigned int diacr; |
| 130 | static char rep; /* flag telling character repeat */ | 130 | static char rep; /* flag telling character repeat */ |
| 131 | 131 | ||
| 132 | static unsigned char ledstate = 0xff; /* undefined */ | 132 | static unsigned char ledstate = 0xff; /* undefined */ |
| @@ -394,22 +394,30 @@ void compute_shiftstate(void) | |||
| 394 | * Otherwise, conclude that DIACR was not combining after all, | 394 | * Otherwise, conclude that DIACR was not combining after all, |
| 395 | * queue it and return CH. | 395 | * queue it and return CH. |
| 396 | */ | 396 | */ |
| 397 | static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) | 397 | static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) |
| 398 | { | 398 | { |
| 399 | int d = diacr; | 399 | unsigned int d = diacr; |
| 400 | unsigned int i; | 400 | unsigned int i; |
| 401 | 401 | ||
| 402 | diacr = 0; | 402 | diacr = 0; |
| 403 | 403 | ||
| 404 | for (i = 0; i < accent_table_size; i++) { | 404 | if ((d & ~0xff) == BRL_UC_ROW) { |
| 405 | if (accent_table[i].diacr == d && accent_table[i].base == ch) | 405 | if ((ch & ~0xff) == BRL_UC_ROW) |
| 406 | return accent_table[i].result; | 406 | return d | ch; |
| 407 | } else { | ||
| 408 | for (i = 0; i < accent_table_size; i++) | ||
| 409 | if (accent_table[i].diacr == d && accent_table[i].base == ch) | ||
| 410 | return accent_table[i].result; | ||
| 407 | } | 411 | } |
| 408 | 412 | ||
| 409 | if (ch == ' ' || ch == d) | 413 | if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) |
| 410 | return d; | 414 | return d; |
| 411 | 415 | ||
| 412 | put_queue(vc, d); | 416 | if (kbd->kbdmode == VC_UNICODE) |
| 417 | to_utf8(vc, d); | ||
| 418 | else if (d < 0x100) | ||
| 419 | put_queue(vc, d); | ||
| 420 | |||
| 413 | return ch; | 421 | return ch; |
| 414 | } | 422 | } |
| 415 | 423 | ||
| @@ -419,7 +427,10 @@ static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) | |||
| 419 | static void fn_enter(struct vc_data *vc, struct pt_regs *regs) | 427 | static void fn_enter(struct vc_data *vc, struct pt_regs *regs) |
| 420 | { | 428 | { |
| 421 | if (diacr) { | 429 | if (diacr) { |
| 422 | put_queue(vc, diacr); | 430 | if (kbd->kbdmode == VC_UNICODE) |
| 431 | to_utf8(vc, diacr); | ||
| 432 | else if (diacr < 0x100) | ||
| 433 | put_queue(vc, diacr); | ||
| 423 | diacr = 0; | 434 | diacr = 0; |
| 424 | } | 435 | } |
| 425 | put_queue(vc, 13); | 436 | put_queue(vc, 13); |
| @@ -615,7 +626,7 @@ static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, s | |||
| 615 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); | 626 | printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); |
| 616 | } | 627 | } |
| 617 | 628 | ||
| 618 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 629 | static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) |
| 619 | { | 630 | { |
| 620 | if (up_flag) | 631 | if (up_flag) |
| 621 | return; /* no action, if this is a key release */ | 632 | return; /* no action, if this is a key release */ |
| @@ -628,7 +639,10 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
| 628 | diacr = value; | 639 | diacr = value; |
| 629 | return; | 640 | return; |
| 630 | } | 641 | } |
| 631 | put_queue(vc, value); | 642 | if (kbd->kbdmode == VC_UNICODE) |
| 643 | to_utf8(vc, value); | ||
| 644 | else if (value < 0x100) | ||
| 645 | put_queue(vc, value); | ||
| 632 | } | 646 | } |
| 633 | 647 | ||
| 634 | /* | 648 | /* |
| @@ -636,13 +650,23 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
| 636 | * dead keys modifying the same character. Very useful | 650 | * dead keys modifying the same character. Very useful |
| 637 | * for Vietnamese. | 651 | * for Vietnamese. |
| 638 | */ | 652 | */ |
| 639 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 653 | static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) |
| 640 | { | 654 | { |
| 641 | if (up_flag) | 655 | if (up_flag) |
| 642 | return; | 656 | return; |
| 643 | diacr = (diacr ? handle_diacr(vc, value) : value); | 657 | diacr = (diacr ? handle_diacr(vc, value) : value); |
| 644 | } | 658 | } |
| 645 | 659 | ||
| 660 | static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
| 661 | { | ||
| 662 | k_unicode(vc, value, up_flag, regs); | ||
| 663 | } | ||
| 664 | |||
| 665 | static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
| 666 | { | ||
| 667 | k_deadunicode(vc, value, up_flag, regs); | ||
| 668 | } | ||
| 669 | |||
| 646 | /* | 670 | /* |
| 647 | * Obsolete - for backwards compatibility only | 671 | * Obsolete - for backwards compatibility only |
| 648 | */ | 672 | */ |
| @@ -650,7 +674,7 @@ static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct | |||
| 650 | { | 674 | { |
| 651 | static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; | 675 | static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; |
| 652 | value = ret_diacr[value]; | 676 | value = ret_diacr[value]; |
| 653 | k_dead2(vc, value, up_flag, regs); | 677 | k_deadunicode(vc, value, up_flag, regs); |
| 654 | } | 678 | } |
| 655 | 679 | ||
| 656 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | 680 | static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) |
| @@ -835,6 +859,62 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc | |||
| 835 | } | 859 | } |
| 836 | } | 860 | } |
| 837 | 861 | ||
| 862 | /* by default, 300ms interval for combination release */ | ||
| 863 | static long brl_timeout = 300; | ||
| 864 | MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); | ||
| 865 | module_param(brl_timeout, long, 0644); | ||
| 866 | static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) | ||
| 867 | { | ||
| 868 | static unsigned pressed,committing; | ||
| 869 | static unsigned long releasestart; | ||
| 870 | |||
| 871 | if (kbd->kbdmode != VC_UNICODE) { | ||
| 872 | if (!up_flag) | ||
| 873 | printk("keyboard mode must be unicode for braille patterns\n"); | ||
| 874 | return; | ||
| 875 | } | ||
| 876 | |||
| 877 | if (!value) { | ||
| 878 | k_unicode(vc, BRL_UC_ROW, up_flag, regs); | ||
| 879 | return; | ||
| 880 | } | ||
| 881 | |||
| 882 | if (value > 8) | ||
| 883 | return; | ||
| 884 | |||
| 885 | if (brl_timeout < 0) { | ||
| 886 | k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs); | ||
| 887 | return;< | ||
