forked from ColemakMods/mod-dh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate
executable file
·313 lines (280 loc) · 7.59 KB
/
generate
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#!/usr/bin/env bash
# requires sponge and gawk
# * Option Parsing
print_help() {
echo "
Generates Colemak-DH console and xmodmap keymap files.
usage: generate [options]
options:
-h, --help print this message
-l, --left whether to generate the left keymaps
-o, --out-dir <output directory> specify a directory to output the keymaps to
"
if [[ $1 == illegal_opt ]]; then
exit 1
else
exit 0
fi
}
out_dir=""
left=false
while getopts :o:h opt; do
case $opt in
h) print_help;;
l) left=true;;
o) out_dir=$OPTARG;;
-)
OPTION=${OPTARG%%=*}
if [[ $OPTARG =~ ^(help|left)$ ]] || \
[[ $OPTARG == *=* ]]; then
OPTION=${OPTARG%%=*}
OPTARG=${OPTARG#*=}
else
OPTION=$OPTARG
# shellcheck disable=SC2124
OPTARG=${@:$OPTIND:1}
((OPTIND++))
fi
case $OPTION in
help) print_help;;
left) left=true;;
out-dir) out_dir=$OPTARG;;
*) print_help illegal_opt;;
esac;;
*) print_help illegal_opt;;
esac
done
# * General Helper Functions
align_base() { # base-file xmodmap-base?(optional)
column -t "$1" | sponge "$1"
# add back blank lines (-e flag is for bsd column)
if [[ -z $2 ]]; then
awk '{print}
($2 == 13 || $2 == 43 || $2 == 40 || $2 == 53) {print ""}' "$1" | sponge "$1"
else
awk '{print}
($2 == 21 || $2 == 51 || $2 == 48 || $2 == 61) {print ""}' "$1" | sponge "$1"
fi
}
sort_base() { # base-file
# inefficient but simple
temp=temp-$1
sort -n -k 2 "$1" > "$temp"
# number row
awk '$2 == 41 {print}' "$temp" > "$1"
awk '($2 >= 2 && $2 <= 13) {print}' "$temp" >> "$1"
echo "" >> "$1"
# top row
awk '(($2 >= 16 && $2 <= 27) || ($2 == 43)) {print}' "$temp" >> "$1"
echo "" >> "$1"
# middle row
awk '(($2 >= 30 && $2 <= 40)) {print}' "$temp" >> "$1"
echo "" >> "$1"
# bottom row
awk '$2 == 86 {print}' "$temp" >> "$1"
awk '(($2 == 42) || ($2 >= 44 && $2 <= 53)) {print}' "$temp" >> "$1"
echo "" >> "$1"
awk '($2 == 56 || $2 == 57) {print}' "$temp" >> "$1"
echo "" >> "$1"
rm "$temp"
}
make_wide_base() { # base-file # out-name
cp "$1" "$2"
# shift 6 to - over; move = before
# shift j to ; over; move [ before; # (or \ for ansi) and ' after
# shift m to o over; ] before
# shift k to . over; / before
awk '{
if (($2 >= 7 && $2 <= 12) || ($2 >= 21 && $2 <= 25) ||
($2 >= 35 && $2 <= 39) || ($2 >= 49 && $2 <= 52)) {
$2=$2+1;
} else if ($2 == 13) {
$2=7;
} else if ($2 == 26) {
$2=21;
} else if ($2 == 27) {
$2=35;
} else if ($2 == 43) {
$2=27;
} else if ($2 == 40) {
$2=43;
} else if ($2 == 53) {
$2=49;
}
print;
}' "$2" | sponge "$2"
}
swap_keys() { # file # key1 # key2
awk "
FNR == NR {
if (\$4 == \"$2\") {
line1=\$0;
code1=\$2;
} else if (\$4 == \"$3\") {
line2=\$0;
code2=\$2;
}
next;
}
{
if (\$4 == \"$2\") {
\$0=line2;
n=split(\$0, a, \" \", seps);
a[2]=code1;
} else if (\$4 == \"$3\") {
\$0=line1;
n=split(\$0, a, \" \", seps);
a[2]=code2;
}
if (\$4 == \"$2\" || \$4 == \"$3\") {
# to preserve whitespace
line=\"\";
for (i = 1; i <= n; i++) line=(line a[i] seps[i])
print line;
} else {
print;
}
}" "$1" "$1" | sponge "$1"
}
# * Conversion Functions
to_xmodmap() { # base-file keymap-name
new_base=xmodmap-$1
cp "$1" "$new_base"
# shift keycodes up by 8
awk '/^keycode/ {$2=$2+8; print}' "$new_base" | sponge "$new_base"
# remove 5th mapping
awk '{$8=""; print $0}' "$new_base" | sponge "$new_base"
sed -i -e 's/ one / 1 /; s/ two / 2 /; s/ three / 3 /; s/ four / 4 /' \
-e 's/ five / 5 /; s/ six / 6 /; s/ seven / 7 /; s/ eight / 8 /' \
-e 's/ nine / 9 /; s/ zero / 0 /; s/0x1002039/U2039/; s/0x100203a/U203a/' \
-e 's/euro/EuroSign/' \
"$new_base"
# fix whitespace changes from awk
align_base "$new_base" t
cat xmodmap-header "$new_base" xmodmap-footer > "xmodmap/$2.xmodmap"
rm "$new_base"
}
to_console() { # base-file keymap-name
new_base=console-$1
cp "$1" "$new_base"
# remove invalid entries
sed -r -i -e 's/(leftsinglequotemark|leftdoublequotemark)/asciitilde/g' \
-e 's/(rightsinglequotemark|rightdoublequotemark)/asciitilde/g' \
-e 's/(endash|emdash|dead_ogonek|dstroke|Dstroke)/asciitilde/g' \
-e 's/(lstroke|Lstroke|guillemotleft|guillemotright)/asciitilde/g' \
-e 's/(dead_acute|dead_doubleacute|dead_caron)/asciitilde/g' \
-e 's/(dead_breve|dead_abovering|dead_macron)/asciitilde/g' \
-e 's/dead_abovedot/asciitilde/g' \
-e 's/Shift_L/Shift/g; s/Alt_L/Alt/g; s/Meta_L//g' \
"$new_base"
align_base "$new_base"
cat console-header "$new_base" console-footer > "console/$2.map"
rm "$new_base"
}
# * Generation Functions
# ** Generic
generate_keymap() { # base-file keymap-name description
sort_base "$1"
to_console "$1" "$2"
to_xmodmap "$1" "$2"
sed -i "1 s/$/$3/" console/"$2".map
sed -i "1 s/$/$3/" xmodmap/"$2".xmodmap
}
# ** ISO US
generate_iso_us() {
generate_keymap iso-base iso-us-colemak-dh "(US, ISO keyboard)."
}
generate_wide_iso_us() {
make_wide_base iso-base iso-wide-base
generate_keymap iso-wide-base iso-us-colemak-dh-wide \
"(US, ISO keyboard, Wide layout)."
rm iso-wide-base
}
# ** ANSI US
generate_z_ansi_us() {
generate_keymap ansi-base ansi-us-colemak-dh-z \
"(US, ANSI keyboard, Z angle mod)."
}
generate_shift_z_ansi_us() {
# replace shift with z and lalt with shift
cp ansi-base ansi-shift-z-base
echo "keycode 42 = Shift_L" >> ansi-shift-z-base
echo "keycode 56 = Alt_L Meta_L" >> ansi-shift-z-base
swap_keys ansi-shift-z-base Shift_L z
swap_keys ansi-shift-z-base Shift_L Alt_L
generate_keymap ansi-shift-z-base ansi-us-colemak-dh-shift-z \
"(US, ANSI keyboard, Shift-z angle mod)."
# remove default shift/alt (from console footer)
sed -r -i -e 's/^keycode\s*42.*Shift.*$//; s/^keycode\s*56.*Alt.*$//' \
console/ansi-us-colemak-dh-shift-z.map
}
generate_awing_ansi_us() {
cp ansi-base ansi-awing-base
# shift 1 to 0 over; move - before
# shift q to ; over; move [ before; ' after
# move a to o over; move ] before
# move x to v and k to . over; move z before; move / before
awk '{
if (($2 >= 2 && $2 <= 11) || ($2 >= 16 && $2 <= 25) ||
($2 >= 30 && $2 <= 39) || ($2 >= 44 && $2 <= 47) ||
($2 >= 49 && $2 <= 52)) {
$2=$2+1;
} else if ($2 == 12) {
$2=2;
} else if ($2 == 26) {
$2=16;
} else if ($2 == 27) {
$2=30;
} else if ($2 == 40) {
$2=27;
} else if ($2 == 48) {
$2=44;
} else if ($2 == 53) {
$2=49;
}
print;
}' ansi-awing-base | sponge ansi-awing-base
generate_keymap ansi-awing-base ansi-us-colemak-dh-awing \
"(US, ANSI keyboard, A-Wing angle mod)."
rm ansi-awing-base
}
generate_wide_ansi_us() {
make_wide_base ansi-base ansi-wide-base
swap_keys ansi-wide-base backslash apostrophe
generate_keymap ansi-wide-base ansi-us-colemak-dh-z-wide \
"(US, ANSI keyboard, Z angle mod, Wide layout)."
make_wide_base ansi-shift-z-base ansi-shift-z-wide-base
generate_keymap ansi-shift-z-wide-base ansi-us-colemak-dh-shift-z-wide \
"(US, ANSI keyboard, Shift-z angle mod, Wide layout)."
rm ansi-shift-z-base ansi-wide-base ansi-shift-z-wide-base
}
# * Main
main() {
if ! hash sponge 2> /dev/null; then
echo "This script requires sponge (from moreutils)."
exit 1
fi
mkdir -p xmodmap
mkdir -p console
awk '!/# ansi/ {sub("# iso.*",""); print}' base > iso-base
awk '!/# iso/ {sub("# ansi.*",""); print}' base > ansi-base
generate_iso_us
generate_wide_iso_us
generate_z_ansi_us
generate_shift_z_ansi_us
generate_awing_ansi_us
generate_wide_ansi_us
if $left; then
generate_left console/
generate_left xmodmap/
fi
rm iso-base ansi-base
if [[ -n $out_dir ]]; then
mkdir -p "$out_dir"/console/
mkdir -p "$out_dir"/xmodmap/
cp -r console/* "$out_dir"/console
cp -r xmodmap/* "$out_dir"/xmodmap
rm -r console xmodmap
fi
}
main