2

Part of my ZSH prompt is a caps lock indicator.

function Capslock(){
    x=$(xset -q | grep Caps) 2> /dev/null || exit 0
    x=${x:22:1}
    if [[ $x == "n" ]]; then

        echo ""
    fi
}
POWERLEVEL9K_CUSTOM_CAPS="Capslock"
POWERLEVEL9K_CUSTOM_CAPS_BACKGROUND="red"
POWERLEVEL9K_CUSTOM_CAPS_FOREGROUND="white"

You will see I am using oh-my-zsh and the POWERLEVEL9k theme although I don't know if this is necessary for the question.

I would like to trigger the re-drawing of the prompt when the capslock button is pushed. Is this possible?

EDIT:

Thanks both of you for your answers, they both work. I am just looking into the correct way to accept two answers.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
Jonathan Hodgson
  • 342
  • 1
  • 3
  • 16

2 Answers2

2

If on GNU/Linux, you could install xbindkeys and run it in your X session with in your ~/.xbindkeysrc file:

"echo . > ~/.caps"
  Caps_Lock

Then, in your ~/.zshrc:

exec {CAPS_MONITOR}< <(tail -f ~/.caps 2> /dev/null)
caps-monitor() {
  if
    read <&$CAPS_MONITOR # consume the input
  then
    zle -R # redraw the prompt
    #zle -M "CapsLock pressed [$((++n))]" # uncomment to verify it works
  else
    zle -M "CapsLock handler dysfunctional, stopping the monitoring"
    zle -F $CAPS_MONITOR
  fi
}
zle -N caps-monitor
zle -wF $CAPS_MONITOR caps-monitor
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
2

The difficulty is that pressing CapsLock doesn't send anything to terminal applications, so zsh doesn't know about it.

As suggested by Stéphane Chazelas, you could use XBindKeys to execute a shell command when CapsLock is pressed. One useful command is to arrange to send the SIGWINCH signal to zsh. This signal is sent by the kernel when the tty size settings are modified (typically by terminal emulators when their window size changes). A few spurious window size changes indications won't hurt. This will even work in a remote shell over SSH if you have X11 forwarding in the SSH session and you send the signal to the SSH client.

Zsh doesn't automatically recalculate the prompt string, so tell it to do so by setting a trap on SIGWINCH.

In ~/.xbindkeysrc:

"pkill -u $USER -SIGWINCH -x 'ssh|zsh'"
    Caps_Lock

In ~/.zshrc:

# + your CapsLock function
trap 'zle reset-prompt 2> /dev/null' SIGWINCH

(Or you can do what I do, which is to not have a CapsLock key. In zsh, you can use ESC u (up-case-word) to make the word after the cursor uppercase, and you can create more widgets to help with that if you want.)

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175