fill3: Separate keypresses in input
- Stdin can contain more than one keypress when inputted quickly.
This commit is contained in:
parent
a016a36f61
commit
2e3004cd13
2 changed files with 36 additions and 8 deletions
|
|
@ -494,14 +494,29 @@ async def update_screen(screen_widget):
|
||||||
APPEARANCE_CHANGED_EVENT.clear()
|
APPEARANCE_CHANGED_EVENT.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def digest_terminal_input(input_str):
|
||||||
|
cursor = 0
|
||||||
|
result = []
|
||||||
|
for index, char in enumerate(input_str):
|
||||||
|
if cursor != index:
|
||||||
|
if char == terminal.ESC:
|
||||||
|
result.append(input_str[cursor:index])
|
||||||
|
cursor = index
|
||||||
|
elif ord(char) < 32:
|
||||||
|
result.extend([input_str[cursor:index], char])
|
||||||
|
cursor = index + 1
|
||||||
|
if cursor != index + 1:
|
||||||
|
result.append(input_str[cursor:index+1])
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@handle_exception
|
@handle_exception
|
||||||
def on_terminal_input(screen_widget):
|
def on_terminal_input(screen_widget):
|
||||||
term_code = sys.stdin.read()
|
for part in digest_terminal_input(sys.stdin.read()):
|
||||||
if term_code.startswith(terminal.MOUSE):
|
if part.startswith(terminal.MOUSE):
|
||||||
for part in term_code.split(terminal.MOUSE)[1:]:
|
screen_widget.on_mouse_input(part[3:])
|
||||||
screen_widget.on_mouse_input(part)
|
else:
|
||||||
else:
|
screen_widget.on_keyboard_input(part)
|
||||||
return screen_widget.on_keyboard_input(term_code)
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
|
|
@ -513,7 +528,7 @@ def signal_handler(loop, signal_, func):
|
||||||
loop.remove_signal_handler(signal_)
|
loop.remove_signal_handler(signal_)
|
||||||
|
|
||||||
|
|
||||||
async def tui(title, screen_widget):
|
async def tui(title, screen_widget, input_handler=on_terminal_input):
|
||||||
global APPEARANCE_CHANGED_EVENT
|
global APPEARANCE_CHANGED_EVENT
|
||||||
global SHUTDOWN_EVENT
|
global SHUTDOWN_EVENT
|
||||||
APPEARANCE_CHANGED_EVENT = asyncio.Event()
|
APPEARANCE_CHANGED_EVENT = asyncio.Event()
|
||||||
|
|
@ -525,7 +540,7 @@ async def tui(title, screen_widget):
|
||||||
terminal.alternate_buffer(), terminal.raw(), terminal.mouse_tracking()):
|
terminal.alternate_buffer(), terminal.raw(), terminal.mouse_tracking()):
|
||||||
update_task = asyncio.create_task(update_screen(screen_widget))
|
update_task = asyncio.create_task(update_screen(screen_widget))
|
||||||
try:
|
try:
|
||||||
loop.add_reader(sys.stdin, on_terminal_input, screen_widget)
|
loop.add_reader(sys.stdin, input_handler, screen_widget)
|
||||||
try:
|
try:
|
||||||
await SHUTDOWN_EVENT.wait()
|
await SHUTDOWN_EVENT.wait()
|
||||||
finally:
|
finally:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import fill3
|
import fill3
|
||||||
|
import fill3.terminal as terminal
|
||||||
|
|
||||||
|
|
||||||
class WidgetTests(unittest.TestCase):
|
class WidgetTests(unittest.TestCase):
|
||||||
|
|
@ -139,5 +140,17 @@ class WidgetTests(unittest.TestCase):
|
||||||
"B A")
|
"B A")
|
||||||
|
|
||||||
|
|
||||||
|
class DigestTerminalInputTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_digest_terminal_input(self):
|
||||||
|
self.assertRaises(UnboundLocalError, fill3.digest_terminal_input, "")
|
||||||
|
self.assertEqual(fill3.digest_terminal_input("a"), ["a"])
|
||||||
|
self.assertEqual(fill3.digest_terminal_input("ab"), ["ab"])
|
||||||
|
self.assertEqual(fill3.digest_terminal_input("a\nb"), ["a", "\n", "b"])
|
||||||
|
self.assertEqual(fill3.digest_terminal_input("a\tb"), ["a", "\t", "b"])
|
||||||
|
self.assertEqual(fill3.digest_terminal_input(terminal.UP * 2), [terminal.UP] * 2)
|
||||||
|
self.assertEqual(fill3.digest_terminal_input(terminal.CTRL_C * 2), [terminal.CTRL_C] * 2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue