This commit is contained in:
Kovid Goyal 2022-12-31 13:38:37 +05:30
commit bd33cef092
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 75 additions and 29 deletions

View File

@ -33,14 +33,14 @@ from .constants import (
)
from .fast_data_types import (
CLOSE_BEING_CONFIRMED, GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT,
GLFW_MOD_SUPER, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, IMPERATIVE_CLOSE_REQUESTED,
GLFW_MOD_SUPER, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, GLFW_RELEASE, IMPERATIVE_CLOSE_REQUESTED,
NO_CLOSE_REQUESTED, ChildMonitor, Color, EllipticCurveKey, KeyEvent, SingleKey,
add_timer, apply_options_update, background_opacity_of, change_background_opacity,
change_os_window_state, cocoa_hide_app, cocoa_hide_other_apps,
cocoa_minimize_os_window, cocoa_set_menubar_title, create_os_window,
current_application_quit_request, current_focused_os_window_id, current_os_window,
destroy_global_data, focus_os_window, get_boss, get_options, get_os_window_size,
global_font_size, last_focused_os_window_id, mark_os_window_for_close,
glfw_is_modifier_key, global_font_size, last_focused_os_window_id, mark_os_window_for_close,
os_window_font_size, patch_global_colors, redirect_mouse_handling, ring_bell,
run_with_activation_token, safe_pipe, send_data_to_peer,
set_application_quit_request, set_background_image, set_boss, set_in_sequence_mode,
@ -254,6 +254,8 @@ class Boss:
self.current_visual_select: Optional[VisualSelect] = None
self.startup_cursor_text_color = opts.cursor_text_color
self.pending_sequences: Optional[SubSequenceMap] = None
# A list of events received so far that are potentially part of a sequence keybinding.
self.current_sequence: List[KeyEvent] = []
self.default_pending_action: str = ''
self.cached_values = cached_values
self.os_window_map: Dict[int, TabManager] = {}
@ -1168,6 +1170,7 @@ class Boss:
sequences = get_shortcut(get_options().sequence_map, ev)
if sequences and not isinstance(sequences, str):
self.set_pending_sequences(sequences)
self.current_sequence = [ev]
return True
if self.global_shortcuts_map and get_shortcut(self.global_shortcuts_map, ev):
return True
@ -1177,14 +1180,23 @@ class Boss:
def clear_pending_sequences(self) -> None:
self.pending_sequences = None
self.current_sequence = []
self.default_pending_action = ''
set_in_sequence_mode(False)
def process_sequence(self, ev: KeyEvent) -> None:
def process_sequence(self, ev: KeyEvent) -> bool:
# Process an event as part of a sequence. Returns whether the key
# is consumed as part of a kitty sequence keybinding.
if not self.pending_sequences:
set_in_sequence_mode(False)
return
return False
if len(self.current_sequence):
self.current_sequence.append(ev)
if ev.action == GLFW_RELEASE or glfw_is_modifier_key(ev.key):
return True
# For a press/repeat event that's not a modifier, try matching with
# kitty bindings:
remaining = {}
matched_action = None
for seq, key_action in self.pending_sequences.items():
@ -1197,11 +1209,20 @@ class Boss:
if remaining:
self.pending_sequences = remaining
return True
else:
matched_action = matched_action or self.default_pending_action
self.clear_pending_sequences()
if matched_action is not None:
if matched_action is not None and matched_action != '':
self.clear_pending_sequences()
self.combine(matched_action)
return True
else:
w = self.active_window
if w is not None:
for ev in self.current_sequence:
w.write_to_child(w.encoded_key(ev))
self.clear_pending_sequences()
return False
def cancel_current_visual_select(self) -> None:
if self.current_visual_select:

View File

@ -313,6 +313,10 @@ def glfw_get_key_name(key: int, native_key: int) -> Optional[str]:
pass
def glfw_is_modifier_key(key: int) -> bool:
pass
StartupCtx = NewType('StartupCtx', int)
Display = NewType('Display', int)

View File

@ -1256,6 +1256,33 @@ glfw_get_key_name(PyObject UNUSED *self, PyObject *args) {
return Py_BuildValue("z", glfwGetKeyName(key, native_key));
}
bool
is_modifier_key(const uint32_t key) {
START_ALLOW_CASE_RANGE
switch (key) {
case GLFW_FKEY_LEFT_SHIFT ... GLFW_FKEY_ISO_LEVEL5_SHIFT:
case GLFW_FKEY_CAPS_LOCK:
case GLFW_FKEY_SCROLL_LOCK:
case GLFW_FKEY_NUM_LOCK:
return true;
default:
return false;
}
END_ALLOW_CASE_RANGE
}
static PyObject*
glfw_is_modifier_key(PyObject UNUSED *self, PyObject *args) {
uint32_t key;
if (!PyArg_ParseTuple(args, "I", &key)) return NULL;
PyObject *ans = is_modifier_key(key) ? Py_True : Py_False;
Py_INCREF(ans);
return ans;
}
static PyObject*
glfw_window_hint(PyObject UNUSED *self, PyObject *args) {
int key, val;
@ -1762,6 +1789,7 @@ static PyMethodDef module_methods[] = {
{"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""},
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},
{"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""},
METHODB(glfw_is_modifier_key, METH_VARARGS),
{"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
{NULL, NULL, 0, NULL} /* Sentinel */

View File

@ -31,21 +31,6 @@ typedef struct {
KeyAction action;
} EncodingData;
bool
is_modifier_key(const uint32_t key) {
START_ALLOW_CASE_RANGE
switch (key) {
case GLFW_FKEY_LEFT_SHIFT ... GLFW_FKEY_ISO_LEVEL5_SHIFT:
case GLFW_FKEY_CAPS_LOCK:
case GLFW_FKEY_SCROLL_LOCK:
case GLFW_FKEY_NUM_LOCK:
return true;
default:
return false;
}
END_ALLOW_CASE_RANGE
}
static void
convert_glfw_mods(int mods, KeyEvent *ev, const unsigned key_encoding_flags) {
if (!key_encoding_flags) mods &= ~GLFW_LOCK_MASK;

View File

@ -167,14 +167,21 @@ on_key_input(GLFWkeyevent *ev) {
PyObject *ke = NULL;
#define create_key_event() { ke = convert_glfw_key_event_to_python(ev); if (!ke) { PyErr_Print(); return; } }
if (global_state.in_sequence_mode) {
debug("in sequence mode, handling as shortcut\n");
if (
action != GLFW_RELEASE && !is_modifier_key(key)
) {
debug("in sequence mode, handling as a potential shortcut\n");
create_key_event();
PyObject *ret = PyObject_CallMethod(
global_state.boss, "process_sequence", "O", ke);
Py_CLEAR(ke);
// the shortcut could have created a new window or closed the
// window, rendering the pointer no longer valid
w = window_for_window_id(active_window_id);
if (ret == NULL) { PyErr_Print(); }
else {
bool consumed = ret == Py_True;
Py_DECREF(ret);
if (consumed && action != GLFW_RELEASE && w) {
w->last_special_key_pressed = key;
create_key_event();
call_boss(process_sequence, "O", ke);
Py_CLEAR(ke);
}
}
return;
}

View File

@ -18,5 +18,6 @@
int
encode_glfw_key_event(const GLFWkeyevent *e, const bool cursor_key_mode, const unsigned flags, char *output);
bool
// Defined in glfw.c
extern bool
is_modifier_key(const uint32_t key);