about summary refs log tree commit diff
path: root/Functions/Misc/zkbd
blob: 1065a84f194d5764e4d9143990b01a955ae266c6 (plain) (blame)
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
272
#!/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

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
print 'typeset -g -A key\n' > $zkbd/$TERM.tmp || return 1

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:t}:-$VENDOR-$OSTYPE} termFile=$zkbd/$TERM.tmp
command mv $termFile $zkbd/$TERM-$termID && termFile=$zkbd/$TERM-$termID

cat <<EOF

Parameter assignments for the keys you typed have been written to the file:
$termFile

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, for example like this:

    source ${(D)zkbd}/\$TERM-\${\${DISPLAY:t}:-\$VENDOR-\$OSTYPE}
    [[ -n \${key[Left]} ]] && bindkey "\${key[Left]}" backward-char
    [[ -n \${key[Right]} ]] && bindkey "\${key[Right]}" forward-char
    # etc.

Adjust the name of the file being sourced, as necessary.
EOF