diff options
author | Florent Le Coz <louiz@louiz.org> | 2012-10-09 04:35:02 +0000 |
---|---|---|
committer | Florent Le Coz <louiz@louiz.org> | 2012-10-09 04:35:02 +0000 |
commit | 653695498aa334f3c34b0946162020fbae10839d (patch) | |
tree | cc2354bfb13e8f37daf9cce15d04ce2b3d3a544d | |
parent | 4965ee161896ccea6700485dc944db88947107c1 (diff) | |
download | poezio-653695498aa334f3c34b0946162020fbae10839d.tar.gz poezio-653695498aa334f3c34b0946162020fbae10839d.tar.bz2 poezio-653695498aa334f3c34b0946162020fbae10839d.tar.xz poezio-653695498aa334f3c34b0946162020fbae10839d.zip |
Separate special keys from normal chars when receving a batch of chars.
In case of lags or paste of text, the input can yield a list of chars
instead of just one char. In case of lags, keyboard special keys
(KEY_BACKSPACE, ^W, etc) are mixed with other “normal” chars ('a', 'b', 'D',
' ' etc). Instead of handling that whole batch in one go (which requires us
to ignore all the special keys, otherwise they would be displayed in the
input, which are both bad ways to handle that), we separate special keys
from the normal ones, and we handle that big batch as one or more smaller
batches. This should make the input behave correctly in case of lag AND in
case of paste of huge text (only one refresh per batch, respond instantly,
no key lost or ignored, etc)
fixed #2365
-rw-r--r-- | src/core.py | 95 |
1 files changed, 63 insertions, 32 deletions
diff --git a/src/core.py b/src/core.py index 2accb4c4..700e6815 100644 --- a/src/core.py +++ b/src/core.py @@ -359,48 +359,79 @@ class Core(object): return '\n' elif key == '^I': return ' ' - elif len(key) > 1: - return '' return key def replace_line_breaks(key): if key == '^J': return '\n' return key - + def separate_chars_from_bindings(char_list): + """ + returns a list of lists. For example if you give + ['a', 'b', 'KEY_BACKSPACE', 'n', 'u'], this function returns + [['a', 'b'], ['KEY_BACKSPACE'], ['n', 'u']] + + This way, in case of lag (for example), we handle the typed text + by “batch” as much as possible (instead of one char at a time, + which implies a refresh after each char, which is very slow), + but we still handle the special chars (backspaces, arrows, + ctrl+x ou alt+x, etc) one by one, which avoids the issue of + printing them OR ignoring them in that case. This should + resolve the “my ^W are ignored when I lag ;(”. + """ + res = [] + current = [] + for char in char_list: + assert(len(char) > 0) + if len(char) == 1: + current.append(char) + else: + res.append(current) + res.append([char]) + current = [] + if current: + res.append(current) + return res while self.running: if self.paused: continue - char_list = [common.replace_key_with_bound(key)\ + big_char_list = [common.replace_key_with_bound(key)\ for key in self.read_keyboard()] - if self.paused: - self.current_tab().input.do_command(char_list[0]) - self.current_tab().input.prompt() - continue - # Special case for M-x where x is a number - if len(char_list) == 1: - char = char_list[0] - if char.startswith('M-') and len(char) == 3: - try: - nb = int(char[2]) - except ValueError: - pass - else: - if self.current_tab().nb == nb: - self.go_to_previous_tab() + log.debug(big_char_list) + log.debug(separate_chars_from_bindings(big_char_list)) + # whether to refresh after ALL keys have been handled + do_refresh = True + for char_list in separate_chars_from_bindings(big_char_list): + if self.paused: + self.current_tab().input.do_command(char_list[0]) + self.current_tab().input.prompt() + continue + # Special case for M-x where x is a number + if len(char_list) == 1: + char = char_list[0] + if char.startswith('M-') and len(char) == 3: + try: + nb = int(char[2]) + except ValueError: + pass else: - self.command_win('%d' % nb) - # search for keyboard shortcut - func = self.key_func.get(char, None) - if func: - func() + if self.current_tab().nb == nb: + self.go_to_previous_tab() + else: + self.command_win('%d' % nb) + # search for keyboard shortcut + func = self.key_func.get(char, None) + if func: + func() + else: + res = self.do_command(replace_line_breaks(char), False) + if res: + do_refresh = True else: - res = self.do_command(replace_line_breaks(char), False) - if res: - self.refresh_window() - else: - self.do_command(''.join(map( - lambda x: sanitize_input(x), - char_list) - ), True) + self.do_command(''.join(map( + lambda x: sanitize_input(x), + char_list) + ), True) + refresh = True + if refresh == True: self.refresh_window() self.doupdate() |