gen-pc-fkeys.pl revision d522f475
1d522f475Smrg#! /usr/bin/perl -w
2d522f475Smrg# Author: Thomas E. Dickey
3d522f475Smrg# $XTermId: gen-pc-fkeys.pl,v 1.21 2007/11/30 23:03:55 tom Exp $
4d522f475Smrg#
5d522f475Smrg# Construct a list of function-key definitions corresponding to xterm's
6d522f475Smrg# Sun/PC keyboard.  This uses ncurses' infocmp to obtain the strings (including
7d522f475Smrg# extensions) to modify (and verify).
8d522f475Smrguse strict;
9d522f475Smrg
10d522f475Smrgmy($max_modifier, $terminfo);
11d522f475Smrgmy(@old_fkeys, $opt_fkeys, $min_fkeys, $max_fkeys);
12d522f475Smrgmy(%old_ckeys, $opt_ckeys, $min_ckeys, $max_ckeys);
13d522f475Smrgmy(%old_ekeys, $opt_ekeys, $min_ekeys, $max_ekeys);
14d522f475Smrg
15d522f475Smrgmy(@ckey_names);
16d522f475Smrg@ckey_names = (
17d522f475Smrg	'kcud1', 'kcub1', 'kcuf1', 'kcuu1',	# 1 = no modifiers
18d522f475Smrg	'kDN',   'kLFT',  'kRIT',  'kUP',	# 2 = shift
19d522f475Smrg	# make_ckey_names() repeats this row, appending the modifier code
20d522f475Smrg	);
21d522f475Smrgmy %ckey_names;
22d522f475Smrgmy(@ckey_known);
23d522f475Smrg@ckey_known = (
24d522f475Smrg	'kind',  'kLFT',  'kRIT',  'kri',	# 2 = shift (standard)
25d522f475Smrg	);
26d522f475Smrg
27d522f475Smrgmy(@ekey_names);
28d522f475Smrg@ekey_names = (
29d522f475Smrg	'khome', 'kend',  'knp',   'kpp',   'kdch1', 'kich1', # 1 = no modifiers
30d522f475Smrg	'kHOM',  'kEND',  'kNXT',  'kPRV',  'kDC',   'kIC',   # 2 = shift
31d522f475Smrg	# make_ekey_names() repeats this row, appending the modifier code
32d522f475Smrg);
33d522f475Smrgmy %ekey_names;
34d522f475Smrg
35d522f475Smrg$min_fkeys=12;		# the number of "real" function keys on your keyboard
36d522f475Smrg$max_fkeys=64;		# the number of function-keys terminfo can support
37d522f475Smrg$max_modifier=8;	# modifier 1 + (1=shift, 2=alt, 4=control 8=meta)
38d522f475Smrg
39d522f475Smrg$min_ckeys=4;		# the number of "real" cursor keys on your keyboard
40d522f475Smrg$max_ckeys=($min_ckeys * ($max_modifier - 1));
41d522f475Smrg
42d522f475Smrg$min_ekeys=6;		# the number of "real" editing keys on your keyboard
43d522f475Smrg$max_ekeys=($min_ekeys * ($max_modifier - 1));
44d522f475Smrg
45d522f475Smrg$opt_ckeys=2;		# xterm's modifyCursorKeys resource
46d522f475Smrg$opt_ekeys=2;		# xterm's modifyCursorKeys resource
47d522f475Smrg$opt_fkeys=2;		# xterm's modifyFunctionKeys resource
48d522f475Smrg$terminfo="xterm-new";	# the terminfo entry to use
49d522f475Smrg
50d522f475Smrg# apply the given modifier to the terminfo string, return the result
51d522f475Smrgsub modify_fkey($$$) {
52d522f475Smrg	my $code = $_[0];
53d522f475Smrg	my $text = $_[1];
54d522f475Smrg	my $opts = $_[2];
55d522f475Smrg	if (not defined($text)) {
56d522f475Smrg		$text = "";
57d522f475Smrg	} elsif ($code != 1) {
58d522f475Smrg		$text =~ s/\\EO/\\E\[/ if ($opts >= 1);
59d522f475Smrg
60d522f475Smrg		my $piece = substr $text, 0, length ($text) - 1;
61d522f475Smrg		my $final = substr $text, length ($text) - 1;
62d522f475Smrg		my $check = substr $piece, length ($piece) - 1;
63d522f475Smrg		if ($check =~ /[0-9]/) {
64d522f475Smrg			$code = ";" . $code;
65d522f475Smrg		} elsif ( $check =~ /\[/ and $opts >= 2) {
66d522f475Smrg			$code = "1;" . $code;
67d522f475Smrg		}
68d522f475Smrg		if ( $opts >= 3 ) {
69d522f475Smrg			$code = ">" . $code;
70d522f475Smrg		}
71d522f475Smrg		$text = $piece . $code . $final;
72d522f475Smrg		$text =~ s/([\d;]+)>/>$1/;
73d522f475Smrg	}
74d522f475Smrg	return $text;
75d522f475Smrg}
76d522f475Smrg
77d522f475Smrg# compute the next modifier value -
78d522f475Smrg# Cycling through the modifiers is not just like counting.  Users prefer
79d522f475Smrg# pressing one modifier (even if using Emacs).  So first we cycle through
80d522f475Smrg# the individual modifiers, then for completeness two, three, etc.
81d522f475Smrgsub next_modifier {
82d522f475Smrg	my $code = $_[0];
83d522f475Smrg	my $mask = $code - 1;
84d522f475Smrg	if ($mask == 0) {
85d522f475Smrg		$mask = 1;	# shift
86d522f475Smrg	} elsif ($mask == 1) {
87d522f475Smrg		$mask = 4;	# control
88d522f475Smrg	} elsif ($mask == 2) {
89d522f475Smrg		$mask = 3;	# shift+alt
90d522f475Smrg	} elsif ($mask == 4) {
91d522f475Smrg		$mask = 5;	# shift+control
92d522f475Smrg	} elsif ($mask == 5) {
93d522f475Smrg		$mask = 2;	# alt
94d522f475Smrg	}
95d522f475Smrg	# printf ("# next_modifier(%d) = %d\n", $code, $mask + 1);
96d522f475Smrg	return $mask + 1;
97d522f475Smrg}
98d522f475Smrg
99d522f475Smrgsub make_ckey_names() {
100d522f475Smrg	my ($j, $k);
101d522f475Smrg	my $min = $min_ckeys * 2;
102d522f475Smrg	my $max = $max_ckeys - 1;
103d522f475Smrg
104d522f475Smrg	# printf "# make_ckey_names\n";
105d522f475Smrg	for $j ($min..$max) {
106d522f475Smrg		$k = 1 + substr($j / $min_ckeys, 0, 1);
107d522f475Smrg		$ckey_names[$j] = $ckey_names[$min_ckeys + ($j % $min_ckeys)] . $k;
108d522f475Smrg		# printf "# make %d:%s\n", $j, $ckey_names[$j];
109d522f475Smrg	}
110d522f475Smrg	for $j (0..$#ckey_names) {
111d522f475Smrg		# printf "# %d:%s\n", $j, $ckey_names[$j];
112d522f475Smrg		$ckey_names{$ckey_names[$j]} = $j;
113d522f475Smrg	}
114d522f475Smrg}
115d522f475Smrg
116d522f475Smrgsub make_ekey_names() {
117d522f475Smrg	my ($j, $k);
118d522f475Smrg	my $min = $min_ekeys * 2;
119d522f475Smrg	my $max = $max_ekeys - 1;
120d522f475Smrg
121d522f475Smrg	# printf "# make_ekey_names\n";
122d522f475Smrg	for $j ($min..$max) {
123d522f475Smrg		$k = 1 + substr($j / $min_ekeys, 0, 1);
124d522f475Smrg		$ekey_names[$j] = $ekey_names[$min_ekeys + ($j % $min_ekeys)] . $k;
125d522f475Smrg		# printf "# make %d:%s\n", $j, $ekey_names[$j];
126d522f475Smrg	}
127d522f475Smrg	for $j (0..$#ekey_names) {
128d522f475Smrg		# printf "# %d:%s\n", $j, $ekey_names[$j];
129d522f475Smrg		$ekey_names{$ekey_names[$j]} = $j;
130d522f475Smrg	}
131d522f475Smrg}
132d522f475Smrg
133d522f475Smrg# Read the terminfo entry's list of function keys $old_fkeys[].
134d522f475Smrg# We could handle $old_fkeys[0], but choose to start numbering from 1.
135d522f475Smrgsub readterm($) {
136d522f475Smrg	my $term = $_[0];
137d522f475Smrg	my($key, $n, $str);
138d522f475Smrg	my(@list) = `infocmp -x -1 $term`;
139d522f475Smrg
140d522f475Smrg	for $n (0..$#list) {
141d522f475Smrg		chop $list[$n];
142d522f475Smrg		$list[$n] =~ s/^[[:space:]]//;
143d522f475Smrg
144d522f475Smrg		$key = $list[$n];
145d522f475Smrg		$key =~ s/=.*//;
146d522f475Smrg
147d522f475Smrg		$str = $list[$n];
148d522f475Smrg		$str =~ s/^[^=]+=//;
149d522f475Smrg		$str =~ s/,$//;
150d522f475Smrg
151d522f475Smrg		if ( $list[$n] =~ /^kf[[:digit:]]+=/ ) {
152d522f475Smrg			$key =~ s/^kf//;
153d522f475Smrg			# printf "# $n:%s(%d)(%s)\n", $list[$n], $key, $str;
154d522f475Smrg			$old_fkeys[$key] = $str;
155d522f475Smrg		} elsif ( $key =~ /^kc[[:alpha:]]+1/
156d522f475Smrg			or $key =~ /^k(LFT|RIT|UP|DN)\d?/) {
157d522f475Smrg			# printf "# $n:%s(%d)(%s)\n", $list[$n], $key, $str;
158d522f475Smrg			$old_ckeys{$key} = $str;
159d522f475Smrg		} elsif ( defined $ekey_names{$key} ) {
160d522f475Smrg			# printf "# $n:%s(%s)(%s)\n", $list[$n], $key, $str;
161d522f475Smrg			$old_ekeys{$key} = $str;
162d522f475Smrg		}
163d522f475Smrg	}
164d522f475Smrg	# printf ("last index:%d\n", $#old_fkeys);
165d522f475Smrg}
166d522f475Smrg
167d522f475Smrg# read the whole terminfo to ensure we get the non-modified stuff, then read
168d522f475Smrg# the part that contains modifiers.
169d522f475Smrgsub read_part($) {
170d522f475Smrg	my $part = $_[0];
171d522f475Smrg
172d522f475Smrg	%old_ckeys = ();
173d522f475Smrg	@old_fkeys = ();
174d522f475Smrg	readterm($terminfo);
175d522f475Smrg	readterm($part);
176d522f475Smrg}
177d522f475Smrg
178d522f475Smrgsub nameof_ckeys($) {
179d522f475Smrg	my $opts = $_[0];
180d522f475Smrg	my $optname = "xterm+pcc" . ($opts >= 0 ? $opts : "n");
181d522f475Smrg	return $optname;
182d522f475Smrg}
183d522f475Smrg
184d522f475Smrgsub generate_ckeys($) {
185d522f475Smrg	my $opts = $_[0];
186d522f475Smrg	my($modifier, $cur_ckey, $index);
187d522f475Smrg
188d522f475Smrg	printf "%s|fragment with modifyCursorKeys:%s,\n",
189d522f475Smrg		nameof_ckeys($opts), $opts;
190d522f475Smrg
191d522f475Smrg	# show the standard cursor definitions
192d522f475Smrg	$modifier = 1;
193d522f475Smrg	for ($index = 0; $index < $min_ckeys; ++$index) {
194d522f475Smrg		$cur_ckey = $index + ($modifier * $min_ckeys);
195d522f475Smrg		my $name = $ckey_known[$index];
196d522f475Smrg		my $input = $old_ckeys{$ckey_names[$index]};
197d522f475Smrg		my $result = modify_fkey($modifier + 1, $input, $opts);
198d522f475Smrg		printf "\t%s=%s,\n", $name, $result;
199d522f475Smrg		if (defined $old_ckeys{$name}) {
200d522f475Smrg			if ($old_ckeys{$name} ne $result) {
201d522f475Smrg				printf "# found %s=%s\n", $name, $old_ckeys{$name};
202d522f475Smrg			}
203d522f475Smrg		}
204d522f475Smrg	}
205d522f475Smrg
206d522f475Smrg	# show the extended cursor definitions
207d522f475Smrg	for ($index = 0; $index < $min_ckeys; ++$index) {
208d522f475Smrg		for ($modifier = 1; $modifier < $max_modifier; ++$modifier) {
209d522f475Smrg			$cur_ckey = $index + ($modifier * $min_ckeys);
210d522f475Smrg			if (defined $ckey_names[$cur_ckey] and
211d522f475Smrg				$ckey_names[$cur_ckey] ne "kLFT" and
212d522f475Smrg				$ckey_names[$cur_ckey] ne "kRIT" ) {
213d522f475Smrg				my $name = $ckey_names[$cur_ckey];
214d522f475Smrg				my $input = $old_ckeys{$ckey_names[$index]};
215d522f475Smrg				my $result = modify_fkey($modifier + 1, $input, $opts);
216d522f475Smrg				printf "\t%s=%s,\n", $name, $result;
217d522f475Smrg				if (defined $old_ckeys{$name}) {
218d522f475Smrg					if ($old_ckeys{$name} ne $result) {
219d522f475Smrg						printf "# found %s=%s\n", $name, $old_ckeys{$name};
220d522f475Smrg					}
221d522f475Smrg				}
222d522f475Smrg			}
223d522f475Smrg		}
224d522f475Smrg	}
225d522f475Smrg}
226d522f475Smrg
227d522f475Smrgsub nameof_ekeys($) {
228d522f475Smrg	my $opts = $_[0];
229d522f475Smrg	my $optname = "xterm+pce" . ($opts >= 0 ? $opts : "n");
230d522f475Smrg	return $optname;
231d522f475Smrg}
232d522f475Smrg
233d522f475Smrgsub generate_ekeys($) {
234d522f475Smrg	my $opts = $_[0];
235d522f475Smrg	my($modifier, $cur_ekey, $index);
236d522f475Smrg
237d522f475Smrg	printf "%s|fragment with modifyCursorKeys:%s,\n",
238d522f475Smrg		nameof_ekeys($opts), $opts;
239d522f475Smrg
240d522f475Smrg	for ($index = 0; $index < $min_ekeys; ++$index) {
241d522f475Smrg		for ($modifier = 1; $modifier < $max_modifier; ++$modifier) {
242d522f475Smrg			$cur_ekey = $index + ($modifier * $min_ekeys);
243d522f475Smrg			if (defined $ekey_names[$cur_ekey] ) {
244d522f475Smrg				my $name = $ekey_names[$cur_ekey];
245d522f475Smrg				my $input = $old_ekeys{$ekey_names[$index]};
246d522f475Smrg				my $result = modify_fkey($modifier + 1, $input, $opts);
247d522f475Smrg				printf "\t%s=%s,\n", $name, $result;
248d522f475Smrg				if (defined $old_ekeys{$name}) {
249d522f475Smrg					if ($old_ekeys{$name} ne $result) {
250d522f475Smrg						printf "# found %s=%s\n", $name, $old_ekeys{$name};
251d522f475Smrg					}
252d522f475Smrg				}
253d522f475Smrg			}
254d522f475Smrg		}
255d522f475Smrg	}
256d522f475Smrg}
257d522f475Smrg
258d522f475Smrgsub nameof_fkeys($) {
259d522f475Smrg	my $opts = $_[0];
260d522f475Smrg	my $optname = "xterm+pcf" . ($opts >= 0 ? $opts : "n");
261d522f475Smrg	return $optname;
262d522f475Smrg}
263d522f475Smrg
264d522f475Smrgsub generate_fkeys($) {
265d522f475Smrg	my $opts = $_[0];
266d522f475Smrg	my($modifier, $cur_fkey);
267d522f475Smrg
268d522f475Smrg	printf "%s|fragment with modifyFunctionKeys:%s and ctrlFKeys:10,\n",
269d522f475Smrg		nameof_fkeys($opts), $opts;
270d522f475Smrg
271d522f475Smrg	for ($cur_fkey = 1, $modifier = 1; $cur_fkey < $max_fkeys; ++$cur_fkey) {
272d522f475Smrg		my $index = (($cur_fkey - 1) % $min_fkeys);
273d522f475Smrg		if ($index == 0 && $cur_fkey != 1) {
274d522f475Smrg			$modifier = next_modifier($modifier);
275d522f475Smrg		}
276d522f475Smrg		if (defined $old_fkeys[$index + 1]) {
277d522f475Smrg			my $input = $old_fkeys[$index + 1];
278d522f475Smrg			my $result = modify_fkey($modifier, $input, $opts);
279d522f475Smrg			printf "\tkf%d=%s,\n", $cur_fkey, $result;
280d522f475Smrg			if (defined $old_fkeys[$cur_fkey]) {
281d522f475Smrg				if ($old_fkeys[$cur_fkey] ne $result) {
282d522f475Smrg					printf "# found kf%d=%s\n", $cur_fkey, $old_fkeys[$cur_fkey];
283d522f475Smrg				}
284d522f475Smrg			}
285d522f475Smrg		}
286d522f475Smrg	}
287d522f475Smrg}
288d522f475Smrg
289d522f475Smrgsub show_default() {
290d522f475Smrg	readterm($terminfo);
291d522f475Smrg
292d522f475Smrg	printf "xterm+pcfkeys|fragment for PC-style keys,\n";
293d522f475Smrg	printf "\tuse=%s,\n", nameof_ckeys($opt_ckeys);
294d522f475Smrg	printf "\tuse=%s,\n", nameof_ekeys($opt_ekeys);
295d522f475Smrg	printf "\tuse=%s,\n", nameof_fkeys($opt_fkeys);
296d522f475Smrg
297d522f475Smrg	generate_ckeys($opt_ckeys);
298d522f475Smrg	generate_ekeys($opt_ekeys);
299d522f475Smrg	generate_fkeys($opt_fkeys);
300d522f475Smrg}
301d522f475Smrg
302d522f475Smrgsub show_nondefault()
303d522f475Smrg{
304d522f475Smrg	my $opts;
305d522f475Smrg
306d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
307d522f475Smrg		if ($opts != $opt_ckeys) {
308d522f475Smrg			read_part(nameof_ckeys($opts));
309d522f475Smrg			generate_ckeys($opts);
310d522f475Smrg		}
311d522f475Smrg	}
312d522f475Smrg
313d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
314d522f475Smrg		if ($opts != $opt_ekeys) {
315d522f475Smrg			read_part(nameof_ekeys($opts));
316d522f475Smrg			generate_ekeys($opts);
317d522f475Smrg		}
318d522f475Smrg	}
319d522f475Smrg
320d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
321d522f475Smrg		if ($opts != $opt_fkeys) {
322d522f475Smrg			read_part(nameof_fkeys($opts));
323d522f475Smrg			generate_fkeys($opts);
324d522f475Smrg		}
325d522f475Smrg	}
326d522f475Smrg}
327d522f475Smrg
328d522f475Smrgmake_ckey_names();
329d522f475Smrgmake_ekey_names();
330d522f475Smrg
331d522f475Smrgprintf "# gen-pc-fkeys.pl\n";
332d522f475Smrgprintf "# %s:timode\n", "vile";
333d522f475Smrgshow_default();
334d522f475Smrgshow_nondefault();
335