1#!/bin/zsh -f 2 3[[ -o interactive ]] && { 4 local -hi ARGC # local is a no-op outside of a function 5 (ARGC=0) 2>/dev/null || { # so ARGC remains read-only for "source" 6 print -u2 ${0}: must be run as a function or shell script, not sourced 7 return 1 8 } 9} 10 11emulate -RL zsh 12local zkbd term key seq 13 14zkbd=${ZDOTDIR:-$HOME}/.zkbd 15[[ -d $zkbd ]] || mkdir $zkbd || return 1 16 17trap 'unfunction getmbkey getseq; command rm -f $zkbd/$TERM.tmp' 0 18trap "return 1" 1 2 15 19 20getmbkey () { 21 local k='' i 22 for ((i=10; i>0; --i)) 23 do 24 read -t -k 1 k && break 25 sleep 1 26 done 27 [[ -n $k ]] || return 1 28 [[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0 29 # We might not be done yet, thanks to multibyte characters 30 local mbk=$k 31 while read -t -k 1 k 32 do 33 mbk=$mbk$k 34 done 35 print -Rn $mbk 36} 37 38getseq () { 39 trap "stty ${$(stty -g 2>/dev/null):-echo -raw}" 0 1 2 15 40 stty raw -echo 41 local k='' seq='' i 42 for ((i=10; i>0; --i)) 43 do 44 read -t -k 1 k && break 45 sleep 1 46 done 47 [[ -n $k ]] || return 1 48 [[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0 49 seq=$k 50 while read -t -k 1 k 51 do 52 seq=$seq$k 53 done 54 print -Rn ${(V)seq} 55} 56 57read term"?Enter current terminal type: [$TERM] " 58[[ -n $term ]] && TERM=$term 59print 'typeset -g -A key\n' > $zkbd/$TERM.tmp || return 1 60 61cat <<\EOF 62 63We will now test some features of your keyboard and terminal. 64 65If you do not press the requested keys within 10 seconds, key reading will 66abort. If your keyboard does not have a requested key, press Space to 67skip to the next key. 68 69EOF 70 71local ctrl alt meta 72 73print -n "Hold down Ctrl and press X: " 74ctrl=$(getmbkey) || return 1 75print 76 77if [[ $ctrl != $'\030' ]] 78then 79 print "Your keyboard does not have a working Ctrl key?" 80 print "Giving up ..." 81 return 1 82else 83 print 84fi 85 86print "Your Meta key may have a Microsoft Windows logo on the cap." 87print -n "Hold down Meta and press X: " 88meta=$(getmbkey) || return 1 89print 90 91if [[ $meta == x ]] 92then 93 print "Your keyboard or terminal does not recognize the Meta key." 94 unset meta 95elif [[ $meta > $'\177' ]] 96then 97 print "Your keyboard uses the Meta key to send high-order characters." 98else 99 unset meta 100fi 101print 102 103print -n "Hold down Alt and press X: " 104alt=$(getmbkey) || return 1 105print 106 107if [[ $alt == x ]] 108then 109 print "Your keyboard or terminal does not recognize the Alt key." 110 unset alt 111elif [[ $alt == $meta ]] 112then 113 print "Your keyboard does not distinguish Alt from Meta." 114elif [[ $alt > $'\177' ]] 115then 116 print "Your keyboard uses the Alt key to send high-order characters." 117else 118 unset alt 119fi 120 121if (( $+alt + $+meta == 0 )) 122then 123 print $'\n---------\n' 124 if [[ -o multibyte ]] 125 then cat <<EOF 126You are using zsh in MULTIBYTE mode to support modern character sets (for 127languages other than English). To use the Meta or Alt keys, you probably 128need to revert to single-byte mode with a command such as 129 130 unsetopt MULTIBYTE 131EOF 132 else cat <<EOF 133Your current terminal and keyboard configuration does not appear to use 134high-order characters. You may be able to enable the Meta or Alt keys 135with a command such as 136 137 stty pass8 138EOF 139 fi 140 cat <<EOF 141 142If you want to use these extra keys with zsh, try adding the above command 143to your ${ZDOTDIR:-$HOME}/.zshrc file. 144 145See also "man stty" or the documentation for your terminal or emulator. 146EOF 147fi 148 149(( $+alt || $+meta )) && cat <<EOF 150 151--------- 152 153You may enable keybindings that use the \ 154${meta:+Meta}${meta:+${alt:+ and }}${alt:+Alt} key${meta:+${alt:+s}} \ 155by adding 156 157 bindkey -m 158 159to your ${ZDOTDIR:-$HOME}/.zshrc file. 160 161EOF 162 163read -k 1 key"?Press a key to proceed: " 164[[ $key != $'\n' ]] && print 165 166cat <<\EOF 167 168--------- 169 170You will now be asked to press in turn each of the 12 function keys, then 171the Backspace key, the 6 common keypad keys found on typical PC keyboards, 172plus the 4 arrow keys, and finally the Menu key (near Ctrl on the right). 173If your keyboard does not have the requested key, press Space to skip to 174the next key. 175 176Do not type ahead! Wait at least one second after pressing each key for 177zsh to read the entire sequence and prompt for the next key. If a key 178sequence does not echo within 2 seconds after you press it, that key may 179not be sending any sequence at all. In this case zsh is not able to make 180use of that key. Press Space to skip to the next key. 181 182EOF 183 184read -k 1 key"?Press a key when ready to begin: " 185[[ $key != $'\n' ]] && print 186 187cat <<\EOF 188 189If you do not press a key within 10 seconds, key reading will abort. 190If you make a mistake, stop typing and wait, then run this program again. 191 192EOF 193 194# There are 509 combinations of the following three arrays that represent 195# possible keystrokes. (Actually, Sun keyboards don't have Meta or Menu, 196# though some have R{1..12} keys as well, so really there are either 433 197# or 517 combinations; but some X11 apps map Shift-F{1..11} to emulate the 198# unmodified Sun keys, so really only the 345 PC combinations are usable. 199# Let's not even get into distinguishing Left and Right Shift/Alt/Meta.) 200# No one would ever want to type them all into this program (would they?), 201# so by default ask for the 23 unmodified PC keys. If you uncomment more, 202# you should fix the introductory text above. 203 204local -a pckeys sunkeys modifiers 205pckeys=(F{1..12} 206 Backspace Insert Home PageUp 207 Delete End PageDown 208 Up 209 Left Down Right 210 Menu 211 ) 212sunkeys=(Stop Again 213 Props Undo 214 Front Copy 215 Open Paste 216 Find Cut 217 Help 218 ) 219modifiers=(Shift- # Control- Alt- Meta- 220 # Control-Shift- Alt-Shift- Meta-Shift- 221 # Control-Alt- Control-Meta- Alt-Meta- 222 # Control-Alt-Shift- Control-Meta-Shift- 223 # Alt-Meta-Shift- Control-Alt-Meta-Shift- 224 ) 225 226exec 3>/dev/tty 227 228for key in $pckeys # $^modifiers$^pckeys $sunkeys $^modifiers$^sunkeys 229do 230 print -u3 -Rn "Press $key: " 231 seq="$(getseq)" || return 1 232 print "key[$key]='${(q)seq}'" 233 print -u3 -R $seq 234done >> $zkbd/$TERM.tmp 235 236source $zkbd/$TERM.tmp || return 1 237if [[ "${key[Delete]}" == "${key[Backspace]}" ]] 238then 239 print 240 print Warning: Backspace and Delete key both send "${(q)key[Delete]}" 241else 242 if [[ "${key[Delete]}" != "^?" ]] 243 then 244 print 245 print Warning: Delete key sends "${(q)key[Delete]}" '(not ^?)' 246 fi 247 if [[ "${key[Backspace]}" != "^H" ]] 248 then 249 print 250 print Warning: Backspace sends "${(q)key[Backspace]}" 251 fi 252fi 253 254local termID=${${DISPLAY:t}:-$VENDOR-$OSTYPE} termFile=$zkbd/$TERM.tmp 255command mv $termFile $zkbd/$TERM-$termID && termFile=$zkbd/$TERM-$termID 256 257cat <<EOF 258 259Parameter assignments for the keys you typed have been written to the file: 260$termFile 261 262You may read this file into ${ZDOTDIR:-$HOME}/.zshrc or another startup 263file with the "source" or "." commands, then reference the \$key parameter 264in bindkey commands, for example like this: 265 266 source ${(D)zkbd}/\$TERM-\${\${DISPLAY:t}:-\$VENDOR-\$OSTYPE} 267 [[ -n \${key[Left]} ]] && bindkey "\${key[Left]}" backward-char 268 [[ -n \${key[Right]} ]] && bindkey "\${key[Right]}" forward-char 269 # etc. 270 271Adjust the name of the file being sourced, as necessary. 272EOF 273