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

4

8

Is it possible to display whether or not the caps lock and num lock keys are on in Emacs? The reason 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?

Deceased answered 10/7, 2011 at 2:43 Comment(1)
It's possible in the X11 version of emacs, in the sense that the X server will provide emacs with that information. The terminal code is so far away from the rest of Emacs, though, that this is unlikely to be accessible at the Lisp level. (As an example, Emacs doesn't know the difference between the Return key and Control-m in X, even though the X server gives it this info. They are translated to "Newline" before anything gets a chance to take a look. This is because console-style terminals cannot distinguish between the two cases.)Dorren
F
4

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.

Friar answered 31/8, 2011 at 4:18 Comment(1)
+1 for the battery display tip; it does more than just display battery status, so is probably worth investigating if you are looking for ideas for how to implement this (if it doesn't in fact do it already).Suprarenal
I
4

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" "")))
Iowa answered 8/2, 2016 at 10:40 Comment(0)
J
1

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.

Jobber answered 14/8, 2011 at 2:6 Comment(0)
C
0

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))))
Campstool answered 21/12, 2022 at 23:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.