1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
#!/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
|