update packages

This commit is contained in:
2025-06-22 17:08:08 +02:00
parent 54e5633369
commit 16a0a6db93
558 changed files with 68349 additions and 26568 deletions

View File

@@ -1,13 +1,10 @@
(define-package "key-chord" "20240910.1441" "map pairs of simultaneously pressed keys to commands"
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "key-chord" "20250330.2011"
"Map pairs of simultaneously pressed keys to commands."
'((emacs "24"))
:commit "fc75b1451759121601110da8ddfadcf5156318af" :authors
'(("David Andersson" . "l.david.anderssonsverige.nu"))
:maintainers
'(("David Andersson" . "l.david.anderssonsverige.nu"))
:maintainer
'("David Andersson" . "l.david.anderssonsverige.nu")
:keywords
'("keyboard" "chord" "input"))
;; Local Variables:
;; no-byte-compile: t
;; End:
:url "https://github.com/LemonBreezes/key-chord"
:commit "cb646e815c61f253ad9fdfbe058049dda4e2b32b"
:revdesc "cb646e815c61"
:keywords '("keyboard" "chord" "input")
:authors '(("David Andersson" . "l.david.anderssonsverige.nu"))
:maintainers '(("LemonBreezes" . "look@strawberrytea.xyz")))

View File

@@ -1,11 +1,15 @@
;;; key-chord.el --- map pairs of simultaneously pressed keys to commands -*- lexical-binding: t; -*-
;;; key-chord.el --- map pairs of simultaneously pressed keys to commands
;; -*- lexical-binding: t; -*-
;; Copyright (C) 2003, 2005, 2008, 2012 David Andersson
;; Author: David Andersson <l.david.andersson(at)sverige.nu>
;; Package-Version: 0.7.1
;; Maintainer: LemonBreezes <look@strawberrytea.xyz>
;; Package-Version: 20250330.2011
;; Package-Revision: cb646e815c61
;; Package-Requires: ((emacs "24"))
;; Keywords: keyboard chord input
;; URL: https://github.com/LemonBreezes/key-chord
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
@@ -35,23 +39,66 @@
"Map pairs of simultaneously pressed keys to commands."
:group 'bindings)
(defun key-chord-in-read-char-context-p ()
"Return non-nil if we're in a read-char or similar context.
This is determined by checking if `overriding-local-map` is set to
one of the special read keymaps."
(and overriding-local-map
(memq overriding-local-map
(list read-key-empty-map read-key-full-map))))
(defcustom key-chord-two-keys-delay 0.1
"Max time delay between two key press to be considered a key chord."
:type 'float)
(defcustom key-chord-one-key-delay 0.2
"Max time delay between two press of the same key to be considered a key chord.
This should normally be a little longer than `key-chord-two-keys-delay'."
"Max time delay between two press of the same key for a chord.
This should normally be a little longer than
`key-chord-two-keys-delay'."
:type 'float)
(defcustom key-chord-in-macros t
(defcustom key-chord-in-macros nil
"If nil, don't expand key chords when executing keyboard macros.
If non-nil, expand chord sequenses in macros, but only if a
similar chord was entered during the last interactive macro
recording. (This carries a bit of guesswork. We can't know for
sure when executing whether two keys were typed quickly or slowly
when recorded.)"
If non-nil, expand chord sequenses in macros, but only if a similar
chord was entered during the last interactive macro recording. (This
carries a bit of guesswork. We can't know for sure when executing
whether two keys were typed quickly or slowly when recorded. Be careful
enabling this as it could cause key chords to be expanded in places
where they shouldn't be)."
:type 'boolean)
(defcustom key-chord-one-key-min-delay 0.0
"Minimum delay (in seconds) between two presses for a double-tap key chord.
The delay applies for chords using the same key. If the delay between two
identical key presses is less than this value (as when holding a key), the
chord will not trigger."
:type 'float)
(defcustom key-chord-typing-detection nil
"If non-nil, detect typing and temporarily disable chord detection.
This helps avoid accidental chord triggering during fast typing. This
also dramatically improves the performance of key-chord when typing text
by acting like a debounce."
:type 'boolean)
(defcustom key-chord-typing-speed-threshold 0.1
"Maximum delay between keystrokes to be considered part of typing flow.
Measured in seconds. If keys are pressed faster than this threshold,
key-chord detection will be temporarily disabled."
:type 'float)
(defcustom key-chord-typing-reset-delay 0.5
"Time after which to reset typing detection if no keys are pressed.
Measured in seconds. After this much idle time, key-chord detection
will be re-enabled."
:type 'float)
(defcustom key-chord-use-key-tracking t
"If non-nil, track which keys are used in chords to optimize lookups.
This improves performance by avoiding unnecessary `key-chord-lookup-key'
calls. However, it could potentially cause issues if key chords are
defined outside of the normal key-chord-define* functions."
:type 'boolean)
;; Internal vars
@@ -67,6 +114,20 @@ when recorded.)"
(defvar key-chord-in-last-kbd-macro nil)
(defvar key-chord-defining-kbd-macro nil)
;; Typing detection variables
(defvar key-chord-in-typing-flow nil
"Non-nil when user appears to be typing text rather than executing commands.")
(defvar key-chord-last-key-time nil
"Time when the last key was pressed.")
(defvar key-chord-typing-reset-time nil
"Time after which typing flow should be reset.")
;; Key tracking for optimization
(defvar key-chord-keys-in-use (make-vector 256 nil)
"Vector indicating which keys are used in any chord.")
;;;###autoload
(define-minor-mode key-chord-mode
"Map pairs of simultaneously pressed keys to commands.
@@ -77,7 +138,8 @@ and `key-chord-one-key-delay'."
:global t
(setq input-method-function
(and key-chord-mode
'key-chord-input-method)))
'key-chord-input-method))
(key-chord-reset-typing-detection))
;;;###autoload
(defun key-chord-define-global (keys command)
@@ -121,6 +183,48 @@ cases is shared with all other buffers in the same major mode."
(interactive "sUnset key chord locally (2 keys): ")
(key-chord-define (current-local-map) keys nil))
;;;###autoload
(defun key-chord-register-keys (key1 key2)
"Register KEY1 and KEY2 as being used in a key chord.
This function should be called by packages that define key chords
outside of the standard key-chord-define functions."
;; Always register keys regardless of key-tracking setting
(when (and (integerp key1) (< key1 256))
(aset key-chord-keys-in-use key1 t))
(when (and (integerp key2) (< key2 256))
(aset key-chord-keys-in-use key2 t)))
;;;###autoload
(defun key-chord-unregister-keys (key1 key2)
"Unregister KEY1 and KEY2 as being used in a key chord.
This should only be called if you're certain these keys are not
used in any other chords."
;; Always attempt to unregister keys regardless of key-tracking setting
;; Only unregister if we're sure the keys aren't used elsewhere
(let ((remove-key1 t)
(remove-key2 t))
;; Check if keys are used in any other chords
(let ((maps (list (current-global-map) (current-local-map))))
(dolist (map (append maps (current-minor-mode-maps)))
(when map
;; Check if key1 is used in any other chord
(dotimes (k 256)
(when (and (not (and (= k key2) (= key1 key2)))
(or (key-chord-lookup-key1 map (vector 'key-chord key1 k))
(key-chord-lookup-key1 map (vector 'key-chord k key1))))
(setq remove-key1 nil)))
;; Check if key2 is used in any other chord
(dotimes (k 256)
(when (and (not (and (= k key1) (= key1 key2)))
(or (key-chord-lookup-key1 map (vector 'key-chord key2 k))
(key-chord-lookup-key1 map (vector 'key-chord k key2))))
(setq remove-key2 nil))))))
;; Remove keys from tracking vector if not used elsewhere
(when remove-key1 (aset key-chord-keys-in-use key1 nil))
(when remove-key2 (aset key-chord-keys-in-use key2 nil))))
;;;###autoload
(defun key-chord-define (keymap keys command)
"Define in KEYMAP, a key-chord of the two keys in KEYS starting a COMMAND.
@@ -131,19 +235,28 @@ can be used.
COMMAND can be an interactive function, a string, or nil.
If COMMAND is nil, the key-chord is removed."
(if (/= 2 (length keys))
(error "Key-chord keys must have two elements"))
;; Exotic chars in a string are >255 but define-key wants 128..255
;; for those.
(let ((key1 (logand 255 (aref keys 0)))
(key2 (logand 255 (aref keys 1))))
(when (/= 2 (length keys))
(error "Key-chord keys must have two elements"))
(let ((key1 (aref keys 0))
(key2 (aref keys 1)))
;; Check that both keys are bytes
(unless (and (integerp key1) (< key1 256)
(integerp key2) (< key2 256))
(error "Key-chord keys must both be bytes (characters with codes < 256)"))
(if (eq key1 key2)
(define-key keymap (vector 'key-chord key1 key2) command)
(define-key keymap (vector 'key-chord key1 key2) command)
(define-key keymap (vector 'key-chord key2 key1) command))))
(define-key keymap (vector 'key-chord key2 key1) command))
;; Update key tracking directly
(if command
(key-chord-register-keys key1 key2)
(key-chord-unregister-keys key1 key2))))
(defun key-chord-lookup-key1 (keymap key)
"Like lookup-key but no third arg and no numeric return value."
"Like `lookup-key' but no third arg and no numeric return value.
KEYMAP is the keymap to look up the KEY in."
(let ((res (lookup-key keymap key)))
(and (not (numberp res))
res)))
@@ -168,48 +281,178 @@ Commands. Please ignore that."
(interactive)
(describe-bindings [key-chord]))
(defun key-chord-reset-all-state ()
"Reset all key-chord state variables."
(setq key-chord-last-unmatched nil)
(setq key-chord-in-typing-flow nil)
(setq key-chord-last-key-time nil)
(setq key-chord-typing-reset-time nil))
(defun key-chord-reset-typing-detection ()
"Reset typing detection state when `key-chord-mode' is toggled."
(key-chord-reset-all-state))
(defun key-chord-reset-typing-mode ()
"Reset the typing detection mode."
(setq key-chord-in-typing-flow nil)
(setq key-chord-last-unmatched nil))
(defun key-chord-pause-typing-flow ()
"Temporarily pause typing flow detection to allow chord detection."
(when key-chord-typing-detection
(setq key-chord-in-typing-flow nil)))
(defun key-chord-valid-chord-char-p (char)
"Return non-nil if CHAR is valid for chord detection.
A valid character is an integer in the range 0-255."
(and (integerp char) (< char 256)))
(defun key-chord-execute-chord (first-char next-char)
"Execute the chord composed of FIRST-CHAR and NEXT-CHAR.
Returns the key-chord event to be processed."
;; Record the chord for macro tracking
(setq key-chord-defining-kbd-macro
(cons first-char key-chord-defining-kbd-macro))
;; Reset state after successful chord execution
(setq key-chord-last-unmatched nil)
;; Return the chord event
(list 'key-chord first-char next-char))
(defun key-chord-no-chord (first-char &optional next-char)
"Handle the case when no chord is matched.
FIRST-CHAR is the first character pressed.
If NEXT-CHAR is provided, it will be added to `unread-command-events`."
(when next-char
(setq unread-command-events (cons next-char unread-command-events)))
(setq key-chord-last-unmatched first-char)
(list first-char))
(defun key-chord-check-typing-flow (current-time)
"Check if user is in typing mode based on timing between keystrokes.
CURRENT-TIME is the time at which the function was called."
(when key-chord-typing-detection
;; Check if we need to reset typing flow based on elapsed time
(when (and key-chord-typing-reset-time
(> (float-time current-time) key-chord-typing-reset-time))
(setq key-chord-in-typing-flow nil)
(setq key-chord-last-unmatched nil)) ;; Reset last-unmatched when exiting typing flow
;; Set new reset time
(setq key-chord-typing-reset-time
(+ (float-time current-time) key-chord-typing-reset-delay))
;; Check if we're in typing flow based on timing
(unless key-chord-in-typing-flow
(when key-chord-last-key-time
(let ((elapsed (float-time (time-subtract current-time key-chord-last-key-time))))
(when (< elapsed key-chord-typing-speed-threshold)
(setq key-chord-in-typing-flow t)))))
;; Update last key time
(setq key-chord-last-key-time current-time)))
(defun key-chord-input-method (first-char)
"Input method controlled by key bindings with the prefix `key-chord'."
(cond
((and (not (eq first-char key-chord-last-unmatched))
(key-chord-lookup-key (vector 'key-chord first-char)))
(let ((delay (if (key-chord-lookup-key
(vector 'key-chord first-char first-char))
key-chord-one-key-delay
key-chord-two-keys-delay)))
(cond ((if executing-kbd-macro
(not (memq first-char key-chord-in-last-kbd-macro))
(when (bound-and-true-p eldoc-mode)
(eldoc-pre-command-refresh-echo-area))
(sit-for delay 'no-redisplay))
(setq key-chord-last-unmatched nil)
(list first-char))
(t ; input-pending-p
(let* ((input-method-function nil)
(next-char (read-event))
(res (vector 'key-chord first-char next-char)))
(cond ((key-chord-lookup-key res)
(setq key-chord-defining-kbd-macro
(cons first-char key-chord-defining-kbd-macro))
(list 'key-chord first-char next-char))
(t ;put back next-char and return first-char
(setq unread-command-events
(cons next-char unread-command-events))
(when (eq first-char next-char)
(setq key-chord-last-unmatched first-char))
(list first-char))))))))
(t ; no key-chord keymap
(setq key-chord-last-unmatched first-char)
(list first-char))))
"Input method controlled by key bindings with the prefix `key-chord'.
FIRST-CHAR is the first character input by the user."
;; Check if we're in a read-char context and bypass key-chord if so
(if (key-chord-in-read-char-context-p)
(progn
(key-chord-reset-all-state)
(list first-char))
;; Not in read-char context, proceed with normal key-chord processing
(progn
;; Check typing mode (but not during macro execution)
(unless executing-kbd-macro
(key-chord-check-typing-flow (current-time)))
(cond
;; For any non-valid chord character, bypass chord detection
((not (key-chord-valid-chord-char-p first-char))
(setq key-chord-last-unmatched nil) ;; Reset for safety
(list first-char))
;; Skip chord detection if in typing mode (but not during macro execution)
((and key-chord-typing-detection
key-chord-in-typing-flow
(not executing-kbd-macro))
;; Don't update key-chord-last-unmatched in typing flow mode
(list first-char))
;; Skip chord detection during macro execution if key-chord-in-macros is nil
;; or if the key is not in a recorded chord
((and executing-kbd-macro
(or (not key-chord-in-macros)
(not (memq first-char key-chord-in-last-kbd-macro))))
(key-chord-no-chord first-char))
;; Optimization: Skip chord detection completely if key tracking is enabled
;; and first-char is not used in any chord
((and key-chord-use-key-tracking
(not (aref key-chord-keys-in-use first-char)))
(key-chord-no-chord first-char))
;; Continue with chord detection for keys that might be part of a chord
((not (eq first-char key-chord-last-unmatched))
(key-chord-pause-typing-flow) ;; Temporarily exit typing flow for chord detection
(let ((res (key-chord-lookup-key (vector 'key-chord first-char))))
(if (not res)
(key-chord-no-chord first-char)
(let ((start-time (current-time))
(delay (if (key-chord-lookup-key
(vector 'key-chord first-char first-char))
key-chord-one-key-delay
key-chord-two-keys-delay)))
;; Read second character
(let ((next-char (read-event nil nil delay)))
(cond
;; No second character received within timeout
((null next-char)
(key-chord-no-chord first-char))
;; Handle invalid next character
((not (key-chord-valid-chord-char-p next-char))
(key-chord-no-chord first-char next-char))
;; Handle double-press of the same key (with timing checks)
((eq first-char next-char)
(let ((elapsed (float-time (time-subtract (current-time) start-time))))
(if (< elapsed key-chord-one-key-min-delay)
;; Too fast (key held down) - not a chord
(key-chord-no-chord first-char next-char)
;; Check if this is a valid same-key chord
(if (key-chord-lookup-key (vector 'key-chord first-char next-char))
(key-chord-execute-chord first-char next-char)
;; Not a valid chord
(key-chord-no-chord first-char next-char)))))
;; Handle two different keys
(t
;; Check if this is a valid two-key chord
(if (key-chord-lookup-key (vector 'key-chord first-char next-char))
(key-chord-execute-chord first-char next-char)
;; Not a valid chord
(key-chord-no-chord first-char next-char)))))))))
;; Key was last unmatched
(t (key-chord-no-chord first-char))))))
(defun key-chord--start-kbd-macro (_append &optional _no-exec)
"Reset key chord tracking when a keyboard macro is started.
_APPEND and _NO-EXEC are ignored arguments from `start-kbd-macro'."
(setq key-chord-defining-kbd-macro nil))
(advice-add 'start-kbd-macro :after #'key-chord--start-kbd-macro)
(defun key-chord--end-kbd-macro (&optional _repeat _loopfunc)
"Save key chord information when a keyboard macro ends.
_REPEAT and _LOOPFUNC are ignored arguments from `end-kbd-macro'."
(setq key-chord-in-last-kbd-macro key-chord-defining-kbd-macro))
(advice-add 'end-kbd-macro :after #'key-chord--end-kbd-macro)
(provide 'key-chord)
;; Local Variables:
;; indent-tabs-mode: nil