1d522f475Smrg#! /usr/bin/perl -w
204b94745Smrg# $XTermId: gen-pc-fkeys.pl,v 1.22 2007/11/30 23:03:55 tom Exp $
320d2c4d2Smrg# -----------------------------------------------------------------------------
420d2c4d2Smrg# this file is part of xterm
520d2c4d2Smrg#
620d2c4d2Smrg# Copyright 2004-2005,2007 by Thomas E. Dickey
720d2c4d2Smrg#
820d2c4d2Smrg#                         All Rights Reserved
920d2c4d2Smrg#
1020d2c4d2Smrg# Permission is hereby granted, free of charge, to any person obtaining a
1120d2c4d2Smrg# copy of this software and associated documentation files (the
1220d2c4d2Smrg# "Software"), to deal in the Software without restriction, including
1320d2c4d2Smrg# without limitation the rights to use, copy, modify, merge, publish,
1420d2c4d2Smrg# distribute, sublicense, and/or sell copies of the Software, and to
1520d2c4d2Smrg# permit persons to whom the Software is furnished to do so, subject to
1620d2c4d2Smrg# the following conditions:
1720d2c4d2Smrg#
1820d2c4d2Smrg# The above copyright notice and this permission notice shall be included
1920d2c4d2Smrg# in all copies or substantial portions of the Software.
2020d2c4d2Smrg#
2120d2c4d2Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2220d2c4d2Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2320d2c4d2Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2420d2c4d2Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
2520d2c4d2Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2620d2c4d2Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2720d2c4d2Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2820d2c4d2Smrg#
2920d2c4d2Smrg# Except as contained in this notice, the name(s) of the above copyright
3020d2c4d2Smrg# holders shall not be used in advertising or otherwise to promote the
3120d2c4d2Smrg# sale, use or other dealings in this Software without prior written
3220d2c4d2Smrg# authorization.
3320d2c4d2Smrg# -----------------------------------------------------------------------------
34d522f475Smrg#
35d522f475Smrg# Construct a list of function-key definitions corresponding to xterm's
36d522f475Smrg# Sun/PC keyboard.  This uses ncurses' infocmp to obtain the strings (including
37d522f475Smrg# extensions) to modify (and verify).
38d522f475Smrguse strict;
39d522f475Smrg
40d522f475Smrgmy($max_modifier, $terminfo);
41d522f475Smrgmy(@old_fkeys, $opt_fkeys, $min_fkeys, $max_fkeys);
42d522f475Smrgmy(%old_ckeys, $opt_ckeys, $min_ckeys, $max_ckeys);
43d522f475Smrgmy(%old_ekeys, $opt_ekeys, $min_ekeys, $max_ekeys);
44d522f475Smrg
45d522f475Smrgmy(@ckey_names);
46d522f475Smrg@ckey_names = (
47d522f475Smrg	'kcud1', 'kcub1', 'kcuf1', 'kcuu1',	# 1 = no modifiers
48d522f475Smrg	'kDN',   'kLFT',  'kRIT',  'kUP',	# 2 = shift
49d522f475Smrg	# make_ckey_names() repeats this row, appending the modifier code
50d522f475Smrg	);
51d522f475Smrgmy %ckey_names;
52d522f475Smrgmy(@ckey_known);
53d522f475Smrg@ckey_known = (
54d522f475Smrg	'kind',  'kLFT',  'kRIT',  'kri',	# 2 = shift (standard)
55d522f475Smrg	);
56d522f475Smrg
57d522f475Smrgmy(@ekey_names);
58d522f475Smrg@ekey_names = (
59d522f475Smrg	'khome', 'kend',  'knp',   'kpp',   'kdch1', 'kich1', # 1 = no modifiers
60d522f475Smrg	'kHOM',  'kEND',  'kNXT',  'kPRV',  'kDC',   'kIC',   # 2 = shift
61d522f475Smrg	# make_ekey_names() repeats this row, appending the modifier code
62d522f475Smrg);
63d522f475Smrgmy %ekey_names;
64d522f475Smrg
65d522f475Smrg$min_fkeys=12;		# the number of "real" function keys on your keyboard
66d522f475Smrg$max_fkeys=64;		# the number of function-keys terminfo can support
67d522f475Smrg$max_modifier=8;	# modifier 1 + (1=shift, 2=alt, 4=control 8=meta)
68d522f475Smrg
69d522f475Smrg$min_ckeys=4;		# the number of "real" cursor keys on your keyboard
70d522f475Smrg$max_ckeys=($min_ckeys * ($max_modifier - 1));
71d522f475Smrg
72d522f475Smrg$min_ekeys=6;		# the number of "real" editing keys on your keyboard
73d522f475Smrg$max_ekeys=($min_ekeys * ($max_modifier - 1));
74d522f475Smrg
75d522f475Smrg$opt_ckeys=2;		# xterm's modifyCursorKeys resource
76d522f475Smrg$opt_ekeys=2;		# xterm's modifyCursorKeys resource
77d522f475Smrg$opt_fkeys=2;		# xterm's modifyFunctionKeys resource
78d522f475Smrg$terminfo="xterm-new";	# the terminfo entry to use
79d522f475Smrg
80d522f475Smrg# apply the given modifier to the terminfo string, return the result
81d522f475Smrgsub modify_fkey($$$) {
82d522f475Smrg	my $code = $_[0];
83d522f475Smrg	my $text = $_[1];
84d522f475Smrg	my $opts = $_[2];
85d522f475Smrg	if (not defined($text)) {
86d522f475Smrg		$text = "";
87d522f475Smrg	} elsif ($code != 1) {
88d522f475Smrg		$text =~ s/\\EO/\\E\[/ if ($opts >= 1);
89d522f475Smrg
90d522f475Smrg		my $piece = substr $text, 0, length ($text) - 1;
91d522f475Smrg		my $final = substr $text, length ($text) - 1;
92d522f475Smrg		my $check = substr $piece, length ($piece) - 1;
93d522f475Smrg		if ($check =~ /[0-9]/) {
94d522f475Smrg			$code = ";" . $code;
95d522f475Smrg		} elsif ( $check =~ /\[/ and $opts >= 2) {
96d522f475Smrg			$code = "1;" . $code;
97d522f475Smrg		}
98d522f475Smrg		if ( $opts >= 3 ) {
99d522f475Smrg			$code = ">" . $code;
100d522f475Smrg		}
101d522f475Smrg		$text = $piece . $code . $final;
102d522f475Smrg		$text =~ s/([\d;]+)>/>$1/;
103d522f475Smrg	}
104d522f475Smrg	return $text;
105d522f475Smrg}
106d522f475Smrg
107d522f475Smrg# compute the next modifier value -
108d522f475Smrg# Cycling through the modifiers is not just like counting.  Users prefer
109d522f475Smrg# pressing one modifier (even if using Emacs).  So first we cycle through
110d522f475Smrg# the individual modifiers, then for completeness two, three, etc.
111d522f475Smrgsub next_modifier {
112d522f475Smrg	my $code = $_[0];
113d522f475Smrg	my $mask = $code - 1;
114d522f475Smrg	if ($mask == 0) {
115d522f475Smrg		$mask = 1;	# shift
116d522f475Smrg	} elsif ($mask == 1) {
117d522f475Smrg		$mask = 4;	# control
118d522f475Smrg	} elsif ($mask == 2) {
119d522f475Smrg		$mask = 3;	# shift+alt
120d522f475Smrg	} elsif ($mask == 4) {
121d522f475Smrg		$mask = 5;	# shift+control
122d522f475Smrg	} elsif ($mask == 5) {
123d522f475Smrg		$mask = 2;	# alt
124d522f475Smrg	}
125d522f475Smrg	# printf ("# next_modifier(%d) = %d\n", $code, $mask + 1);
126d522f475Smrg	return $mask + 1;
127d522f475Smrg}
128d522f475Smrg
129d522f475Smrgsub make_ckey_names() {
130d522f475Smrg	my ($j, $k);
131d522f475Smrg	my $min = $min_ckeys * 2;
132d522f475Smrg	my $max = $max_ckeys - 1;
133d522f475Smrg
134d522f475Smrg	# printf "# make_ckey_names\n";
135d522f475Smrg	for $j ($min..$max) {
136d522f475Smrg		$k = 1 + substr($j / $min_ckeys, 0, 1);
137d522f475Smrg		$ckey_names[$j] = $ckey_names[$min_ckeys + ($j % $min_ckeys)] . $k;
138d522f475Smrg		# printf "# make %d:%s\n", $j, $ckey_names[$j];
139d522f475Smrg	}
140d522f475Smrg	for $j (0..$#ckey_names) {
141d522f475Smrg		# printf "# %d:%s\n", $j, $ckey_names[$j];
142d522f475Smrg		$ckey_names{$ckey_names[$j]} = $j;
143d522f475Smrg	}
144d522f475Smrg}
145d522f475Smrg
146d522f475Smrgsub make_ekey_names() {
147d522f475Smrg	my ($j, $k);
148d522f475Smrg	my $min = $min_ekeys * 2;
149d522f475Smrg	my $max = $max_ekeys - 1;
150d522f475Smrg
151d522f475Smrg	# printf "# make_ekey_names\n";
152d522f475Smrg	for $j ($min..$max) {
153d522f475Smrg		$k = 1 + substr($j / $min_ekeys, 0, 1);
154d522f475Smrg		$ekey_names[$j] = $ekey_names[$min_ekeys + ($j % $min_ekeys)] . $k;
155d522f475Smrg		# printf "# make %d:%s\n", $j, $ekey_names[$j];
156d522f475Smrg	}
157d522f475Smrg	for $j (0..$#ekey_names) {
158d522f475Smrg		# printf "# %d:%s\n", $j, $ekey_names[$j];
159d522f475Smrg		$ekey_names{$ekey_names[$j]} = $j;
160d522f475Smrg	}
161d522f475Smrg}
162d522f475Smrg
163d522f475Smrg# Read the terminfo entry's list of function keys $old_fkeys[].
164d522f475Smrg# We could handle $old_fkeys[0], but choose to start numbering from 1.
165d522f475Smrgsub readterm($) {
166d522f475Smrg	my $term = $_[0];
167d522f475Smrg	my($key, $n, $str);
168d522f475Smrg	my(@list) = `infocmp -x -1 $term`;
169d522f475Smrg
170d522f475Smrg	for $n (0..$#list) {
171d522f475Smrg		chop $list[$n];
172d522f475Smrg		$list[$n] =~ s/^[[:space:]]//;
173d522f475Smrg
174d522f475Smrg		$key = $list[$n];
175d522f475Smrg		$key =~ s/=.*//;
176d522f475Smrg
177d522f475Smrg		$str = $list[$n];
178d522f475Smrg		$str =~ s/^[^=]+=//;
179d522f475Smrg		$str =~ s/,$//;
180d522f475Smrg
181d522f475Smrg		if ( $list[$n] =~ /^kf[[:digit:]]+=/ ) {
182d522f475Smrg			$key =~ s/^kf//;
183d522f475Smrg			# printf "# $n:%s(%d)(%s)\n", $list[$n], $key, $str;
184d522f475Smrg			$old_fkeys[$key] = $str;
185d522f475Smrg		} elsif ( $key =~ /^kc[[:alpha:]]+1/
186d522f475Smrg			or $key =~ /^k(LFT|RIT|UP|DN)\d?/) {
187d522f475Smrg			# printf "# $n:%s(%d)(%s)\n", $list[$n], $key, $str;
188d522f475Smrg			$old_ckeys{$key} = $str;
189d522f475Smrg		} elsif ( defined $ekey_names{$key} ) {
190d522f475Smrg			# printf "# $n:%s(%s)(%s)\n", $list[$n], $key, $str;
191d522f475Smrg			$old_ekeys{$key} = $str;
192d522f475Smrg		}
193d522f475Smrg	}
194d522f475Smrg	# printf ("last index:%d\n", $#old_fkeys);
195d522f475Smrg}
196d522f475Smrg
197d522f475Smrg# read the whole terminfo to ensure we get the non-modified stuff, then read
198d522f475Smrg# the part that contains modifiers.
199d522f475Smrgsub read_part($) {
200d522f475Smrg	my $part = $_[0];
201d522f475Smrg
202d522f475Smrg	%old_ckeys = ();
203d522f475Smrg	@old_fkeys = ();
204d522f475Smrg	readterm($terminfo);
205d522f475Smrg	readterm($part);
206d522f475Smrg}
207d522f475Smrg
208d522f475Smrgsub nameof_ckeys($) {
209d522f475Smrg	my $opts = $_[0];
210d522f475Smrg	my $optname = "xterm+pcc" . ($opts >= 0 ? $opts : "n");
211d522f475Smrg	return $optname;
212d522f475Smrg}
213d522f475Smrg
214d522f475Smrgsub generate_ckeys($) {
215d522f475Smrg	my $opts = $_[0];
216d522f475Smrg	my($modifier, $cur_ckey, $index);
217d522f475Smrg
218d522f475Smrg	printf "%s|fragment with modifyCursorKeys:%s,\n",
219d522f475Smrg		nameof_ckeys($opts), $opts;
220d522f475Smrg
221d522f475Smrg	# show the standard cursor definitions
222d522f475Smrg	$modifier = 1;
223d522f475Smrg	for ($index = 0; $index < $min_ckeys; ++$index) {
224d522f475Smrg		$cur_ckey = $index + ($modifier * $min_ckeys);
225d522f475Smrg		my $name = $ckey_known[$index];
226d522f475Smrg		my $input = $old_ckeys{$ckey_names[$index]};
227d522f475Smrg		my $result = modify_fkey($modifier + 1, $input, $opts);
228d522f475Smrg		printf "\t%s=%s,\n", $name, $result;
229d522f475Smrg		if (defined $old_ckeys{$name}) {
230d522f475Smrg			if ($old_ckeys{$name} ne $result) {
231d522f475Smrg				printf "# found %s=%s\n", $name, $old_ckeys{$name};
232d522f475Smrg			}
233d522f475Smrg		}
234d522f475Smrg	}
235d522f475Smrg
236d522f475Smrg	# show the extended cursor definitions
237d522f475Smrg	for ($index = 0; $index < $min_ckeys; ++$index) {
238d522f475Smrg		for ($modifier = 1; $modifier < $max_modifier; ++$modifier) {
239d522f475Smrg			$cur_ckey = $index + ($modifier * $min_ckeys);
240d522f475Smrg			if (defined $ckey_names[$cur_ckey] and
241d522f475Smrg				$ckey_names[$cur_ckey] ne "kLFT" and
242d522f475Smrg				$ckey_names[$cur_ckey] ne "kRIT" ) {
243d522f475Smrg				my $name = $ckey_names[$cur_ckey];
244d522f475Smrg				my $input = $old_ckeys{$ckey_names[$index]};
245d522f475Smrg				my $result = modify_fkey($modifier + 1, $input, $opts);
246d522f475Smrg				printf "\t%s=%s,\n", $name, $result;
247d522f475Smrg				if (defined $old_ckeys{$name}) {
248d522f475Smrg					if ($old_ckeys{$name} ne $result) {
249d522f475Smrg						printf "# found %s=%s\n", $name, $old_ckeys{$name};
250d522f475Smrg					}
251d522f475Smrg				}
252d522f475Smrg			}
253d522f475Smrg		}
254d522f475Smrg	}
255d522f475Smrg}
256d522f475Smrg
257d522f475Smrgsub nameof_ekeys($) {
258d522f475Smrg	my $opts = $_[0];
259d522f475Smrg	my $optname = "xterm+pce" . ($opts >= 0 ? $opts : "n");
260d522f475Smrg	return $optname;
261d522f475Smrg}
262d522f475Smrg
263d522f475Smrgsub generate_ekeys($) {
264d522f475Smrg	my $opts = $_[0];
265d522f475Smrg	my($modifier, $cur_ekey, $index);
266d522f475Smrg
267d522f475Smrg	printf "%s|fragment with modifyCursorKeys:%s,\n",
268d522f475Smrg		nameof_ekeys($opts), $opts;
269d522f475Smrg
270d522f475Smrg	for ($index = 0; $index < $min_ekeys; ++$index) {
271d522f475Smrg		for ($modifier = 1; $modifier < $max_modifier; ++$modifier) {
272d522f475Smrg			$cur_ekey = $index + ($modifier * $min_ekeys);
273d522f475Smrg			if (defined $ekey_names[$cur_ekey] ) {
274d522f475Smrg				my $name = $ekey_names[$cur_ekey];
275d522f475Smrg				my $input = $old_ekeys{$ekey_names[$index]};
276d522f475Smrg				my $result = modify_fkey($modifier + 1, $input, $opts);
277d522f475Smrg				printf "\t%s=%s,\n", $name, $result;
278d522f475Smrg				if (defined $old_ekeys{$name}) {
279d522f475Smrg					if ($old_ekeys{$name} ne $result) {
280d522f475Smrg						printf "# found %s=%s\n", $name, $old_ekeys{$name};
281d522f475Smrg					}
282d522f475Smrg				}
283d522f475Smrg			}
284d522f475Smrg		}
285d522f475Smrg	}
286d522f475Smrg}
287d522f475Smrg
288d522f475Smrgsub nameof_fkeys($) {
289d522f475Smrg	my $opts = $_[0];
290d522f475Smrg	my $optname = "xterm+pcf" . ($opts >= 0 ? $opts : "n");
291d522f475Smrg	return $optname;
292d522f475Smrg}
293d522f475Smrg
294d522f475Smrgsub generate_fkeys($) {
295d522f475Smrg	my $opts = $_[0];
296d522f475Smrg	my($modifier, $cur_fkey);
297d522f475Smrg
298d522f475Smrg	printf "%s|fragment with modifyFunctionKeys:%s and ctrlFKeys:10,\n",
299d522f475Smrg		nameof_fkeys($opts), $opts;
300d522f475Smrg
301d522f475Smrg	for ($cur_fkey = 1, $modifier = 1; $cur_fkey < $max_fkeys; ++$cur_fkey) {
302d522f475Smrg		my $index = (($cur_fkey - 1) % $min_fkeys);
303d522f475Smrg		if ($index == 0 && $cur_fkey != 1) {
304d522f475Smrg			$modifier = next_modifier($modifier);
305d522f475Smrg		}
306d522f475Smrg		if (defined $old_fkeys[$index + 1]) {
307d522f475Smrg			my $input = $old_fkeys[$index + 1];
308d522f475Smrg			my $result = modify_fkey($modifier, $input, $opts);
309d522f475Smrg			printf "\tkf%d=%s,\n", $cur_fkey, $result;
310d522f475Smrg			if (defined $old_fkeys[$cur_fkey]) {
311d522f475Smrg				if ($old_fkeys[$cur_fkey] ne $result) {
312d522f475Smrg					printf "# found kf%d=%s\n", $cur_fkey, $old_fkeys[$cur_fkey];
313d522f475Smrg				}
314d522f475Smrg			}
315d522f475Smrg		}
316d522f475Smrg	}
317d522f475Smrg}
318d522f475Smrg
319d522f475Smrgsub show_default() {
320d522f475Smrg	readterm($terminfo);
321d522f475Smrg
322d522f475Smrg	printf "xterm+pcfkeys|fragment for PC-style keys,\n";
323d522f475Smrg	printf "\tuse=%s,\n", nameof_ckeys($opt_ckeys);
324d522f475Smrg	printf "\tuse=%s,\n", nameof_ekeys($opt_ekeys);
325d522f475Smrg	printf "\tuse=%s,\n", nameof_fkeys($opt_fkeys);
326d522f475Smrg
327d522f475Smrg	generate_ckeys($opt_ckeys);
328d522f475Smrg	generate_ekeys($opt_ekeys);
329d522f475Smrg	generate_fkeys($opt_fkeys);
330d522f475Smrg}
331d522f475Smrg
332d522f475Smrgsub show_nondefault()
333d522f475Smrg{
334d522f475Smrg	my $opts;
335d522f475Smrg
336d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
337d522f475Smrg		if ($opts != $opt_ckeys) {
338d522f475Smrg			read_part(nameof_ckeys($opts));
339d522f475Smrg			generate_ckeys($opts);
340d522f475Smrg		}
341d522f475Smrg	}
342d522f475Smrg
343d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
344d522f475Smrg		if ($opts != $opt_ekeys) {
345d522f475Smrg			read_part(nameof_ekeys($opts));
346d522f475Smrg			generate_ekeys($opts);
347d522f475Smrg		}
348d522f475Smrg	}
349d522f475Smrg
350d522f475Smrg	for ($opts = 0; $opts <= 3; ++$opts) {
351d522f475Smrg		if ($opts != $opt_fkeys) {
352d522f475Smrg			read_part(nameof_fkeys($opts));
353d522f475Smrg			generate_fkeys($opts);
354d522f475Smrg		}
355d522f475Smrg	}
356d522f475Smrg}
357d522f475Smrg
358d522f475Smrgmake_ckey_names();
359d522f475Smrgmake_ekey_names();
360d522f475Smrg
361d522f475Smrgprintf "# gen-pc-fkeys.pl\n";
362d522f475Smrgprintf "# %s:timode\n", "vile";
363d522f475Smrgshow_default();
364d522f475Smrgshow_nondefault();
365