mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Add key_to_character function
This commit is contained in:
@@ -1026,7 +1026,7 @@ class DOMNode(MessagePump):
|
||||
)
|
||||
return style
|
||||
|
||||
def check_consume_key(self, key: str) -> bool:
|
||||
def check_consume_key(self, key: str, character: str | None) -> bool:
|
||||
"""Check if the widget may consume the given key.
|
||||
|
||||
This should be implemented in widgets that handle [`Key`][textual.events.Key] events and
|
||||
@@ -1037,6 +1037,7 @@ class DOMNode(MessagePump):
|
||||
|
||||
Args:
|
||||
key: A key identifier.
|
||||
character: A printable character associated with they key, or `None` if character is not printable.
|
||||
|
||||
Returns:
|
||||
`True` if the widget may capture the key in its `Key` event handler, or `False` if it won't.
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import unicodedata
|
||||
from enum import Enum
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
# Adapted from prompt toolkit https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/prompt_toolkit/keys.py
|
||||
@@ -282,6 +283,7 @@ def _get_key_aliases(key: str) -> list[str]:
|
||||
return [key] + KEY_ALIASES.get(key, [])
|
||||
|
||||
|
||||
@lru_cache(1024)
|
||||
def format_key(key: str) -> str:
|
||||
"""Given a key (i.e. the `key` string argument to Binding __init__),
|
||||
return the value that should be displayed in the app when referring
|
||||
@@ -303,6 +305,32 @@ def format_key(key: str) -> str:
|
||||
return tentative_unicode_name
|
||||
|
||||
|
||||
@lru_cache(1024)
|
||||
def key_to_character(key: str) -> str | None:
|
||||
"""Given a key identifier, return the character associated with it.
|
||||
|
||||
Args:
|
||||
key: The key identifier.
|
||||
|
||||
Returns:
|
||||
A key if one could be found, otherwise `None`.
|
||||
"""
|
||||
_, separator, key = key.rpartition("+")
|
||||
if separator:
|
||||
return None
|
||||
if len(key) == 1:
|
||||
return key
|
||||
try:
|
||||
return unicodedata.lookup(KEY_TO_UNICODE_NAME[key])
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
return unicodedata.lookup(key.replace("_", " ").upper())
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def _character_to_key(character: str) -> str:
|
||||
"""Convert a single character to a key value.
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ import rich.repr
|
||||
from rich.console import RenderableType
|
||||
from rich.style import Style
|
||||
|
||||
from textual.keys import key_to_character
|
||||
|
||||
from . import constants, errors, events, messages
|
||||
from ._arrange import arrange
|
||||
from ._callback import invoke
|
||||
@@ -330,7 +332,7 @@ class Screen(Generic[ScreenResultType], Widget):
|
||||
for filter_namespace in filter_namespaces:
|
||||
check_consume_key = filter_namespace.check_consume_key
|
||||
for key in list(bindings_map.key_to_bindings):
|
||||
if check_consume_key(key):
|
||||
if check_consume_key(key, key_to_character(key)):
|
||||
del bindings_map.key_to_bindings[key]
|
||||
filter_namespaces.append(namespace)
|
||||
|
||||
|
||||
@@ -361,18 +361,19 @@ class Input(Widget, can_focus=True):
|
||||
"""Flag to indicate if the cursor is at the end"""
|
||||
return self.cursor_position >= len(self.value)
|
||||
|
||||
def check_consume_key(self, key: str) -> bool:
|
||||
def check_consume_key(self, key: str, character: str | None) -> bool:
|
||||
"""Check if the widget may consume the given key.
|
||||
|
||||
As an input we are expecting to capture printable keys.
|
||||
|
||||
Args:
|
||||
key: A key identifier.
|
||||
character: A printable character associated with they key, or `None` if character is not printable.
|
||||
|
||||
Returns:
|
||||
`True` if the widget may capture the key in it's `Key` message, or `False` if it won't.
|
||||
"""
|
||||
return len(key) == 1 and key.isprintable()
|
||||
return character is not None and character.isprintable()
|
||||
|
||||
def validate_cursor_position(self, cursor_position: int) -> int:
|
||||
return min(max(0, cursor_position), len(self.value))
|
||||
|
||||
@@ -546,13 +546,14 @@ TextArea {
|
||||
|
||||
return highlight_query
|
||||
|
||||
def check_consume_key(self, key: str) -> bool:
|
||||
def check_consume_key(self, key: str, character: str | None = None) -> bool:
|
||||
"""Check if the widget may consume the given key.
|
||||
|
||||
As a textarea we are expecting to capture printable keys.
|
||||
|
||||
Args:
|
||||
key: A key identifier.
|
||||
character: A printable character associated with they key, or `None` if character is not printable.
|
||||
|
||||
Returns:
|
||||
`True` if the widget may capture the key in it's `Key` message, or `False` if it won't.
|
||||
@@ -561,7 +562,7 @@ TextArea {
|
||||
return False
|
||||
if self.tab_behavior == "indent" and key == "tab":
|
||||
return True
|
||||
return len(key) == 1 and key.isprintable()
|
||||
return character is not None and character.isprintable()
|
||||
|
||||
def _build_highlight_map(self) -> None:
|
||||
"""Query the tree for ranges to highlights, and update the internal highlights mapping."""
|
||||
|
||||
@@ -2,7 +2,7 @@ import pytest
|
||||
|
||||
from textual.app import App
|
||||
from textual.binding import Binding
|
||||
from textual.keys import _character_to_key, format_key
|
||||
from textual.keys import _character_to_key, format_key, key_to_character
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -67,3 +67,12 @@ def test_get_key_display():
|
||||
== "shift+^]"
|
||||
)
|
||||
assert app.get_key_display(Binding("delete", "", "")) == "del"
|
||||
|
||||
|
||||
def test_key_to_character():
|
||||
assert key_to_character("f") == "f"
|
||||
assert key_to_character("F") == "F"
|
||||
assert key_to_character("space") == " "
|
||||
assert key_to_character("ctrl+space") is None
|
||||
assert key_to_character("question_mark") == "?"
|
||||
assert key_to_character("foo") is None
|
||||
|
||||
Reference in New Issue
Block a user