From a7eb9b0fbeeaa24d803355fd90d462809916a2d8 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Thu, 23 May 2013 13:25:42 -0400 Subject: [PATCH] Don't apply keyboard decoding to unread-command-events. * src/keyboard.c: Apply keyboard decoding only to events that come directly from the tty, not from unread-command-events (bug#14368). (read_event_from_main_queue): New function, extracted from read_char). (read_decoded_char): Remove. (read_decoded_event_from_main_queue): New function to replace it. (read_char): Use it. (read_key_sequence): Use read_char rather than read_decoded_char. Fixes: debbugs:14403 --- src/ChangeLog | 8 ++ src/keyboard.c | 291 +++++++++++++++++++++++++++---------------------- 2 files changed, 170 insertions(+), 129 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 8f97659db33..1d2af4b2a7d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,13 @@ 2013-05-23 Stefan Monnier + * keyboard.c: Apply keyboard decoding only to events that come directly + from the tty, not from unread-command-events (bug#14368). + (read_event_from_main_queue): New function, extracted from read_char). + (read_decoded_char): Remove. + (read_decoded_event_from_main_queue): New function to replace it. + (read_char): Use it. + (read_key_sequence): Use read_char rather than read_decoded_char. + * keyboard.c (read_decoded_char): Don't decode under w32 (bug#14403). 2013-05-22 Barry OReilly (tiny change) diff --git a/src/keyboard.c b/src/keyboard.c index 7f863269a7e..c9ba39769cd 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2222,6 +2222,157 @@ do { if (! polling_stopped_here) stop_polling (); \ do { if (polling_stopped_here) start_polling (); \ polling_stopped_here = 0; } while (0) +static Lisp_Object +read_event_from_main_queue (EMACS_TIME *end_time, + sys_jmp_buf local_getcjmp, + bool *used_mouse_menu) +{ + Lisp_Object c = Qnil; + sys_jmp_buf save_jump; + KBOARD *kb IF_LINT (= NULL); + + start: + + /* Read from the main queue, and if that gives us something we can't use yet, + we put it on the appropriate side queue and try again. */ + + if (end_time && EMACS_TIME_LE (*end_time, current_emacs_time ())) + return c; + + /* Actually read a character, waiting if necessary. */ + save_getcjmp (save_jump); + restore_getcjmp (local_getcjmp); + if (!end_time) + timer_start_idle (); + c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time); + restore_getcjmp (save_jump); + + if (! NILP (c) && (kb != current_kboard)) + { + Lisp_Object last = KVAR (kb, kbd_queue); + if (CONSP (last)) + { + while (CONSP (XCDR (last))) + last = XCDR (last); + if (!NILP (XCDR (last))) + emacs_abort (); + } + if (!CONSP (last)) + kset_kbd_queue (kb, Fcons (c, Qnil)); + else + XSETCDR (last, Fcons (c, Qnil)); + kb->kbd_queue_has_data = 1; + c = Qnil; + if (single_kboard) + goto start; + current_kboard = kb; + /* This is going to exit from read_char + so we had better get rid of this frame's stuff. */ + return make_number (-2); + } + + /* Terminate Emacs in batch mode if at eof. */ + if (noninteractive && INTEGERP (c) && XINT (c) < 0) + Fkill_emacs (make_number (1)); + + if (INTEGERP (c)) + { + /* Add in any extra modifiers, where appropriate. */ + if ((extra_keyboard_modifiers & CHAR_CTL) + || ((extra_keyboard_modifiers & 0177) < ' ' + && (extra_keyboard_modifiers & 0177) != 0)) + XSETINT (c, make_ctrl_char (XINT (c))); + + /* Transfer any other modifier bits directly from + extra_keyboard_modifiers to c. Ignore the actual character code + in the low 16 bits of extra_keyboard_modifiers. */ + XSETINT (c, XINT (c) | (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL)); + } + + /* FIXME: Decode tty keyboard input here. */ + return c; +} + + + +/* Like `read_event_from_main_queue' but applies keyboard-coding-system + to tty input. */ +static Lisp_Object +read_decoded_event_from_main_queue (EMACS_TIME *end_time, + sys_jmp_buf local_getcjmp, + Lisp_Object prev_event, + bool *used_mouse_menu) +{ +#define MAX_ENCODED_BYTES 16 + Lisp_Object events[MAX_ENCODED_BYTES]; + int n = 0; + while (true) + { + Lisp_Object nextevt + = read_event_from_main_queue (end_time, local_getcjmp, + used_mouse_menu); +#ifdef WINDOWSNT + /* w32_console already returns decoded events. */ + return nextevt; +#else + struct frame *frame = XFRAME (selected_frame); + struct terminal *terminal = frame->terminal; + if (!((FRAME_TERMCAP_P (frame) || FRAME_MSDOS_P (frame)) + /* Don't apply decoding if we're just reading a raw event + (e.g. reading bytes sent by the xterm to specify the position + of a mouse click). */ + && (!EQ (prev_event, Qt)) + && (TERMINAL_KEYBOARD_CODING (terminal)->common_flags + & CODING_REQUIRE_DECODING_MASK))) + return nextevt; /* No decoding needed. */ + else + { + int meta_key = terminal->display_info.tty->meta_key; + eassert (n < MAX_ENCODED_BYTES); + events[n++] = nextevt; + if (NATNUMP (nextevt) + && XINT (nextevt) < (meta_key == 1 ? 0x80 : 0x100)) + { /* An encoded byte sequence, let's try to decode it. */ + struct coding_system *coding + = TERMINAL_KEYBOARD_CODING (terminal); + unsigned char *src = alloca (n); + int i; + for (i = 0; i < n; i++) + src[i] = XINT (events[i]); + if (meta_key != 2) + for (i = 0; i < n; i++) + src[i] &= ~0x80; + coding->destination = alloca (n * 4); + coding->dst_bytes = n * 4; + decode_coding_c_string (coding, src, n, Qnil); + eassert (coding->produced_char <= n); + if (coding->produced_char == 0) + { /* The encoded sequence is incomplete. */ + if (n < MAX_ENCODED_BYTES) /* Avoid buffer overflow. */ + continue; /* Read on! */ + } + else + { + const unsigned char *p = coding->destination; + eassert (coding->carryover_bytes == 0); + n = 0; + while (n < coding->produced_char) + events[n++] = make_number (STRING_CHAR_ADVANCE (p)); + } + } + /* Now `events' should hold decoded events. + Normally, n should be equal to 1, but better not rely on it. + We can only return one event here, so return the first we + had and keep the others (if any) for later. */ + while (n > 1) + Vunread_command_events + = Fcons (events[--n], Vunread_command_events); + return events[0]; + } +#endif + } +} + /* Read a character from the keyboard; call the redisplay if needed. */ /* commandflag 0 means do not autosave, but do redisplay. -1 means do not redisplay, but do autosave. @@ -2739,68 +2890,20 @@ read_char (int commandflag, Lisp_Object map, STOP_POLLING; - /* Finally, we read from the main queue, - and if that gives us something we can't use yet, we put it on the - appropriate side queue and try again. */ - if (NILP (c)) { - KBOARD *kb IF_LINT (= NULL); - + c = read_decoded_event_from_main_queue (end_time, local_getcjmp, + prev_event, used_mouse_menu); if (end_time && EMACS_TIME_LE (*end_time, current_emacs_time ())) - goto exit; - - /* Actually read a character, waiting if necessary. */ - save_getcjmp (save_jump); - restore_getcjmp (local_getcjmp); - if (!end_time) - timer_start_idle (); - c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time); - restore_getcjmp (save_jump); - - if (! NILP (c) && (kb != current_kboard)) - { - Lisp_Object last = KVAR (kb, kbd_queue); - if (CONSP (last)) - { - while (CONSP (XCDR (last))) - last = XCDR (last); - if (!NILP (XCDR (last))) - emacs_abort (); - } - if (!CONSP (last)) - kset_kbd_queue (kb, Fcons (c, Qnil)); - else - XSETCDR (last, Fcons (c, Qnil)); - kb->kbd_queue_has_data = 1; - c = Qnil; - if (single_kboard) - goto wrong_kboard; - current_kboard = kb; + goto exit; + if (EQ (c, make_number (-2))) + { /* This is going to exit from read_char so we had better get rid of this frame's stuff. */ UNGCPRO; - return make_number (-2); - } - } - - /* Terminate Emacs in batch mode if at eof. */ - if (noninteractive && INTEGERP (c) && XINT (c) < 0) - Fkill_emacs (make_number (1)); - - if (INTEGERP (c)) - { - /* Add in any extra modifiers, where appropriate. */ - if ((extra_keyboard_modifiers & CHAR_CTL) - || ((extra_keyboard_modifiers & 0177) < ' ' - && (extra_keyboard_modifiers & 0177) != 0)) - XSETINT (c, make_ctrl_char (XINT (c))); - - /* Transfer any other modifier bits directly from - extra_keyboard_modifiers to c. Ignore the actual character code - in the low 16 bits of extra_keyboard_modifiers. */ - XSETINT (c, XINT (c) | (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL)); - } + return c; + } + } non_reread: @@ -8690,76 +8793,6 @@ test_undefined (Lisp_Object binding) && EQ (Fcommand_remapping (binding, Qnil, Qnil), Qundefined))); } -/* Like `read_char' but applies keyboard-coding-system to tty input. */ -static Lisp_Object -read_decoded_char (int commandflag, Lisp_Object map, - Lisp_Object prev_event, bool *used_mouse_menu) -{ -#define MAX_ENCODED_BYTES 16 - Lisp_Object events[MAX_ENCODED_BYTES]; - int n = 0; - while (true) - { - Lisp_Object nextevt - = read_char (commandflag, map, prev_event, used_mouse_menu, NULL); -#ifdef WINDOWSNT - /* w32_console already returns decoded events. */ - return nextevt; -#else - struct frame *frame = XFRAME (selected_frame); - struct terminal *terminal = frame->terminal; - if (!((FRAME_TERMCAP_P (frame) || FRAME_MSDOS_P (frame)) - && (TERMINAL_KEYBOARD_CODING (terminal)->common_flags - & CODING_REQUIRE_DECODING_MASK))) - return nextevt; /* No decoding needed. */ - else - { - int meta_key = terminal->display_info.tty->meta_key; - eassert (n < MAX_ENCODED_BYTES); - events[n++] = nextevt; - if (NATNUMP (nextevt) - && XINT (nextevt) < (meta_key == 1 ? 0x80 : 0x100)) - { /* An encoded byte sequence, let's try to decode it. */ - struct coding_system *coding - = TERMINAL_KEYBOARD_CODING (terminal); - unsigned char *src = alloca (n); - int i; - for (i = 0; i < n; i++) - src[i] = XINT (events[i]); - if (meta_key != 2) - for (i = 0; i < n; i++) - src[i] &= ~0x80; - coding->destination = alloca (n * 4); - coding->dst_bytes = n * 4; - decode_coding_c_string (coding, src, n, Qnil); - eassert (coding->produced_char <= n); - if (coding->produced_char == 0) - { /* The encoded sequence is incomplete. */ - if (n < MAX_ENCODED_BYTES) /* Avoid buffer overflow. */ - continue; /* Read on! */ - } - else - { - const unsigned char *p = coding->destination; - eassert (coding->carryover_bytes == 0); - n = 0; - while (n < coding->produced_char) - events[n++] = make_number (STRING_CHAR_ADVANCE (p)); - } - } - /* Now `events' should hold decoded events. - Normally, n should be equal to 1, but better not rely on it. - We can only return one event here, so return the first we - had and keep the others (if any) for later. */ - while (n > 1) - Vunread_command_events - = Fcons (events[--n], Vunread_command_events); - return events[0]; - } -#endif - } -} - /* Read a sequence of keys that ends with a non prefix character, storing it in KEYBUF, a buffer of size BUFSIZE. Prompt with PROMPT. @@ -9037,9 +9070,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt, { KBOARD *interrupted_kboard = current_kboard; struct frame *interrupted_frame = SELECTED_FRAME (); - key = read_decoded_char (NILP (prompt), - current_binding, last_nonmenu_event, - &used_mouse_menu); + key = read_char (NILP (prompt), + current_binding, last_nonmenu_event, + &used_mouse_menu, NULL); if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */ /* When switching to a new tty (with a new keyboard), read_char returns the new buffer, rather than -2 -- 2.39.2