Implement keyboard input
This commit is contained in:
parent
48e7226a2a
commit
e5293fba16
3
glfw.py
3
glfw.py
@ -376,6 +376,7 @@ cursorenterfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
|
|||||||
scrollfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
|
scrollfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
|
||||||
keyfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int, c_int)
|
keyfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int, c_int)
|
||||||
charfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint)
|
charfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint)
|
||||||
|
charmodsfun = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint, c_int)
|
||||||
monitorfun = CFUNCTYPE(None, POINTER(GLFWmonitor), c_int)
|
monitorfun = CFUNCTYPE(None, POINTER(GLFWmonitor), c_int)
|
||||||
|
|
||||||
# --- Init --------------------------------------------------------------------
|
# --- Init --------------------------------------------------------------------
|
||||||
@ -505,6 +506,7 @@ def glfwCreateWindow(width=640, height=480, title="GLFW Window",
|
|||||||
'framebuffersizefun': None,
|
'framebuffersizefun': None,
|
||||||
'keyfun': None,
|
'keyfun': None,
|
||||||
'charfun': None,
|
'charfun': None,
|
||||||
|
'charmodsfun': None,
|
||||||
'mousebuttonfun': None,
|
'mousebuttonfun': None,
|
||||||
'cursorposfun': None,
|
'cursorposfun': None,
|
||||||
'cursorenterfun': None,
|
'cursorenterfun': None,
|
||||||
@ -645,6 +647,7 @@ exec(__callback__('WindowIconify'))
|
|||||||
exec(__callback__('FramebufferSize'))
|
exec(__callback__('FramebufferSize'))
|
||||||
exec(__callback__('Key'))
|
exec(__callback__('Key'))
|
||||||
exec(__callback__('Char'))
|
exec(__callback__('Char'))
|
||||||
|
exec(__callback__('CharMods'))
|
||||||
exec(__callback__('MouseButton'))
|
exec(__callback__('MouseButton'))
|
||||||
exec(__callback__('CursorPos'))
|
exec(__callback__('CursorPos'))
|
||||||
exec(__callback__('Scroll'))
|
exec(__callback__('Scroll'))
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import glfw
|
|||||||
from pyte.streams import Stream, DebugStream
|
from pyte.streams import Stream, DebugStream
|
||||||
|
|
||||||
from .char_grid import CharGrid
|
from .char_grid import CharGrid
|
||||||
|
from .keys import interpret_text_event, interpret_key_event
|
||||||
from .screen import Screen
|
from .screen import Screen
|
||||||
from .tracker import ChangeTracker
|
from .tracker import ChangeTracker
|
||||||
from .utils import resize_pty, create_pty
|
from .utils import resize_pty, create_pty
|
||||||
@ -42,11 +43,24 @@ class Boss(Thread):
|
|||||||
self.stream = sclass(self.screen)
|
self.stream = sclass(self.screen)
|
||||||
self.write_buf = memoryview(b'')
|
self.write_buf = memoryview(b'')
|
||||||
resize_pty(80, 24)
|
resize_pty(80, 24)
|
||||||
|
glfw.glfwSetCharModsCallback(window, self.on_text_input)
|
||||||
|
glfw.glfwSetKeyCallback(window, self.on_key)
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.char_grid.initialize()
|
self.char_grid.initialize()
|
||||||
glfw.glfwPostEmptyEvent()
|
glfw.glfwPostEmptyEvent()
|
||||||
|
|
||||||
|
def on_key(self, window, key, scancode, action, mods):
|
||||||
|
if action == glfw.GLFW_PRESS or action == glfw.GLFW_REPEAT:
|
||||||
|
data = interpret_key_event(key, scancode, mods)
|
||||||
|
if data:
|
||||||
|
self.write_to_child(data)
|
||||||
|
|
||||||
|
def on_text_input(self, window, codepoint, mods):
|
||||||
|
data = interpret_text_event(codepoint, mods)
|
||||||
|
if data:
|
||||||
|
self.write_to_child(data)
|
||||||
|
|
||||||
def on_window_resize(self, window, w, h):
|
def on_window_resize(self, window, w, h):
|
||||||
self.queue_action(self.apply_resize_screen, w, h)
|
self.queue_action(self.apply_resize_screen, w, h)
|
||||||
|
|
||||||
|
|||||||
114
kitty/keys.py
114
kitty/keys.py
@ -2,82 +2,58 @@
|
|||||||
# vim:fileencoding=utf-8
|
# vim:fileencoding=utf-8
|
||||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import glfw
|
||||||
from PyQt5.QtCore import Qt, QObject, QEvent
|
|
||||||
|
|
||||||
CTRL_MASK = 0b10011111
|
|
||||||
|
|
||||||
key_map = {
|
key_map = {
|
||||||
Qt.Key_Up: 'OA',
|
glfw.GLFW_KEY_UP: b'OA',
|
||||||
Qt.Key_Down: 'OB',
|
glfw.GLFW_KEY_DOWN: b'OB',
|
||||||
Qt.Key_Left: 'OD',
|
glfw.GLFW_KEY_LEFT: b'OD',
|
||||||
Qt.Key_Right: 'OC',
|
glfw.GLFW_KEY_RIGHT: b'OC',
|
||||||
Qt.Key_Home: 'OH',
|
glfw.GLFW_KEY_HOME: b'OH',
|
||||||
Qt.Key_End: 'OF',
|
glfw.GLFW_KEY_END: b'OF',
|
||||||
Qt.Key_Insert: '[2~',
|
glfw.GLFW_KEY_ESCAPE: b'',
|
||||||
Qt.Key_Delete: '[3~',
|
glfw.GLFW_KEY_INSERT: b'[2~',
|
||||||
Qt.Key_PageUp: '[5~',
|
glfw.GLFW_KEY_DELETE: b'[3~',
|
||||||
Qt.Key_PageDown: '[6~',
|
glfw.GLFW_KEY_PAGE_UP: b'[5~',
|
||||||
Qt.Key_F1: 'OP',
|
glfw.GLFW_KEY_PAGE_DOWN: b'[6~',
|
||||||
Qt.Key_F2: 'OQ',
|
glfw.GLFW_KEY_F1: b'OP',
|
||||||
Qt.Key_F3: 'OR',
|
glfw.GLFW_KEY_F2: b'OQ',
|
||||||
Qt.Key_F4: 'OS',
|
glfw.GLFW_KEY_F3: b'OR',
|
||||||
Qt.Key_F5: '[15~',
|
glfw.GLFW_KEY_F4: b'OS',
|
||||||
Qt.Key_F6: '[17~',
|
glfw.GLFW_KEY_F5: b'[15~',
|
||||||
Qt.Key_F7: '[18~',
|
glfw.GLFW_KEY_F6: b'[17~',
|
||||||
Qt.Key_F8: '[19~',
|
glfw.GLFW_KEY_F7: b'[18~',
|
||||||
Qt.Key_F9: '[20~',
|
glfw.GLFW_KEY_F8: b'[19~',
|
||||||
Qt.Key_F10: '[21~',
|
glfw.GLFW_KEY_F9: b'[20~',
|
||||||
Qt.Key_F11: '[23~',
|
glfw.GLFW_KEY_F10: b'[21~',
|
||||||
Qt.Key_F12: '[24~',
|
glfw.GLFW_KEY_F11: b'[23~',
|
||||||
|
glfw.GLFW_KEY_F12: b'[24~',
|
||||||
}
|
}
|
||||||
|
key_map = {k: b'\x1b' + v for k, v in key_map.items()}
|
||||||
|
key_map[glfw.GLFW_KEY_ENTER] = b'\n\r'
|
||||||
|
key_map[glfw.GLFW_KEY_BACKSPACE] = b'\x08'
|
||||||
|
|
||||||
|
control_codes = {k: 1 + i for i, k in enumerate(range(glfw.GLFW_KEY_A, glfw.GLFW_KEY_RIGHT_BRACKET))}
|
||||||
|
alt_codes = {k: (0x1b, k) for i, k in enumerate(range(glfw.GLFW_KEY_A, glfw.GLFW_KEY_RIGHT_BRACKET))}
|
||||||
|
|
||||||
|
|
||||||
def key_event_to_data(ev, mods):
|
def interpret_key_event(key, scancode, mods):
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
if mods & Qt.AltModifier:
|
if mods == glfw.GLFW_MOD_CONTROL and key in control_codes:
|
||||||
data.append(27)
|
# Map Ctrl-key to ascii control code
|
||||||
x = key_map.get(ev.key())
|
data.append(control_codes[key])
|
||||||
|
elif mods == glfw.GLFW_MOD_ALT and key in alt_codes:
|
||||||
|
# Map Alt+key to Esc-key
|
||||||
|
data.extend(alt_codes[key])
|
||||||
|
else:
|
||||||
|
x = key_map.get(key)
|
||||||
if x is not None:
|
if x is not None:
|
||||||
data.extend(b'\033' + x.encode('ascii'))
|
data.extend(x)
|
||||||
else:
|
|
||||||
t = ev.text()
|
|
||||||
if t:
|
|
||||||
t = t.encode('utf-8')
|
|
||||||
if mods & Qt.ControlModifier and len(t) == 1 and 0 < t[0] & CTRL_MASK < 33:
|
|
||||||
data.append(t[0] & CTRL_MASK)
|
|
||||||
else:
|
|
||||||
data.extend(t)
|
|
||||||
return bytes(data)
|
return bytes(data)
|
||||||
|
|
||||||
|
|
||||||
class KeyFilter(QObject):
|
def interpret_text_event(codepoint, mods):
|
||||||
|
if mods > glfw.GLFW_MOD_SHIFT:
|
||||||
def __init__(self, parent=None):
|
return b'' # Handled by interpret_key_event above
|
||||||
QObject.__init__(self, parent)
|
data = chr(codepoint).encode('utf-8')
|
||||||
self.disabled = False
|
return data
|
||||||
|
|
||||||
@property
|
|
||||||
def disable_filtering(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.disabled = True
|
|
||||||
|
|
||||||
def __exit__(self, *args):
|
|
||||||
self.disabled = False
|
|
||||||
|
|
||||||
def eventFilter(self, watched, event):
|
|
||||||
if self.disabled:
|
|
||||||
return False
|
|
||||||
etype = event.type()
|
|
||||||
if etype == QEvent.KeyPress:
|
|
||||||
# We use a global event filter to prevent Qt from re-painting the
|
|
||||||
# entire terminal widget on a Tab key press
|
|
||||||
app = self.parent()
|
|
||||||
window, fw = app.activeWindow(), app.focusWidget()
|
|
||||||
if hasattr(window, 'boss') and fw is window.boss.term:
|
|
||||||
window.boss.term.keyPressEvent(event)
|
|
||||||
if event.isAccepted():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user