keymap.lisp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. ;;;; keymap.lisp
  2. (in-package #:keymap)
  3. (defvar *global-keymap*)
  4. (defclass keymap ()
  5. ((parents :accessor parents :initarg :parents :initform '())
  6. (keybindings :accessor keybindings :initform (make-hash-table :test 'equalp))))
  7. (defun make-keymap (&rest parents)
  8. (make-instance 'keymap :parents parents))
  9. (defun binding (key &optional (keymap *global-keymap*))
  10. (check-type keymap keymap)
  11. (ensure-normalized-key key)
  12. (multiple-value-bind (binding present?) (gethash key (keybindings keymap))
  13. (if present?
  14. (values binding keymap)
  15. (dolist (parent (parents keymap) (values nil nil))
  16. (multiple-value-bind (binding source) (binding key parent)
  17. (when source
  18. (return (values binding source))))))))
  19. (defun own-keys (&optional keymap *global-keymap*)
  20. (check-type keymap keymap)
  21. (loop for key being the hash-keys in (keybindings keymap)
  22. collect key))
  23. (defun all-keys (&optional (keymap *global-keymap*))
  24. (check-type keymap keymap)
  25. (remove-duplicates (append (own-keys keymap)
  26. (loop for parent in (parents keymap)
  27. append (all-keys parent)))
  28. :test #'key=
  29. :from-end t))
  30. (defun key-source (key &optional (keymap *global-keymap*))
  31. (check-type keymap keymap)
  32. (ensure-normalized-key key)
  33. (nth-value 1 (binding key keymap)))
  34. (defun key-bound-p (key &optional (keymap *global-keymap*))
  35. (check-type keymap keymap)
  36. (ensure-normalized-key key)
  37. (not (null (key-source key keymap))))
  38. (defun ownp (key &optional (keymap *global-keymap*))
  39. (check-type keymap keymap)
  40. (ensure-normalized-key key)
  41. (nth-value 1 (gethash key (keybindings keymap))))
  42. (defun inheritedp (key &optional (keymap *global-keymap*))
  43. (check-type keymap keymap)
  44. (ensure-normalized-key key)
  45. (and (key-bound-p key keymap)
  46. (not (ownp key keymap))))
  47. (defun activep (keymap)
  48. (check-type keymap keymap)
  49. (labels ((check (k)
  50. (or (eql k keymap)
  51. (some #'check (parents k)))))
  52. (check *global-keymap*)))
  53. (defun install-keybinding (key binding)
  54. (if (null binding)
  55. (global-keymap:remove-binding key)
  56. (global-keymap:add-binding key binding)))
  57. (defun install (keymap)
  58. (check-type keymap keymap)
  59. (global-keymap:clear :sync nil)
  60. (loop for key in (all-keys keymap)
  61. for binding = (binding key keymap)
  62. when binding
  63. do (global-keymap:add-binding key binding :sync nil))
  64. (global-keymap:sync)
  65. (setf *global-keymap* keymap))
  66. (defun add-binding (key binding &optional (keymap *global-keymap*))
  67. (check-type binding (or function null))
  68. (check-type keymap keymap)
  69. (ensure-normalized-key key)
  70. (setf (gethash key (keybindings keymap)) binding)
  71. ;; important: after update
  72. ;; if the key is not present in the global keymap, the keymap is necessarily inactive and we do nothing
  73. (when (eql (key-source key *global-keymap*) keymap)
  74. (install-keybinding key binding)))
  75. (defun remove-binding (key &optional (keymap *global-keymap*))
  76. (ensure-normalized-key key)
  77. (check-type keymap keymap)
  78. (let ((old-global-binding (binding key *global-keymap*)))
  79. (remhash key (keybindings keymap))
  80. (let ((new-global-binding (binding key *global-keymap*)))
  81. (unless (eql old-global-binding new-global-binding)
  82. (install-keybinding key new-global-binding)))))