#!/bin/zsh -f
[[ -o interactive ]] && {
local -hi ARGC # local is a no-op outside of a function
(ARGC=0) 2>/dev/null || { # so ARGC remains read-only for "source"
print -u2 ${0}: must be run as a function or shell script, not sourced
return 1
}
}
emulate -RL zsh
local zkbd term key seq
zkbd=${ZDOTDIR:-$HOME}/.zkbd
[[ -d $zkbd ]] || mkdir $zkbd || return 1
print 'typeset -g -A key\n' > $zkbd/$TERM.tmp || return 1
trap "unfunction getmbkey getseq; command rm -f $zkbd/$TERM.tmp" 0
trap "return 1" 1 2 15
getmbkey () {
local k='' i
for ((i=10; i>0; --i))
do
read -t -k 1 k && break
sleep 1
done
[[ -n $k ]] || return 1
[[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0
# We might not be done yet, thanks to multibyte characters
local mbk=$k
while read -t -k 1 k
do
mbk=$mbk$k
done
print -Rn $mbk
}
getseq () {
trap "stty ${$(stty -g 2>/dev/null):-echo -raw}" 0 1 2 15
stty raw -echo
local k='' seq='' i
for ((i=10; i>0; --i))
do
read -t -k 1 k && break
sleep 1
done
[[ -n $k ]] || return 1
[[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0
seq=$k
while read -t -k 1 k
do
seq=$seq$k
done
print -Rn ${(V)seq}
}
read term"?Enter current terminal type: [$TERM] "
[[ -n $term ]] && TERM=$term
cat <<\EOF
We will now test some features of your keyboard and terminal.
If you do not press the requested keys within 10 seconds, key reading will
abort. If your keyboard does not have a requested key, press Space to
skip to the next key.
EOF
local ctrl alt meta
print -n "Hold down Ctrl and press X: "
ctrl=$(getmbkey) || return 1
print
if [[ $ctrl != $'\030' ]]
then
print "Your keyboard does not have a working Ctrl key?"
print "Giving up ..."
return 1
else
print
fi
print "Your Meta key may have a Microsoft Windows logo on the cap."
print -n "Hold down Meta and press X: "
meta=$(getmbkey) || return 1
print
if [[ $meta == x ]]
then
print "Your keyboard or terminal does not recognize the Meta key."
unset meta
elif [[ $meta > $'\177' ]]
then
print "Your keyboard uses the Meta key to send high-order characters."
else
unset meta
fi
print
print -n "Hold down Alt and press X: "
alt=$(getmbkey) || return 1
print
if [[ $alt == x ]]
then
print "Your keyboard or terminal does not recognize the Alt key."
unset alt
elif [[ $alt == $meta ]]
then
print "Your keyboard does not distinguish Alt from Meta."
elif [[ $alt > $'\177' ]]
then
print "Your keyboard uses the Alt key to send high-order characters."
else
unset alt
fi
if (( $+alt + $+meta == 0 ))
then
print $'\n---------\n'
if [[ -o multibyte ]]
then cat <<EOF
You are using zsh in MULTIBYTE mode to support modern character sets (for
languages other than English). To use the Meta or Alt keys, you probably
need to revert to single-byte mode with a command such as
unsetopt MULTIBYTE
EOF
else cat <<EOF
Your current terminal and keyboard configuration does not appear to use
high-order characters. You may be able to enable the Meta or Alt keys
with a command such as
stty pass8
EOF
fi
cat <<EOF
If you want to use these extra keys with zsh, try adding the above command
to your ${ZDOTDIR:-$HOME}/.zshrc file.
See also "man stty" or the documentation for your terminal or emulator.
EOF
fi
(( $+alt || $+meta )) && cat <<EOF
---------
You may enable keybindings that use the \
${meta:+Meta}${meta:+${alt:+ and }}${alt:+Alt} key${meta:+${alt:+s}} \
by adding
bindkey -m
to your ${ZDOTDIR:-$HOME}/.zshrc file.
EOF
read -k 1 key"?Press a key to proceed: "
[[ $key != $'\n' ]] && print
cat <<\EOF
---------
You will now be asked to press in turn each of the 12 function keys, then
the Backspace key, the 6 common keypad keys found on typical PC keyboards,
plus the 4 arrow keys, and finally the Menu key (near Ctrl on the right).
If your keyboard does not have the requested key, press Space to skip to
the next key.
Do not type ahead! Wait at least one second after pressing each key for
zsh to read the entire sequence and prompt for the next key. If a key
sequence does not echo within 2 seconds after you press it, that key may
not be sending any sequence at all. In this case zsh is not able to make
use of that key. Press Space to skip to the next key.
EOF
read -k 1 key"?Press a key when ready to begin: "
[[ $key != $'\n' ]] && print
cat <<\EOF
If you do not press a key within 10 seconds, key reading will abort.
If you make a mistake, stop typing and wait, then run this program again.
EOF
# There are 509 combinations of the following three arrays that represent
# possible keystrokes. (Actually, Sun keyboards don't have Meta or Menu,
# though some have R{1..12} keys as well, so really there are either 433
# or 517 combinations; but some X11 apps map Shift-F{1..11} to emulate the
# unmodified Sun keys, so really only the 345 PC combinations are usable.
# Let's not even get into distinguishing Left and Right Shift/Alt/Meta.)
# No one would ever want to type them all into this program (would they?),
# so by default ask for the 23 unmodified PC keys. If you uncomment more,
# you should fix the introductory text above.
local -a pckeys sunkeys modifiers
pckeys=(F{1..12}
Backspace Insert Home PageUp
Delete End PageDown
Up
Left Down Right
Menu
)
sunkeys=(Stop Again
Props Undo
Front Copy
Open Paste
Find Cut
Help
)
modifiers=(Shift- # Control- Alt- Meta-
# Control-Shift- Alt-Shift- Meta-Shift-
# Control-Alt- Control-Meta- Alt-Meta-
# Control-Alt-Shift- Control-Meta-Shift-
# Alt-Meta-Shift- Control-Alt-Meta-Shift-
)
exec 3>/dev/tty
for key in $pckeys # $^modifiers$^pckeys $sunkeys $^modifiers$^sunkeys
do
print -u3 -Rn "Press $key: "
seq="$(getseq)" || return 1
print "key[$key]='${(q)seq}'"
print -u3 -R $seq
done >> $zkbd/$TERM.tmp
source $zkbd/$TERM.tmp || return 1
if [[ "${key[Delete]}" == "${key[Backspace]}" ]]
then
print
print Warning: Backspace and Delete key both send "${(q)key[Delete]}"
else
if [[ "${key[Delete]}" != "^?" ]]
then
print
print Warning: Delete key sends "${(q)key[Delete]}" '(not ^?)'
fi
if [[ "${key[Backspace]}" != "^H" ]]
then
print
print Warning: Backspace sends "${(q)key[Backspace]}"
fi
fi
local termID=${DISPLAY:-$VENDOR-$OSTYPE}
command mv $zkbd/$TERM.tmp $zkbd/$TERM-$termID
cat <<EOF
Parameter assignments for the keys you typed have been written to the file:
$zkbd/$TERM-$termID
You may read this file into ${ZDOTDIR:-$HOME}/.zshrc or another startup
file with the "source" or "." commands, then reference the \$key parameter
in bindkey commands, like this:
source ${zkbd/$HOME/~}/\$TERM-\${DISPLAY:-\$VENDOR-\$OSTYPE}
[[ -n \${key[Left]} ]] && bindkey "\${key[Left]}" backward-char
[[ -n \${key[Right]} ]] && bindkey "\${key[Right]}" forward-char
# etc.
EOF
Copyright 2K16 - 2K18 Indonesian Hacker Rulez