Add NumLock and CapsLock reporting to the keyboard protocol
This commit is contained in:
parent
c989a7198b
commit
4c644b8556
@ -141,9 +141,10 @@ Modifiers
|
|||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This protocol supports six modifier keys, :kbd:`shift, alt, ctrl, super, hyper
|
This protocol supports six modifier keys, :kbd:`shift, alt, ctrl, super, hyper
|
||||||
and meta`. Here :kbd:`super` is either the *Windows/Linux* key or the *Cmd* key on
|
and meta` as well as :kbd:`num_lock and caps_lock`. Here :kbd:`super` is either
|
||||||
mac keyboards. :kbd:`hyper` and :kbd:`meta` are typically present only on X11
|
the *Windows/Linux* key or the *Cmd* key on mac keyboards. :kbd:`hyper` and
|
||||||
based systems with special XKB rules. Modifiers are encoded as a bit field with::
|
:kbd:`meta` are typically present only on X11 based systems with special XKB
|
||||||
|
rules. Modifiers are encoded as a bit field with::
|
||||||
|
|
||||||
shift 0b1 (1)
|
shift 0b1 (1)
|
||||||
alt 0b10 (2)
|
alt 0b10 (2)
|
||||||
@ -151,6 +152,8 @@ based systems with special XKB rules. Modifiers are encoded as a bit field with:
|
|||||||
super 0b1000 (8)
|
super 0b1000 (8)
|
||||||
hyper 0b10000 (16)
|
hyper 0b10000 (16)
|
||||||
meta 0b100000 (32)
|
meta 0b100000 (32)
|
||||||
|
caps_lock 0b1000000 (64)
|
||||||
|
num_lock 0b10000000 (128)
|
||||||
|
|
||||||
In the escape code, the modifier value is encoded as a decimal number which is
|
In the escape code, the modifier value is encoded as a decimal number which is
|
||||||
``1 + actual modifiers``. So to represent :kbd:`shift` only, the value would be ``1 +
|
``1 + actual modifiers``. So to represent :kbd:`shift` only, the value would be ``1 +
|
||||||
|
|||||||
1
glfw/glfw3.h
vendored
1
glfw/glfw3.h
vendored
@ -510,7 +510,6 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* If this bit is set the Num Lock key is enabled and the @ref
|
* If this bit is set the Num Lock key is enabled and the @ref
|
||||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||||
* @note Ravi: Num lock is not supported in this branch
|
|
||||||
*/
|
*/
|
||||||
#define GLFW_MOD_NUM_LOCK 0x0080
|
#define GLFW_MOD_NUM_LOCK 0x0080
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import sys
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from kitty.key_encoding import (
|
from kitty.key_encoding import (
|
||||||
ALT, CTRL, PRESS, RELEASE, REPEAT, SHIFT, SUPER, HYPER, META, KeyEvent,
|
ALT, CAPS_LOCK, CTRL, HYPER, META, NUM_LOCK, PRESS, RELEASE, REPEAT, SHIFT,
|
||||||
encode_key_event
|
SUPER, KeyEvent, encode_key_event
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..tui.handler import Handler
|
from ..tui.handler import Handler
|
||||||
@ -34,7 +34,10 @@ class KeysHandler(Handler):
|
|||||||
CTRL: 'Ctrl',
|
CTRL: 'Ctrl',
|
||||||
SUPER: 'Super',
|
SUPER: 'Super',
|
||||||
HYPER: 'Hyper',
|
HYPER: 'Hyper',
|
||||||
META: 'Meta'}.items():
|
META: 'Meta',
|
||||||
|
NUM_LOCK: 'NumLock',
|
||||||
|
CAPS_LOCK: 'CapsLock',
|
||||||
|
}.items():
|
||||||
if key_event.mods & m:
|
if key_event.mods & m:
|
||||||
lmods.append(name)
|
lmods.append(name)
|
||||||
mods = '+'.join(lmods)
|
mods = '+'.join(lmods)
|
||||||
|
|||||||
@ -761,11 +761,12 @@ ShortcutMap = Dict[Tuple[SingleKey, ...], KeyAction]
|
|||||||
|
|
||||||
def print_shortcut(key_sequence: Iterable[SingleKey], action: KeyAction) -> None:
|
def print_shortcut(key_sequence: Iterable[SingleKey], action: KeyAction) -> None:
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_HYPER, GLFW_MOD_META,
|
GLFW_MOD_ALT, GLFW_MOD_CAPS_LOCK, GLFW_MOD_CONTROL, GLFW_MOD_HYPER,
|
||||||
|
GLFW_MOD_META, GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT, GLFW_MOD_SUPER,
|
||||||
glfw_get_key_name
|
glfw_get_key_name
|
||||||
)
|
)
|
||||||
modmap = {'shift': GLFW_MOD_SHIFT, 'alt': GLFW_MOD_ALT, 'ctrl': GLFW_MOD_CONTROL, ('cmd' if is_macos else 'super'): GLFW_MOD_SUPER,
|
modmap = {'shift': GLFW_MOD_SHIFT, 'alt': GLFW_MOD_ALT, 'ctrl': GLFW_MOD_CONTROL, ('cmd' if is_macos else 'super'): GLFW_MOD_SUPER,
|
||||||
'hyper': GLFW_MOD_HYPER, 'meta': GLFW_MOD_META}
|
'hyper': GLFW_MOD_HYPER, 'meta': GLFW_MOD_META, 'num_lock': GLFW_MOD_NUM_LOCK, 'caps_lock': GLFW_MOD_CAPS_LOCK}
|
||||||
keys = []
|
keys = []
|
||||||
for key_spec in key_sequence:
|
for key_spec in key_sequence:
|
||||||
names = []
|
names = []
|
||||||
|
|||||||
@ -136,6 +136,8 @@ GLFW_MOD_ALT: int
|
|||||||
GLFW_MOD_SUPER: int
|
GLFW_MOD_SUPER: int
|
||||||
GLFW_MOD_HYPER: int
|
GLFW_MOD_HYPER: int
|
||||||
GLFW_MOD_META: int
|
GLFW_MOD_META: int
|
||||||
|
GLFW_MOD_CAPS_LOCK: int
|
||||||
|
GLFW_MOD_NUM_LOCK: int
|
||||||
GLFW_MOD_KITTY: int
|
GLFW_MOD_KITTY: int
|
||||||
GLFW_MOUSE_BUTTON_1: int
|
GLFW_MOUSE_BUTTON_1: int
|
||||||
GLFW_MOUSE_BUTTON_2: int
|
GLFW_MOUSE_BUTTON_2: int
|
||||||
|
|||||||
@ -677,6 +677,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
|
|||||||
if (is_first_window) glfwSwapInterval(OPT(sync_to_monitor) && !global_state.is_wayland ? 1 : 0);
|
if (is_first_window) glfwSwapInterval(OPT(sync_to_monitor) && !global_state.is_wayland ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
glfwSwapBuffers(glfw_window);
|
glfwSwapBuffers(glfw_window);
|
||||||
|
glfwSetInputMode(glfw_window, GLFW_LOCK_KEY_MODS, true);
|
||||||
if (!global_state.is_wayland) {
|
if (!global_state.is_wayland) {
|
||||||
PyObject *pret = PyObject_CallFunction(pre_show_callback, "N", native_window_handle(glfw_window));
|
PyObject *pret = PyObject_CallFunction(pre_show_callback, "N", native_window_handle(glfw_window));
|
||||||
if (pret == NULL) return NULL;
|
if (pret == NULL) return NULL;
|
||||||
@ -1568,6 +1569,8 @@ init_glfw(PyObject *m) {
|
|||||||
ADDC(GLFW_MOD_HYPER);
|
ADDC(GLFW_MOD_HYPER);
|
||||||
ADDC(GLFW_MOD_META);
|
ADDC(GLFW_MOD_META);
|
||||||
ADDC(GLFW_MOD_KITTY);
|
ADDC(GLFW_MOD_KITTY);
|
||||||
|
ADDC(GLFW_MOD_CAPS_LOCK);
|
||||||
|
ADDC(GLFW_MOD_NUM_LOCK);
|
||||||
|
|
||||||
// --- Mouse -------------------------------------------------------------------
|
// --- Mouse -------------------------------------------------------------------
|
||||||
ADDC(GLFW_MOUSE_BUTTON_1);
|
ADDC(GLFW_MOUSE_BUTTON_1);
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
#include "charsets.h"
|
#include "charsets.h"
|
||||||
|
|
||||||
typedef enum { SHIFT=1, ALT=2, CTRL=4, SUPER=8, HYPER=16, META=32} ModifierMasks;
|
typedef enum { SHIFT=1, ALT=2, CTRL=4, SUPER=8, HYPER=16, META=32, CAPS_LOCK=64, NUM_LOCK=128} ModifierMasks;
|
||||||
typedef enum { PRESS = 0, REPEAT = 1, RELEASE = 2} KeyAction;
|
typedef enum { PRESS = 0, REPEAT = 1, RELEASE = 2} KeyAction;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t key, shifted_key, alternate_key;
|
uint32_t key, shifted_key, alternate_key;
|
||||||
struct {
|
struct {
|
||||||
bool shift, alt, ctrl, super, hyper, meta;
|
bool shift, alt, ctrl, super, hyper, meta, numlock, capslock;
|
||||||
unsigned value;
|
unsigned value;
|
||||||
char encoded[4];
|
char encoded[4];
|
||||||
} mods;
|
} mods;
|
||||||
@ -49,12 +49,15 @@ is_modifier_key(const uint32_t key) {
|
|||||||
static inline void
|
static inline void
|
||||||
convert_glfw_mods(int mods, KeyEvent *ev) {
|
convert_glfw_mods(int mods, KeyEvent *ev) {
|
||||||
ev->mods.alt = (mods & GLFW_MOD_ALT) > 0, ev->mods.ctrl = (mods & GLFW_MOD_CONTROL) > 0, ev->mods.shift = (mods & GLFW_MOD_SHIFT) > 0, ev->mods.super = (mods & GLFW_MOD_SUPER) > 0, ev->mods.hyper = (mods & GLFW_MOD_HYPER) > 0, ev->mods.meta = (mods & GLFW_MOD_META) > 0;
|
ev->mods.alt = (mods & GLFW_MOD_ALT) > 0, ev->mods.ctrl = (mods & GLFW_MOD_CONTROL) > 0, ev->mods.shift = (mods & GLFW_MOD_SHIFT) > 0, ev->mods.super = (mods & GLFW_MOD_SUPER) > 0, ev->mods.hyper = (mods & GLFW_MOD_HYPER) > 0, ev->mods.meta = (mods & GLFW_MOD_META) > 0;
|
||||||
|
ev->mods.numlock = (mods & GLFW_MOD_NUM_LOCK) > 0, ev->mods.capslock = (mods & GLFW_MOD_CAPS_LOCK) > 0;
|
||||||
ev->mods.value = ev->mods.shift ? SHIFT : 0;
|
ev->mods.value = ev->mods.shift ? SHIFT : 0;
|
||||||
if (ev->mods.alt) ev->mods.value |= ALT;
|
if (ev->mods.alt) ev->mods.value |= ALT;
|
||||||
if (ev->mods.ctrl) ev->mods.value |= CTRL;
|
if (ev->mods.ctrl) ev->mods.value |= CTRL;
|
||||||
if (ev->mods.super) ev->mods.value |= SUPER;
|
if (ev->mods.super) ev->mods.value |= SUPER;
|
||||||
if (ev->mods.hyper) ev->mods.value |= HYPER;
|
if (ev->mods.hyper) ev->mods.value |= HYPER;
|
||||||
if (ev->mods.meta) ev->mods.value |= META;
|
if (ev->mods.meta) ev->mods.value |= META;
|
||||||
|
if (ev->mods.capslock) ev->mods.value |= CAPS_LOCK;
|
||||||
|
if (ev->mods.numlock) ev->mods.value |= NUM_LOCK;
|
||||||
snprintf(ev->mods.encoded, sizeof(ev->mods.encoded), "%u", ev->mods.value + 1);
|
snprintf(ev->mods.encoded, sizeof(ev->mods.encoded), "%u", ev->mods.value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
kitty/key_encoding.py
generated
20
kitty/key_encoding.py
generated
@ -212,16 +212,19 @@ class KeyEvent(NamedTuple):
|
|||||||
super: bool = False
|
super: bool = False
|
||||||
hyper: bool = False
|
hyper: bool = False
|
||||||
meta: bool = False
|
meta: bool = False
|
||||||
|
caps_lock: bool = False
|
||||||
|
num_lock: bool = False
|
||||||
|
|
||||||
def matches(self, spec: Union[str, ParsedShortcut], types: int = EventType.PRESS | EventType.REPEAT) -> bool:
|
def matches(self, spec: Union[str, ParsedShortcut], types: int = EventType.PRESS | EventType.REPEAT) -> bool:
|
||||||
|
mods = self.mods & ~(NUM_LOCK | CAPS_LOCK)
|
||||||
if not self.type & types:
|
if not self.type & types:
|
||||||
return False
|
return False
|
||||||
if isinstance(spec, str):
|
if isinstance(spec, str):
|
||||||
spec = parse_shortcut(spec)
|
spec = parse_shortcut(spec)
|
||||||
if (self.mods, self.key) == spec:
|
if (mods, self.key) == spec:
|
||||||
return True
|
return True
|
||||||
is_shifted = bool(self.shifted_key and self.shift)
|
is_shifted = bool(self.shifted_key and self.shift)
|
||||||
if is_shifted and (self.mods & ~SHIFT, self.shifted_key) == spec:
|
if is_shifted and (mods & ~SHIFT, self.shifted_key) == spec:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -245,6 +248,10 @@ class KeyEvent(NamedTuple):
|
|||||||
mods |= defines.GLFW_MOD_HYPER
|
mods |= defines.GLFW_MOD_HYPER
|
||||||
if self.meta:
|
if self.meta:
|
||||||
mods |= defines.GLFW_MOD_META
|
mods |= defines.GLFW_MOD_META
|
||||||
|
if self.caps_lock:
|
||||||
|
mods |= defines.GLFW_MOD_CAPS_LOCK
|
||||||
|
if self.num_lock:
|
||||||
|
mods |= defines.GLFW_MOD_NUM_LOCK
|
||||||
|
|
||||||
fnm = get_name_to_functional_number_map()
|
fnm = get_name_to_functional_number_map()
|
||||||
|
|
||||||
@ -257,7 +264,7 @@ class KeyEvent(NamedTuple):
|
|||||||
action=action, text=self.text)
|
action=action, text=self.text)
|
||||||
|
|
||||||
|
|
||||||
SHIFT, ALT, CTRL, SUPER, HYPER, META = 1, 2, 4, 8, 16, 32
|
SHIFT, ALT, CTRL, SUPER, HYPER, META, CAPS_LOCK, NUM_LOCK = 1, 2, 4, 8, 16, 32, 64, 128
|
||||||
enter_key = KeyEvent(key='ENTER')
|
enter_key = KeyEvent(key='ENTER')
|
||||||
backspace_key = KeyEvent(key='BACKSPACE')
|
backspace_key = KeyEvent(key='BACKSPACE')
|
||||||
config_mod_map = {
|
config_mod_map = {
|
||||||
@ -272,6 +279,8 @@ config_mod_map = {
|
|||||||
'CONTROL': CTRL,
|
'CONTROL': CTRL,
|
||||||
'HYPER': HYPER,
|
'HYPER': HYPER,
|
||||||
'META': META,
|
'META': META,
|
||||||
|
'NUM_LOCK': NUM_LOCK,
|
||||||
|
'CAPS_LOCK': CAPS_LOCK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -306,6 +315,7 @@ def decode_key_event(csi: str, csi_type: str) -> KeyEvent:
|
|||||||
mods=mods, shift=bool(mods & SHIFT), alt=bool(mods & ALT),
|
mods=mods, shift=bool(mods & SHIFT), alt=bool(mods & ALT),
|
||||||
ctrl=bool(mods & CTRL), super=bool(mods & SUPER),
|
ctrl=bool(mods & CTRL), super=bool(mods & SUPER),
|
||||||
hyper=bool(mods & HYPER), meta=bool(mods & META),
|
hyper=bool(mods & HYPER), meta=bool(mods & META),
|
||||||
|
caps_lock=bool(mods & CAPS_LOCK), num_lock=bool(mods & NUM_LOCK),
|
||||||
key=key_name(keynum),
|
key=key_name(keynum),
|
||||||
shifted_key=key_name(first_section[1] if len(first_section) > 1 else 0),
|
shifted_key=key_name(first_section[1] if len(first_section) > 1 else 0),
|
||||||
alternate_key=key_name(first_section[2] if len(first_section) > 2 else 0),
|
alternate_key=key_name(first_section[2] if len(first_section) > 2 else 0),
|
||||||
@ -362,6 +372,10 @@ def encode_key_event(key_event: KeyEvent) -> str:
|
|||||||
m |= 16
|
m |= 16
|
||||||
if key_event.meta:
|
if key_event.meta:
|
||||||
m |= 32
|
m |= 32
|
||||||
|
if key_event.caps_lock:
|
||||||
|
m |= 64
|
||||||
|
if key_event.num_lock:
|
||||||
|
m |= 128
|
||||||
if action > 1 or m:
|
if action > 1 or m:
|
||||||
ans += f';{m+1}'
|
ans += f';{m+1}'
|
||||||
if action > 1:
|
if action > 1:
|
||||||
|
|||||||
@ -5,11 +5,18 @@
|
|||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from .config import KeyAction, KeyMap, SequenceMap, SubSequenceMap
|
from .config import KeyAction, KeyMap, SequenceMap, SubSequenceMap
|
||||||
from .fast_data_types import KeyEvent
|
from .fast_data_types import (
|
||||||
|
GLFW_MOD_ALT, GLFW_MOD_CAPS_LOCK, GLFW_MOD_CONTROL, GLFW_MOD_HYPER,
|
||||||
|
GLFW_MOD_META, GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT, GLFW_MOD_SUPER, KeyEvent
|
||||||
|
)
|
||||||
from .types import SingleKey
|
from .types import SingleKey
|
||||||
from .typing import ScreenType
|
from .typing import ScreenType
|
||||||
|
|
||||||
|
|
||||||
|
mod_mask = GLFW_MOD_ALT | GLFW_MOD_CONTROL | GLFW_MOD_SHIFT | GLFW_MOD_SUPER | GLFW_MOD_META | GLFW_MOD_HYPER
|
||||||
|
lock_mask = GLFW_MOD_NUM_LOCK | GLFW_MOD_CAPS_LOCK
|
||||||
|
|
||||||
|
|
||||||
def keyboard_mode_name(screen: ScreenType) -> str:
|
def keyboard_mode_name(screen: ScreenType) -> str:
|
||||||
flags = screen.current_key_encoding_flags()
|
flags = screen.current_key_encoding_flags()
|
||||||
if flags:
|
if flags:
|
||||||
@ -18,22 +25,22 @@ def keyboard_mode_name(screen: ScreenType) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def get_shortcut(keymap: Union[KeyMap, SequenceMap], ev: KeyEvent) -> Optional[Union[KeyAction, SubSequenceMap]]:
|
def get_shortcut(keymap: Union[KeyMap, SequenceMap], ev: KeyEvent) -> Optional[Union[KeyAction, SubSequenceMap]]:
|
||||||
mods = ev.mods & 0b1111
|
mods = ev.mods & mod_mask
|
||||||
ans = keymap.get(SingleKey(mods, False, ev.key))
|
ans = keymap.get(SingleKey(mods, False, ev.key))
|
||||||
if ans is None and ev.shifted_key and mods & 0b1:
|
if ans is None and ev.shifted_key and mods & GLFW_MOD_SHIFT:
|
||||||
ans = keymap.get(SingleKey(mods & 0b1110, False, ev.shifted_key))
|
ans = keymap.get(SingleKey(mods & (~GLFW_MOD_SHIFT), False, ev.shifted_key))
|
||||||
if ans is None:
|
if ans is None:
|
||||||
ans = keymap.get(SingleKey(mods, True, ev.native_key))
|
ans = keymap.get(SingleKey(mods, True, ev.native_key))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def shortcut_matches(s: SingleKey, ev: KeyEvent) -> bool:
|
def shortcut_matches(s: SingleKey, ev: KeyEvent) -> bool:
|
||||||
mods = ev.mods & 0b1111
|
mods = ev.mods & mod_mask
|
||||||
smods = s.mods & 0b1111
|
smods = s.mods & mod_mask
|
||||||
if s.is_native:
|
if s.is_native:
|
||||||
return s.key == ev.native_key and smods == mods
|
return s.key == ev.native_key and smods == mods
|
||||||
if s.key == ev.key and mods == smods:
|
if s.key == ev.key and mods == smods:
|
||||||
return True
|
return True
|
||||||
if ev.shifted_key and mods & 0b1 and (mods & 0b1110) == smods and ev.shifted_key == s.key:
|
if ev.shifted_key and mods & GLFW_MOD_SHIFT and (mods & ~GLFW_MOD_SHIFT) == smods and ev.shifted_key == s.key:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user