I'm building a UI for a text adventure game. I want my topmost widget to handle keypresses for simple shortcuts. 'Enter' to open an input field for instance. But if the input field ist the current focus widget, I want the 'enter' keypress to emit a connected signal.
Is there a way to pass the keypress to the current focus widget, without the container handling it first? The only solution I can think of is the following:
class UserInput(urwid.Edit):
signals = ['submit']
def __init__(self):
super().__init__(u">> ", wrap='clip')
def keypress(self, size, key):
if key == 'enter':
self._emit('submit')
else:
super().keypress(size, key)
class Container(urwid.Frame):
def keypress(self, size, key):
# pass keys with double binding if focus widget is input field
if isinstance(self.focus, urwid.Edit):
pass
else:
# Move Player
if key in ['w', 'a', 's', 'd', 'q', 'e']:
self.handle_userInput(key)
# Append input field to bottom of ListWalker
elif key in [' ', 'enter']:
self.textBox.show_inputField()
...
# Open Menu in side panel
if key == 'esc':
self.switch_infoTab('menu')
# pass unhandled keys to base class method
else:
super().keypress(size, key)
I think the type check at the beginning of Container.keypress
is clunky. A hint to a better solution would be much apprechiated.
If understand Urwid correctly this should indeed be possible! Think of what the arrow keys do for navigation in nested hierarchies of widgets.
Example: Let's say there is a Columns widget that contains two Edit widgets, and the first Edit has the focus. When you press right, the cursor will step through the string in the Edit widget until you reach the end. Then the focus will shift to the second Edit widget.
How does this work? The
keypress
method has a return value. If it returnsNone
it means the widget handled the key press. If the returns thekey
value back, it means that it did not handle key press. The Edit widget returnsNone
when it is moving the cursor inside the widget. Once the end is reached, it starts returnkey
instead. The Columns widget tries to callkeyprees
on its focused widget. If it returnsNone
then it is done. If it returns a key, then the Columns widget shifts the focus to the next child instead.So in your case, you can call
keypress
on the currently focused widget in your Container widget. If it returnskey
back and the key is'enter'
then you can launch a new input field.I learned this from the following page: http://urwid.org/manual/widgets.html (see the "then keyboard input will be handled this way:" part).