开发者

Display the status of caps lock, num lock and shift keys in Emacs

开发者 https://www.devze.com 2023-03-18 08:29 出处:网络
Is it possible to display whether or not the caps lock and num lock keys are on in Emacs? The reas开发者_开发知识库on why I ask is because I am a one-handed typist and use a FrogPad. The 20 key device

Is it possible to display whether or not the caps lock and num lock keys are on in Emacs? The reas开发者_开发知识库on why I ask is because I am a one-handed typist and use a FrogPad. The 20 key device uses multiple shift key sequences to have the full functionality of a standard qwerty keyboard. I would find it extremely helpful to display the status of the shift, caps lock and numlock keys inside emacs. I have googled this and could only find posts regarding remapping keys. Is this even possible?


The lowest level of keyboard input received by emacs lisp is the keyboard event, which combines a basic code with the on/off settings of the emacs modifiers (meta, control, shift, hyper, super, and alt). Because of this combination, there appears to be no way for lisp code to learn when you, for example, press and hold the shift key. Note also that there is no representation at all of CAPS LOCK or NUM LOCK.

On a side note, emacs does in fact distinguish between newline and C-m, but at a very low level in the lisp code, the former is mapped to the latter. See lisp/term/x-win.el (usually found under /usr/share/emacs/NN.X) if you really want the gory details.

So, from within emacs lisp, I believe it impossible to do what you want.

However, it is possible to embed text from external commands into the emacs mode line, and to have that updated on a regular basis. So, in principle you could find a linux command that returns caps lock, shift, and numlock status, and periodicaly inject that into the command line. This probably doesn't really meet your needs, since it won't update the modeline in real time as you press shift, capslock, and numlock. But if you want to pursue this, check out the implementations of display-time-mode and display-battery-mode.


It's not possible in portable Emacs, but if you're using X11:

(require 'dash)
(require 's)

(defun x-led-mask ()
  "Get the current status of the LED mask from X."
  (with-temp-buffer
    (call-process "xset" nil t nil "q")
    (let ((led-mask-string
           (->> (buffer-string)
                s-lines
                (--first (s-contains? "LED mask" it))
                s-split-words
                -last-item)))
      (string-to-number led-mask-string 16))))

(defun caps-lock-on (led-mask)
  "Return non-nil if caps lock is on."
  (eq (logand led-mask 1) 1))

(define-minor-mode caps-lock-show-mode
  "Display whether caps lock is on."
  :global t
  :lighter (:eval (if (caps-lock-on (x-led-mask)) " CAPS-LOCK" "")))


When run emacs in X Server, you can write a C program, continuous monitor Shift, Caps and Numlock status, when change happen, print it to stdout. In emacs, run this program as external process, process its output using process-filter, and finally display Shift, Caps and Numlock status in mode-line.


A solution that I came up with on macOS inspired by Dale Hagglund's recommendation.

  1. Make a trivial tool to extract caps lock state, see https://apple.stackexchange.com/a/210803/7097.

  2. Integrate it into init.el

;; Making cursor color depend on the caps-lock state

;;; Function that processes caps-lock state
;;; 
;;; The output I had is '0\n' or '1\n'
(defun caps-lock-filter (process output)
  (cond ((string= "1\n" output) (set-cursor-color "#ff3311"))
        ((string= "0\n" output) (set-cursor-color "#11ff87"))
        (t (message "Unexpected output from caps-lock: '%s'" output))))

;;; Hooked function `caps-lock-tick` will be called more often than
;;; it takes for process to spin up, finish and be deleted.
;;; We don't need more than 1 process, so I store it in
;;; `*caps-lock-checking-process*`.
(setq *caps-lock-checking-process* nil)
(defun caps-lock-tick (&rest args)
  (if (not (process-live-p *caps-lock-checking-process*))
      (let* ((process (start-process-shell-command
               "caps-lock-checking"
               nil
               "my/path/to/capslock/checkmodkeys capslock")))
        (setq *caps-lock-checking-process* process)
        (set-process-filter process 'caps-lock-filter)
        (set-process-query-on-exit-flag process nil))))

;;; Adding hooks that trigger update of the cursor color
;;;
;;; That is the minimal set of hooks necessary for a reliable
;;; updates, that I found.
(add-hook 'pre-redisplay-functions #'caps-lock-tick)
(add-function
 :after after-focus-change-function
 (lambda () (unless (frame-focus-state)
          (caps-lock-tick nil))))
0

精彩评论

暂无评论...
验证码 换一张
取 消