aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/low-level-key.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/low-level-key.el')
-rw-r--r--lisp/low-level-key.el615
1 files changed, 323 insertions, 292 deletions
diff --git a/lisp/low-level-key.el b/lisp/low-level-key.el
index bc9311f82d0..8a8d912977d 100644
--- a/lisp/low-level-key.el
+++ b/lisp/low-level-key.el
@@ -1,26 +1,74 @@
1;;; -*- lexical-binding: t -*- 1;;; low-level-key.el --- Handling of key press/release events -*- lexical-binding: t -*-
2 2
3;; The physical-key event is like this: 3;; Copyright (C) 2025 Free Software Foundation, Inc.
4;; (low-level-key IS-KEY-PRESS KEY MODIFIER TIME FRAME) 4
5;; IS-KEY-PRESS is t if the key has been pressed, nil if it has been released. 5;; This file is part of GNU Emacs.
6;; KEY is the keysym number. 6
7;; MODIFIER is the modifier associated with this key. It is nil if the key is 7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; not a modifier. It can be one of the following symbols: shift, control, meta, 8;; it under the terms of the GNU General Public License as published by
9;; super, hyper, alt. It can also be t if the key is a modifier but it can't be 9;; the Free Software Foundation, either version 3 of the License, or
10;; identified, as in the PGTK backend. 10;; (at your option) any later version.
11;; TIME is the timestamp in milliseconds of the event. 11
12;; FRAME is the frame where the event happened. 12;; GNU Emacs is distributed in the hope that it will be useful,
13;; 13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; After calling 'llk-init' and setting a non-nil value for 14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; 'enable-low-level-key-events', events begin to be handled by 'llk-handler', 15;; GNU General Public License for more details.
16;; which tries to detect n-taps and calls the corresponding function. 16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Commentary:
21
22;; Emacs can send low-level key events, that correspond to key presses
23;; and releases. These events are by default disabled.
24
25;; When enabled by setting `enable-low-level-key-events' to a non-nil
26;; value, emacs will begin sending them, and they will be ignored as
27;; low-level-key is bound to `ignore' on `special-event-map'.
28
29;; This file sets a handler for them (`llk-handle') which generates
30;; input events for key presses, key releases and double and triple
31;; taps. These events can be bound to commands on normal keymaps.
32
33;; Because generating these events for all keys would interfere with
34;; normal keyboard input, they must be activated individually by calling
35;; the function `llk-bind'.
36
37;; The low-level-key event payload is described by the 'low-level-key'
38;; struct. Use 'cl-describe-type' to get more information about it.
17;; 39;;
18;; To implement other functionalities, you can replace llk-handler with 40;; After loading this file and setting a non-nil value for
19;; your own function. 41;; 'enable-low-level-key-events', events begin to be handled by
42;; 'llk-handle', which tries to detect n-taps, and creates input
43;; events. See 'llk-bind'.
44
45;; Code:
20 46
21(require 'cl-lib) 47(require 'cl-lib)
22 48
23;; User options 49(defvar llk-tap-timeout (let ((time (mouse-double-click-time)))
50 (if (> time 0) time 800))
51 "Time in milliseconds between key presses/releases to consider a double tap.
52For triple taps, the time is twice this value.")
53
54(cl-defstruct (low-level-key (:type list))
55 "Structure for low level key events.
56Received as low-level-key on `special-event-map'."
57 (event-type nil :type symbol
58 :documentation "Type of event: low-level-key")
59 (is-key-press nil :type boolean
60 :documentation "t if the key has been pressed, nil if it has been released.")
61 (key nil :type integer
62 :documentation "The keysym number.")
63 (modifier nil :type symbol
64 :documentation "Modifier associated with this key. It is nil if the key is
65not a modifier. It can be one of the following symbols: shift, control, meta,
66super, hyper, alt. It can also be t if the key is a modifier but it can't be
67identified, as in the PGTK backend.")
68 (time nil :type integer
69 :documentation "Timestamp in milliseconds of the event.")
70 (frame nil :type frame
71 :documentation "Frame where the event happened."))
24 72
25(defvar llk-bindings nil 73(defvar llk-bindings nil
26 "List of bindings for low level key events (press/release/tap). 74 "List of bindings for low level key events (press/release/tap).
@@ -28,315 +76,298 @@
28Use the `llk-bind' function to add bindings. See its documentation for 76Use the `llk-bind' function to add bindings. See its documentation for
29a description of the binding information.") 77a description of the binding information.")
30 78
31(defvar llk-tap-count 2 79(defvar llk-keysyms nil
32 "Number or key press/releases to consider a tap.") 80 "List of keysyms and their names.
81Each element has the form (CODE . KEYSYM), where code is a NUMBER and
82KEYSYM a symbol, such as `xk-shift-l'")
33 83
34(defvar llk-tap-timeout 1000 84;; TODO docstring.
35 "Time (ms) between consecutive key presses/releases to consider a tap.") 85(defun llk-bind (key &rest events)
86 "Activates low level event generation for a key.
36 87
37(defvar llk-tap-keys 88KEY can be a number or a symbol. The symbols `shift', `control',
38 '(xk-shift-l xk-shift-r xk-control-l xk-control-r meta) 89`meta', `super', `hyper', `alt' activate events for the corresponding
39 "Keys that can generate taps.") 90modifier keys. A number activates events for the corresponding KeySym.
40 91
41(defvar llk-keysyms nil 92EVENTS are symbols that activate one event. Possible values are `press',
42 "List of keysym numbers and their corresponding symbols. 93`release', `double' and `triple'.
94
95See `llk-keysyms' for a list of known values for KEY and their names.
96For each of those, there is a corresponding variable. It is better to
97use the variables to specify keys, as numerical values are
98platform-dependent. The names are parallel to those for KeySyms on X,
99as defined in `xkeysymdef.h'. For example, `XK_Shift_L' (the left shift
100key), corresponds to `xk-shift-l'.
101
102The `xkeysymdef.h' file defines different KeySyms for capital and small
103versions of latin letters. For this event, only the capital version is
104used, with the variables `xk-a', `xk-b', etc.
105
106Low level key events must be enabled with the variable
107`enable-low-level-key-events'.
108
109Once a key is activated with this function, input events will be
110generated for them, and can be bound to commands using normal keymaps.
43 111
44Each element has the form (KEYSYM . SYMBOL). The variable value for 112For example, activating the double tap for the left shift key:
45each symbol is the keysym. This list is initialized by `llk-init'.")
46 113
47(defvar llk-describe-next-press nil 114 (llk-bind xk-shift-l \\='double)
48 "Internal variable to mark that next key press should be described.")
49 115
50(defmacro define-xk (name x-keysym w32-keysym) 116will generate the event `double-xk-shift-l', than can be bound to a
117command with:
118
119 (keymap-global-set [double-xk-shift-l] COMMAND)
120
121Prefixes for events are `press-key-', `release-key-', `double-' and
122`triple-'.
123
124If you use a KeySym number that is not on `llk-keysyms', the events will
125use its numerical value."
126 (setq llk-bindings
127 (cl-delete-if (lambda (x) (eq (car x) key)) llk-bindings))
128 (push (append (list key) events) llk-bindings))
129
130;; We store the last events (key/modifier is-press timestamp) here to
131;; test for multitap. This is not the use the low-level-key struct.
132(defvar llk--event-history-for-tap nil
133 "Internal variable for detecting taps.")
134
135(defun llk--detect-n-tap (n timeout)
136 "Internal function to detect n-tap keys."
137 ;; Only care about last 2xN events
138 (ntake (* 2 n) llk--event-history-for-tap)
139 ;; If we have:
140 ;; - Exactly 2 * n events.
141 ;; - down, up, down, up, ...
142 ;; - not two much time between first and last
143 (and (eq (* 2 n) (length llk--event-history-for-tap))
144 (cl-every #'eq
145 (ntake (* 2 n)
146 (list nil t nil t nil t nil t
147 nil t nil t nil t nil t))
148 (mapcar 'cl-second llk--event-history-for-tap))
149 (< (- (cl-third (cl-first llk--event-history-for-tap))
150 (cl-third (car (last llk--event-history-for-tap))))
151 timeout)
152 (progn (setq llk--event-history-for-tap nil) t)))
153
154(defun llk--generate-event (key event-type)
155 (when (numberp key)
156 (let ((sym (cdr (assoc key llk-keysyms))))
157 (when sym
158 (setq key sym))))
159 (push (intern (format "%s-%s" event-type key))
160 unread-command-events))
161
162(defun llk--generate-events (key is-press binding timestamp)
163 (if is-press
164 (when (member 'press binding)
165 (llk--generate-event key 'press-key))
166 (when (member 'release binding)
167 (llk--generate-event key 'release-key)))
168
169 (let ((double (member 'double binding))
170 (triple (member 'triple binding)))
171 ;; a non-tap key clears the event history.
172 (if (or double triple)
173 (progn
174 ;; Clear the event history if it has events from another key.
175 (unless (equal (car (car llk--event-history-for-tap)) key)
176 (setq llk--event-history-for-tap nil))
177 (push (list key is-press timestamp) llk--event-history-for-tap)
178 (and double
179 (llk--detect-n-tap 2 llk-tap-timeout)
180 (llk--generate-event key 'double-key))
181 (and triple
182 (llk--detect-n-tap 3 (* 2 llk-tap-timeout))
183 (llk--generate-event key 'triple-key)))
184 ;; A non-tap key clears the event history.
185 (setq llk--event-history-for-tap nil))))
186
187(defun llk-handle ()
188 (interactive)
189 (let* ((key (low-level-key-key last-input-event))
190 (modifier (low-level-key-modifier last-input-event))
191 (timestamp (low-level-key-time last-input-event))
192 (is-press (low-level-key-is-key-press last-input-event))
193 (binding (assoc key llk-bindings))
194 (binding-modifier (assoc modifier llk-bindings)))
195 (if binding
196 (llk--generate-events key is-press binding timestamp)
197 (when binding-modifier
198 (llk--generate-events modifier is-press binding-modifier timestamp)))))
199
200(defmacro llk--define-xk (name x-keysym w32-keysym)
51 "Internal macro to define keysyms." 201 "Internal macro to define keysyms."
52 `(let ((ksym (pcase (window-system) 202 `(let ((ksym (pcase (window-system)
53 ('pgtk ,x-keysym) 203 ((or 'pgtk 'x) ,x-keysym)
54 ('x ,x-keysym)
55 ('w32 ,w32-keysym)))) 204 ('w32 ,w32-keysym))))
56 (defconst ,name ksym "Constant for a keysym value.") 205 (defconst ,name ksym "Constant for a keysym value.")
57 (push (cons ksym ',name) llk-keysyms))) 206 (push (cons ksym ',name) llk-keysyms)))
58 207
59(defun llk-define-keysyms () 208(defun llk--define-keysyms ()
60 "Initialize the keysym list, `llk-keysyms'. 209 "Initialize the keysym list, `llk-keysyms'."
61
62Called from `llk-init'."
63 (setq llk-keysyms nil) 210 (setq llk-keysyms nil)
64 211
65 ;; tty keys 212 ;; tty keys
66 (define-xk xk-backspace #xff08 #x08) ;; XK_BackSpace VK_BACK 213 (llk--define-xk xk-backspace #xff08 #x08) ;; XK_BackSpace VK_BACK
67 (define-xk xk-tab #xff09 #x09) ;; XK_Tab VK_TAB 214 (llk--define-xk xk-tab #xff09 #x09) ;; XK_Tab VK_TAB
68 (define-xk xk-clear #xff0b #x0C) ;; XK_Clear VK_CLEAR 215 (llk--define-xk xk-clear #xff0b #x0C) ;; XK_Clear VK_CLEAR
69 (define-xk xk-return #xff0d #x0D) ;; XK_Return VK_RETURN 216 (llk--define-xk xk-return #xff0d #x0D) ;; XK_Return VK_RETURN
70 (define-xk xk-pause #xff13 #x13) ;; XK_Pause VK_PAUSE 217 (llk--define-xk xk-pause #xff13 #x13) ;; XK_Pause VK_PAUSE
71 (define-xk xk-scroll-lock #xff14 #x91) ;; XK_Scroll_Lock VK_SCROLL 218 (llk--define-xk xk-scroll-lock #xff14 #x91) ;; XK_Scroll_Lock VK_SCROLL
72 (define-xk xk-escape #xff1B #x1B) ;; XK_Escape VK_ESCAPE 219 (llk--define-xk xk-escape #xff1B #x1B) ;; XK_Escape VK_ESCAPE
73 (define-xk xk-delete #xffff #x2E) ;; XK_Delete VK_DELETE 220 (llk--define-xk xk-delete #xffff #x2E) ;; XK_Delete VK_DELETE
74 221
75 ;; Cursor control and motion 222 ;; Cursor control and motion
76 (define-xk xk-home #xff50 #x24) ;; XK_Home VK_HOME 223 (llk--define-xk xk-home #xff50 #x24) ;; XK_Home VK_HOME
77 (define-xk xk-left #xff51 #x25) ;; XK_Left VK_LEFT 224 (llk--define-xk xk-left #xff51 #x25) ;; XK_Left VK_LEFT
78 (define-xk xk-up #xff52 #x26) ;; XK_Up VK_UP 225 (llk--define-xk xk-up #xff52 #x26) ;; XK_Up VK_UP
79 (define-xk xk-right #xff53 #x27) ;; XK_Right VK_RIGHT 226 (llk--define-xk xk-right #xff53 #x27) ;; XK_Right VK_RIGHT
80 (define-xk xk-down #xff54 #x28) ;; XK_Down VK_DOWN 227 (llk--define-xk xk-down #xff54 #x28) ;; XK_Down VK_DOWN
81 (define-xk xk-page-up #xff55 #x21) ;; XK_Page_Up VK_PRIOR 228 (llk--define-xk xk-page-up #xff55 #x21) ;; XK_Page_Up VK_PRIOR
82 (define-xk xk-page-down #xff56 #x22) ;; XK_Page_Down VK_NEXT 229 (llk--define-xk xk-page-down #xff56 #x22) ;; XK_Page_Down VK_NEXT
83 (define-xk xk-end #xff57 #x23) ;; XK_End VK_END 230 (llk--define-xk xk-end #xff57 #x23) ;; XK_End VK_END
84 (define-xk xk-begin #xff58 #x24) ;; XK_Begin VK_HOME 231 (llk--define-xk xk-begin #xff58 #x24) ;; XK_Begin VK_HOME
85 232
86 ;; Special Windows keyboard keys 233 ;; Special Windows keyboard keys
87 (define-xk xk-win-l #xFF5B #x5B) ;; XK_Win_L VK_LWIN 234 (llk--define-xk xk-win-l #xFF5B #x5B) ;; XK_Win_L VK_LWIN
88 (define-xk xk-win-r #xFF5C #x5C) ;; XK_Win_R VK_RWIN 235 (llk--define-xk xk-win-r #xFF5C #x5C) ;; XK_Win_R VK_RWIN
89 (define-xk xk-app #xFF5D #x5D) ;; XK_App VK_APPS 236 (llk--define-xk xk-app #xFF5D #x5D) ;; XK_App VK_APPS
90 237
91 ;; Misc functions 238 ;; Misc functions
92 (define-xk xk-select #xff60 #x29) ;; XK_Select VK_SELECT 239 (llk--define-xk xk-select #xff60 #x29) ;; XK_Select VK_SELECT
93 (define-xk xk-print #xff61 #x2A) ;; XK_Print VK_PRINT 240 (llk--define-xk xk-print #xff61 #x2A) ;; XK_Print VK_PRINT
94 (define-xk xk-insert #xff64 #x2D) ;; XK_Insert VK_INSERT 241 (llk--define-xk xk-insert #xff64 #x2D) ;; XK_Insert VK_INSERT
95 (define-xk xk-num-lock #xff7f #x90) ;; XK_Num_Lock VK_NUMLOCK 242 (llk--define-xk xk-num-lock #xff7f #x90) ;; XK_Num_Lock VK_NUMLOCK
96 243
97 ;; Keypad 244 ;; Keypad
98 ;; TODO: Check values for MS-Windows 245 ;; TODO: Check values for MS-Windows
99 (define-xk xk-kp-enter #xff8d nil) ;; XK_KP_Enter ??? 246 (llk--define-xk xk-kp-enter #xff8d nil) ;; XK_KP_Enter ???
100 (define-xk xk-kp-multiply #xffaa nil) ;; XK_KP_Multiply ??? 247 (llk--define-xk xk-kp-multiply #xffaa nil) ;; XK_KP_Multiply ???
101 (define-xk xk-kp-add #xffab nil) ;; XK_KP_Add ??? 248 (llk--define-xk xk-kp-add #xffab nil) ;; XK_KP_Add ???
102 (define-xk xk-kp-subtract #xffad nil) ;; XK_KP_Subtract ??? 249 (llk--define-xk xk-kp-subtract #xffad nil) ;; XK_KP_Subtract ???
103 (define-xk xk-kp-decimal #xffae nil) ;; XK_KP_Decimal ??? 250 (llk--define-xk xk-kp-decimal #xffae nil) ;; XK_KP_Decimal ???
104 (define-xk xk-kp-divide #xffaf nil) ;; XK_KP_Divide ??? 251 (llk--define-xk xk-kp-divide #xffaf nil) ;; XK_KP_Divide ???
105 (define-xk xk-kp-0 #xffb0 #x60) ;; XK_KP_0 VK_NUMPAD0 252 (llk--define-xk xk-kp-0 #xffb0 #x60) ;; XK_KP_0 VK_NUMPAD0
106 (define-xk xk-kp-1 #xffb1 #x61) ;; XK_KP_1 VK_NUMPAD1 253 (llk--define-xk xk-kp-1 #xffb1 #x61) ;; XK_KP_1 VK_NUMPAD1
107 (define-xk xk-kp-2 #xffb2 #x62) ;; XK_KP_2 VK_NUMPAD2 254 (llk--define-xk xk-kp-2 #xffb2 #x62) ;; XK_KP_2 VK_NUMPAD2
108 (define-xk xk-kp-3 #xffb3 #x63) ;; XK_KP_3 VK_NUMPAD3 255 (llk--define-xk xk-kp-3 #xffb3 #x63) ;; XK_KP_3 VK_NUMPAD3
109 (define-xk xk-kp-4 #xffb4 #x64) ;; XK_KP_4 VK_NUMPAD4 256 (llk--define-xk xk-kp-4 #xffb4 #x64) ;; XK_KP_4 VK_NUMPAD4
110 (define-xk xk-kp-5 #xffb5 #x65) ;; XK_KP_5 VK_NUMPAD5 257 (llk--define-xk xk-kp-5 #xffb5 #x65) ;; XK_KP_5 VK_NUMPAD5
111 (define-xk xk-kp-6 #xffb6 #x66) ;; XK_KP_6 VK_NUMPAD6 258 (llk--define-xk xk-kp-6 #xffb6 #x66) ;; XK_KP_6 VK_NUMPAD6
112 (define-xk xk-kp-7 #xffb7 #x67) ;; XK_KP_7 VK_NUMPAD7 259 (llk--define-xk xk-kp-7 #xffb7 #x67) ;; XK_KP_7 VK_NUMPAD7
113 (define-xk xk-kp-8 #xffb8 #x68) ;; XK_KP_8 VK_NUMPAD8 260 (llk--define-xk xk-kp-8 #xffb8 #x68) ;; XK_KP_8 VK_NUMPAD8
114 (define-xk xk-kp-9 #xffb9 #x69) ;; XK_KP_9 VK_NUMPAD9 261 (llk--define-xk xk-kp-9 #xffb9 #x69) ;; XK_KP_9 VK_NUMPAD9
115 262
116 ;; Function keys 263 ;; Function keys
117 (define-xk xk-f1 #xffbe #x70) ;; XK_F1 VK_F1 264 (llk--define-xk xk-f1 #xffbe #x70) ;; XK_F1 VK_F1
118 (define-xk xk-f2 #xffbf #x71) ;; XK_F2 VK_F2 265 (llk--define-xk xk-f2 #xffbf #x71) ;; XK_F2 VK_F2
119 (define-xk xk-f3 #xffc0 #x72) ;; XK_F3 VK_F3 266 (llk--define-xk xk-f3 #xffc0 #x72) ;; XK_F3 VK_F3
120 (define-xk xk-f4 #xffc1 #x73) ;; XK_F4 VK_F4 267 (llk--define-xk xk-f4 #xffc1 #x73) ;; XK_F4 VK_F4
121 (define-xk xk-f5 #xffc2 #x74) ;; XK_F5 VK_F5 268 (llk--define-xk xk-f5 #xffc2 #x74) ;; XK_F5 VK_F5
122 (define-xk xk-f6 #xffc3 #x75) ;; XK_F6 VK_F6 269 (llk--define-xk xk-f6 #xffc3 #x75) ;; XK_F6 VK_F6
123 (define-xk xk-f7 #xffc4 #x76) ;; XK_F7 VK_F7 270 (llk--define-xk xk-f7 #xffc4 #x76) ;; XK_F7 VK_F7
124 (define-xk xk-f8 #xffc5 #x77) ;; XK_F8 VK_F8 271 (llk--define-xk xk-f8 #xffc5 #x77) ;; XK_F8 VK_F8
125 (define-xk xk-f9 #xffc6 #x78) ;; XK_F9 VK_F9 272 (llk--define-xk xk-f9 #xffc6 #x78) ;; XK_F9 VK_F9
126 (define-xk xk-f10 #xffc7 #x79) ;; XK_F10 VK_F10 273 (llk--define-xk xk-f10 #xffc7 #x79) ;; XK_F10 VK_F10
127 (define-xk xk-f11 #xffc8 #x7A) ;; XK_F11 VK_F11 274 (llk--define-xk xk-f11 #xffc8 #x7A) ;; XK_F11 VK_F11
128 (define-xk xk-f12 #xffc9 #x7B) ;; XK_F12 VK_F12 275 (llk--define-xk xk-f12 #xffc9 #x7B) ;; XK_F12 VK_F12
129 (define-xk xk-f13 #xffca #x7C) ;; XK_F13 VK_F13 276 (llk--define-xk xk-f13 #xffca #x7C) ;; XK_F13 VK_F13
130 (define-xk xk-f14 #xffcb #x7D) ;; XK_F14 VK_F14 277 (llk--define-xk xk-f14 #xffcb #x7D) ;; XK_F14 VK_F14
131 (define-xk xk-f15 #xffcc #x7E) ;; XK_F15 VK_F15 278 (llk--define-xk xk-f15 #xffcc #x7E) ;; XK_F15 VK_F15
132 (define-xk xk-f16 #xffcd #x7F) ;; XK_F16 VK_F16 279 (llk--define-xk xk-f16 #xffcd #x7F) ;; XK_F16 VK_F16
133 (define-xk xk-f17 #xffce #x80) ;; XK_F17 VK_F17 280 (llk--define-xk xk-f17 #xffce #x80) ;; XK_F17 VK_F17
134 (define-xk xk-f18 #xffcf #x81) ;; XK_F18 VK_F18 281 (llk--define-xk xk-f18 #xffcf #x81) ;; XK_F18 VK_F18
135 (define-xk xk-f19 #xffd0 #x82) ;; XK_F19 VK_F19 282 (llk--define-xk xk-f19 #xffd0 #x82) ;; XK_F19 VK_F19
136 (define-xk xk-f20 #xffd1 #x83) ;; XK_F20 VK_F20 283 (llk--define-xk xk-f20 #xffd1 #x83) ;; XK_F20 VK_F20
137 (define-xk xk-f21 #xffd2 #x84) ;; XK_F21 VK_F21 284 (llk--define-xk xk-f21 #xffd2 #x84) ;; XK_F21 VK_F21
138 (define-xk xk-f22 #xffd3 #x85) ;; XK_F22 VK_F22 285 (llk--define-xk xk-f22 #xffd3 #x85) ;; XK_F22 VK_F22
139 (define-xk xk-f23 #xffd4 #x86) ;; XK_F23 VK_F23 286 (llk--define-xk xk-f23 #xffd4 #x86) ;; XK_F23 VK_F23
140 (define-xk xk-f24 #xffd5 #x87) ;; XK_F24 VK_F24 287 (llk--define-xk xk-f24 #xffd5 #x87) ;; XK_F24 VK_F24
141 288
142 ;; Modifier keys 289 ;; Modifier keys
143 (define-xk xk-shift-l #xffe1 #xA0) ;; XK_Shift_L VK_LSHIFT 290 (llk--define-xk xk-shift-l #xffe1 #xA0) ;; XK_Shift_L VK_LSHIFT
144 (define-xk xk-shift-r #xffe2 #xA1) ;; XK_Shift_R VK_RSHIFT 291 (llk--define-xk xk-shift-r #xffe2 #xA1) ;; XK_Shift_R VK_RSHIFT
145 (define-xk xk-control-l #xffe3 #xA2) ;; XK_Control_L VK_LCONTROL 292 (llk--define-xk xk-control-l #xffe3 #xA2) ;; XK_Control_L VK_LCONTROL
146 (define-xk xk-control-r #xffe4 #xA3) ;; XK_Control_R VK_RCONTROL 293 (llk--define-xk xk-control-r #xffe4 #xA3) ;; XK_Control_R VK_RCONTROL
147 (define-xk xk-caps-lock #xffe5 #x14) ;; XK_Caps_Lock VK_CAPITAL 294 (llk--define-xk xk-caps-lock #xffe5 #x14) ;; XK_Caps_Lock VK_CAPITAL
148 (define-xk xk-metal-l #xffe7 nil) ;; XK_Meta_L 295 (llk--define-xk xk-meta-l #xffe7 nil) ;; XK_Meta_L
149 (define-xk xk-metal-t #xffee nil) ;; XK_Meta_R 296 (llk--define-xk xk-meta-r #xffee nil) ;; XK_Meta_R
150 (define-xk xk-alt-l #xffe9 #xA4) ;; XK_Alt_L VK_LMENU 297 (llk--define-xk xk-alt-l #xffe9 #xA4) ;; XK_Alt_L VK_LMENU
151 (define-xk xk-alt-r #xffea #xA5) ;; XK_Alt_R VK_RMENU 298 (llk--define-xk xk-alt-r #xffea #xA5) ;; XK_Alt_R VK_RMENU
152 (define-xk xk-super-l #xffeb nil) ;; XK_Super_L 299 (llk--define-xk xk-super-l #xffeb nil) ;; XK_Super_L
153 (define-xk xk-super-r #xffec nil) ;; XK_Super_R 300 (llk--define-xk xk-super-r #xffec nil) ;; XK_Super_R
154 (define-xk xk-hyper-l #xffed nil) ;; XK_Hyper_L 301 (llk--define-xk xk-hyper-l #xffed nil) ;; XK_Hyper_L
155 (define-xk xk-hyper-r #xffee nil) ;; XK_Hyper_R 302 (llk--define-xk xk-hyper-r #xffee nil) ;; XK_Hyper_R
156 303
157 ;; Latin 1 304 ;; Latin 1
158 ;; For numbers and letters, MS-Windows does not define constant names. 305 ;; For numbers and letters, MS-Windows does not define constant names.
159 ;; X11 defines distinct keysyms for lowercase and uppercase 306 ;; X11 defines distinct keysyms for lowercase and uppercase
160 ;; letters. We use only the uppercase ones. Events with lowercase 307 ;; letters. We use only the uppercase ones. Events with lowercase
161 ;; letters are converted to uppercase. 308 ;; letters are converted to uppercase.
162 (define-xk xk-space #x0020 #x20) ;; XK_space VK_SPACE 309 (llk--define-xk xk-space #x0020 #x20) ;; XK_space VK_SPACE
163 (define-xk xk-0 #x0030 #x30) ;; XK_0 310 (llk--define-xk xk-0 #x0030 #x30) ;; XK_0
164 (define-xk xk-1 #x0031 #x31) ;; XK_1 311 (llk--define-xk xk-1 #x0031 #x31) ;; XK_1
165 (define-xk xk-2 #x0032 #x32) ;; XK_2 312 (llk--define-xk xk-2 #x0032 #x32) ;; XK_2
166 (define-xk xk-3 #x0033 #x33) ;; XK_3 313 (llk--define-xk xk-3 #x0033 #x33) ;; XK_3
167 (define-xk xk-4 #x0034 #x34) ;; XK_4 314 (llk--define-xk xk-4 #x0034 #x34) ;; XK_4
168 (define-xk xk-5 #x0035 #x35) ;; XK_5 315 (llk--define-xk xk-5 #x0035 #x35) ;; XK_5
169 (define-xk xk-6 #x0036 #x36) ;; XK_6 316 (llk--define-xk xk-6 #x0036 #x36) ;; XK_6
170 (define-xk xk-7 #x0037 #x37) ;; XK_7 317 (llk--define-xk xk-7 #x0037 #x37) ;; XK_7
171 (define-xk xk-8 #x0038 #x38) ;; XK_8 318 (llk--define-xk xk-8 #x0038 #x38) ;; XK_8
172 (define-xk xk-9 #x0039 #x39) ;; XK_9 319 (llk--define-xk xk-9 #x0039 #x39) ;; XK_9
173 (define-xk xk-a #x0041 #x41) ;; XK_A 320 (llk--define-xk xk-a #x0041 #x41) ;; XK_A
174 (define-xk xk-b #x0042 #x42) ;; XK_B 321 (llk--define-xk xk-b #x0042 #x42) ;; XK_B
175 (define-xk xk-c #x0043 #x43) ;; XK_C 322 (llk--define-xk xk-c #x0043 #x43) ;; XK_C
176 (define-xk xk-d #x0044 #x44) ;; XK_D 323 (llk--define-xk xk-d #x0044 #x44) ;; XK_D
177 (define-xk xk-e #x0045 #x45) ;; XK_E 324 (llk--define-xk xk-e #x0045 #x45) ;; XK_E
178 (define-xk xk-f #x0046 #x46) ;; XK_F 325 (llk--define-xk xk-f #x0046 #x46) ;; XK_F
179 (define-xk xk-g #x0047 #x47) ;; XK_G 326 (llk--define-xk xk-g #x0047 #x47) ;; XK_G
180 (define-xk xk-h #x0048 #x48) ;; XK_H 327 (llk--define-xk xk-h #x0048 #x48) ;; XK_H
181 (define-xk xk-i #x0049 #x49) ;; XK_I 328 (llk--define-xk xk-i #x0049 #x49) ;; XK_I
182 (define-xk xk-j #x004A #x4A) ;; XK_J 329 (llk--define-xk xk-j #x004A #x4A) ;; XK_J
183 (define-xk xk-k #x004B #x4B) ;; XK_K 330 (llk--define-xk xk-k #x004B #x4B) ;; XK_K
184 (define-xk xk-l #x004C #x4C) ;; XK_L 331 (llk--define-xk xk-l #x004C #x4C) ;; XK_L
185 (define-xk xk-m #x004D #x4D) ;; XK_M 332 (llk--define-xk xk-m #x004D #x4D) ;; XK_M
186 (define-xk xk-n #x004E #x4E) ;; XK_N 333 (llk--define-xk xk-n #x004E #x4E) ;; XK_N
187 (define-xk xk-o #x004F #x4F) ;; XK_O 334 (llk--define-xk xk-o #x004F #x4F) ;; XK_O
188 (define-xk xk-p #x0050 #x50) ;; XK_P 335 (llk--define-xk xk-p #x0050 #x50) ;; XK_P
189 (define-xk xk-q #x0051 #x51) ;; XK_Q 336 (llk--define-xk xk-q #x0051 #x51) ;; XK_Q
190 (define-xk xk-r #x0052 #x52) ;; XK_R 337 (llk--define-xk xk-r #x0052 #x52) ;; XK_R
191 (define-xk xk-s #x0053 #x53) ;; XK_S 338 (llk--define-xk xk-s #x0053 #x53) ;; XK_S
192 (define-xk xk-t #x0054 #x54) ;; XK_T 339 (llk--define-xk xk-t #x0054 #x54) ;; XK_T
193 (define-xk xk-u #x0055 #x55) ;; XK_U 340 (llk--define-xk xk-u #x0055 #x55) ;; XK_U
194 (define-xk xk-v #x0056 #x56) ;; XK_V 341 (llk--define-xk xk-v #x0056 #x56) ;; XK_V
195 (define-xk xk-w #x0057 #x57) ;; XK_W 342 (llk--define-xk xk-w #x0057 #x57) ;; XK_W
196 (define-xk xk-x #x0058 #x58) ;; XK_X 343 (llk--define-xk xk-x #x0058 #x58) ;; XK_X
197 (define-xk xk-y #x0059 #x59) ;; XK_Y 344 (llk--define-xk xk-y #x0059 #x59) ;; XK_Y
198 (define-xk xk-z #x005A #x5A));; XK_Z 345 (llk--define-xk xk-z #x005A #x5A));; XK_Z
199
200(defun llk-init ()
201 "Initialize low level key events.
202
203Fills the `llk-keysyms' list, and binds the `low-level-key' event
204to the `llk-handle' function. Resets the `llk-bindings' list.
205Besides calling this function, you need to set `enable-low-level-key-events'
206to a non-nil value."
207 (interactive)
208 (llk-define-keysyms)
209 (define-key special-event-map [low-level-key] 'llk-handle)
210 (setq llk-bindings nil))
211
212(defsubst event-is-key-press (event)
213 "Return the value of the IS-KEY-PRESS field of the EVENT, a low level key event."
214 (declare (side-effect-free t))
215 (if (consp event) (nth 1 event)))
216
217(defsubst event-keysym (event)
218 "Return the value of the KEY field of the EVENT, a low level key event."
219 (declare (side-effect-free t))
220 (if (consp event) (nth 2 event)))
221
222(defsubst event-modifier (event)
223 "Return the value of the MODIFIER field of the EVENT, a low level key event."
224 (declare (side-effect-free t))
225 (if (consp event) (nth 3 event)))
226
227(defsubst event-time (event)
228 "Return the value of the TIME field of the EVENT, a low level key event."
229 (declare (side-effect-free t))
230 (if (consp event) (nth 4 event)))
231
232;; For example:
233;; Bind key tap to command
234;; (llk-bind 'tap 'xk-shift-l 'delete-other-windows)
235;; Bind modifier tap to command
236;; (llk-bind 'tap 'shift 'delete-other-windows)
237;; Bind tap to hyper modifier
238;; (llk-bind 'tap 'xk-shift-r (lambda ()
239;; (message "H-...")
240;; (setq unread-command-events
241;; (append (event-apply-hyper-modifier nil) nil))))
242;; Can bind to a command or function
243(defun llk-bind (action key function)
244 "Bind a command or function to a low level key event.
245
246The only action supported currently is `tap'. The key can be a keysym
247symbol, or a modifier symbol (shift, control, alt, meta, hyper, super).
248If there is no keysym symbol for a key, use the keysym number."
249 (push (list action key function) llk-bindings))
250
251;; We store the last events (key/modifier is-press timestamp) here to
252;; test for multitap.
253(defvar llk-events nil
254 "Internal variable for detecting taps.")
255
256;; If positive, return key (xk-shift-l, etc) else return nil.
257(defun llk-detect-n-tap (n timeout)
258 "Internal function to detect n-tap keys."
259 (let (key
260 (is-press (event-is-key-press last-input-event))
261 ;; convert number to keysym symbol
262 (keysym (cdr (assoc (event-keysym last-input-event) llk-keysyms)))
263 (timestamp (event-time last-input-event))
264 (modifier (event-modifier last-input-event)))
265
266 ;; if ehte is no symbol for this key, use its keysym number
267 (unless keysym (setq keysym (event-keysym last-input-event)))
268
269 ;; look in llk-tap-keys for the key, then the modifier
270 (if (member keysym llk-tap-keys)
271 (setq key keysym)
272 (if (member modifier llk-tap-keys)
273 (setq key modifier)))
274
275 (if (not key)
276 ;; Key not in tap list, clear history
277 (setq llk-events nil)
278 ;; Clear it also if the first element is from a different key
279 (and llk-events
280 (not (equal (car (car llk-events)) key))
281 (setq llk-events nil))
282 (push (list key is-press timestamp) llk-events)
283 ;; Only care about last 2xN events
284 (ntake (* 2 n) llk-events)
285 ;; If we have:
286 ;; - Exactly 2 * n events.
287 ;; - down, up, down, up, ...
288 ;; - not two much time between first and last
289 (and (eq (* 2 n) (length llk-events))
290 (cl-every 'eq
291 (ntake (* 2 n)
292 (list nil t nil t nil t nil t
293 nil t nil t nil t nil t))
294 (mapcar 'cl-second llk-events))
295 (< (- (cl-third (cl-first llk-events))
296 (cl-third (car (last llk-events))))
297 timeout)
298 (progn
299 (setq llk-events nil)
300 key)))))
301 346
302(defun describe-low-level-key () 347(defun describe-low-level-key ()
303 "Wait for key press and describe the low level key event it generates." 348 "Wait for key press and describe the low-level key event it generates."
304 (interactive) 349 (interactive)
305 (setq llk-describe-next-press t)) 350 (define-key special-event-map [low-level-key] 'llk--describe))
306
307(defun llk-show-event-description ()
308 "Show information about the last low level key event."
309 (setq llk-describe-next-press nil)
310 (with-help-window (help-buffer)
311 (insert "\n")
312 (let* ((xk (event-keysym last-input-event))
313 (sym (assoc xk llk-keysyms)))
314 (insert (format "Keysym number: %d (#x%X),\n" xk xk))
315 (if sym
316 (insert (format "which corresponds to named key %s.\n\n" (cdr sym)))
317 (insert "which does not correspond to any known named key.\n\n"))
318 (if (event-modifier last-input-event)
319 (insert (format "This key corresponds to the %s modifier.\n\n"
320 (event-modifier last-input-event)))
321 (insert "This key does not correspond to a modifier.\n\n"))
322 (insert "See the value of the `llk-keysyms' variable for a list of known keys.\n"))))
323 351
324(defun llk-handle () 352(defun llk--describe ()
325 "Internal function to handle low level key events." 353 "Internal function for `special-event-map' to describe low level key events."
326 (interactive) 354 (interactive)
327 (if (and (event-is-key-press last-input-event) 355 (when (low-level-key-is-key-press last-input-event)
328 llk-describe-next-press) 356 (define-key special-event-map [low-level-key] 'llk-handle)
329 (llk-show-event-description) 357 (with-help-window (help-buffer)
330 (let ((tap-key (llk-detect-n-tap 358 (insert "\n")
331 llk-tap-count 359 (let* ((xk (low-level-key-key last-input-event))
332 llk-tap-timeout))) 360 (sym (assoc xk llk-keysyms)))
333 (when tap-key 361 (insert (format "Keysym number: %d (#x%X),\n" xk xk))
334 (let ((func (cl-third 362 (if sym
335 (seq-find 363 (insert (format "which corresponds to named key %s.\n\n" (cdr sym)))
336 (lambda (b) 364 (insert "which does not correspond to any known named key.\n\n"))
337 (and (eq (cl-first b) 'tap) 365 (if (low-level-key-modifier last-input-event)
338 (eq (cl-second b) tap-key))) 366 (insert (format "This key corresponds to the %s modifier.\n\n"
339 llk-bindings)))) 367 (low-level-key-modifier last-input-event)))
340 (cond 368 (insert "This key does not correspond to a modifier.\n\n"))
341 ((commandp func) (call-interactively func)) 369 (insert "See the value of the `llk-keysyms' variable for a list of known keys.\n")))))
342 ((functionp func) (funcall func)))))))) 370
371(llk--define-keysyms)
372(define-key special-event-map [low-level-key] 'llk-handle)
373(setq llk-bindings nil)