Commit 3ef92282 authored by louiz’'s avatar louiz’

Continuation keys (like after M-j or Ctrl-c) are handled without blocking

parent 0e2bba64
......@@ -39,13 +39,13 @@ from config import config, firstrun
from contact import Contact, Resource
from daemon import Executor
from fifo import Fifo
from keyboard import Keyboard
from logger import logger
from plugin_manager import PluginManager
from roster import roster
from size_manager import SizeManager
from text_buffer import TextBuffer
from theming import get_theme
import keyboard
from . import completions
from . import commands
......@@ -72,7 +72,7 @@ class Core(object):
self.running = True
self.xmpp = singleton.Singleton(connection.Connection)
self.xmpp.core = self
self.keyboard = Keyboard()
self.keyboard = keyboard.Keyboard()
decorators.refresh_wrapper.core = self
self.paused = False
......@@ -131,6 +131,11 @@ class Core(object):
del self.commands['status']
del self.commands['show']
# A list of integers. For example if the user presses Alt+j, 2, 1,
# we will insert 2, then 1 in that list, and we will finally build
# the number 21 and use it with command_win, before clearing the
# list.
self.room_number_jump = []
self.key_func = KeyDict()
# Key bindings associated with handlers
# and pseudo-keys used to map actions below.
......@@ -742,10 +747,21 @@ class Core(object):
def do_command(self, key, raw):
Execute the action associated with a key
Or if keyboard.continuation_keys_callback is set, call it instead. See
the comment of this variable.
if not key:
return self.current_tab().on_input(key, raw)
if keyboard.continuation_keys_callback is not None:
# Reset the callback to None BEFORE calling it, because this
# callback MAY set a new callback itself, and we don’t want to
# erase it in that case
cb = keyboard.continuation_keys_callback
keyboard.continuation_keys_callback = None
self.current_tab().on_input(key, raw)
def try_execute(self, line):
......@@ -1060,17 +1076,24 @@ class Core(object):
Read 2 more chars and go to the tab
with the given number
char = self.read_keyboard()[0]
nb1 = int(char)
except ValueError:
char = self.read_keyboard()[0]
nb2 = int(char)
except ValueError:
self.command_win('%s%s' % (nb1, nb2))
def read_next_digit(digit):
nb = int(digit)
except ValueError:
# If it is not a number, we do nothing. If it was the first
# one, we do not wait for a second one by re-setting the
# callback
if len(self.room_number_jump) == 2:
arg = "".join(self.room_number_jump)
# We need to read more digits
keyboard.continuation_keys_callback = read_next_digit
keyboard.continuation_keys_callback = read_next_digit
def go_to_roster(self):
"Select the roster as the current tab"
......@@ -1623,13 +1646,11 @@ class Core(object):
def read_keyboard(self):
Get the next keyboard key pressed and returns it.
get_user_input() has a timeout: it returns None when the timeout
occurs. In that case we do not return (we loop until we get
a non-None value), but we check for timed events instead.
Get the next keyboard key pressed and returns it. It blocks until
something can be read on stdin, this function must be called only if
there is something to read. No timeout ever occurs.
res = self.keyboard.get_user_input(self.stdscr)
return res
return self.keyboard.get_user_input(self.stdscr)
def escape_next_key(self):
......@@ -18,6 +18,15 @@ import curses.ascii
import logging
log = logging.getLogger(__name__)
# A callback that will handle the next key entered by the user. For
# example if the user presses Ctrl+j, we set a callbacks, and the
# next key pressed by the user will be passed to this callback
# instead of the normal process of executing global keybard
# shortcuts or inserting text in the current output. The callback
# is always reset to None afterwards (to resume the normal
# processing of keys)
continuation_keys_callback = None
def get_next_byte(s):
Read the next byte of the utf-8 char
......@@ -68,9 +68,12 @@ class YesNoInput(Win):
def prompt(self):
"""Monopolizes the input while waiting for a recognized keypress"""
cl = []
while self.value is None:
if len(cl) == 1 and cl[0] in self.key_func:
cl = self.core.read_keyboard()
def cb(key):
if key in self.key_func:
if self.value is None:
# We didn’t finish with this prompt, continue monopolizing
# it again until value is set
keyboard.continuation_keys_callback = cb
keyboard.continuation_keys_callback = cb
......@@ -8,6 +8,7 @@ log = logging.getLogger(__name__)
import curses
import string
import keyboard
import common
import poopt
from . import Win
......@@ -655,11 +656,12 @@ class MessageInput(HistoryInput):
Read one more char (c), add the corresponding char from formats_char to the text string
attr_char = self.core.read_keyboard()[0]
if attr_char in self.text_attributes:
char = format_chars[self.text_attributes.index(attr_char)]
self.do_command(char, False)
def cb(attr_char):
if attr_char in self.text_attributes:
char = format_chars[self.text_attributes.index(attr_char)]
self.do_command(char, False)
keyboard.continuation_keys_callback = cb
def key_enter(self):
if self.history_enter():
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment