xref: /freebsd/usr.sbin/bsdconfig/share/keymap.subr (revision de7b456e596ff18032d2cbfdf244c66f36770da4)
1if [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1
2#
3# Copyright (c) 2013 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD$
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." keymap.subr
34f_include $BSDCFG_SHARE/struct.subr
35
36############################################################ CONFIGURATION
37
38#
39# Defaults taken from usr.sbin/kbdmap/kbdmap.h
40#
41: ${DEFAULT_LANG:=en}
42: ${DEFAULT_KEYMAP_DIR:=/usr/share/syscons/keymaps}
43
44############################################################ GLOBALS
45
46KEYMAPS=
47
48# A "keymap" from kbdmap's point of view
49f_struct_define KEYMAP \
50	desc \
51	keym \
52	mark
53
54#
55# Default behavior is to call f_keymap_get_all() automatically when loaded.
56#
57: ${KEYMAP_SELF_SCAN_ALL=1}
58
59############################################################ FUNCTIONS
60
61# f_keymap_register $name $desc $keym $mark
62#
63# Register a keymap. A `structure' (see struct.subr) is created with the name
64# keymap_$name (so make sure $name contains only alpha-numeric characters or
65# the underscore, `_'). The remaining arguments after $name correspond to the
66# propertise of the `KEYMAP' structure-type (defined above).
67#
68# If not already registered, the keymap is then appended to the KEYMAPS
69# environment variable, a space-separated list of all registered keymaps.
70#
71f_keymap_register()
72{
73	local name="$1" desc="$2" keym="$3" mark="$4"
74
75	f_struct_new KEYMAP "keymap_$name" || return $FAILURE
76	keymap_$name set desc "$desc"
77	keymap_$name set keym "$keym"
78	keymap_$name set mark "$mark"
79
80	# Scan our global register to see if needs ammending
81	local k found=
82	for k in $KEYMAPS; do
83		[ "$k" = "$name" ] || continue
84		found=1 && break
85	done
86	[ "$found" ] || KEYMAPS="$KEYMAPS $name"
87
88	return $SUCCESS
89}
90
91# f_keymap_checkfile $keymap
92#
93# Check that $keymap is a readable kbdmap(5) file. Returns success if $keymap
94# is a file, is readable, and exists in $DEFAULT_KEYMAP_DIR; otherwise failure.
95# If debugging is enabled, an appropriate debug error message is printed if
96# $keymap is not available.
97#
98f_keymap_checkfile()
99{
100	local keym="$1"
101
102	# Fixup keymap if it doesn't already contain at least one `/'
103	[ "${keym#*/}" = "$keym" ] && keym="$DEFAULT_KEYMAP_DIR/$keym"
104
105	# Short-cuts
106	[ -f "$keym" -a -r "$keym" ] && return $SUCCESS
107	f_debugging || return $FAILURE
108
109	# Print an appropriate debug error message
110	if [ ! -e "$keym" ]; then
111		f_dprintf "%s: No such file or directory" "$keym"
112	elif [ ! -f "$keym" ]; then
113		f_dprintf "%s: Not a file!" "$keym"
114	elif [ ! -r "$keym" ]; then
115		f_dprintf "%s: Permission denied" "$keym"
116	fi
117
118	return $FAILURE
119}
120
121# f_keymap_get_all
122#
123# Get all keymap information for kbdmap(5) entries both in the database and
124# loosely existing in $DEFAULT_KEYMAP_DIR.
125#
126f_keymap_get_all()
127{
128	local fname=f_keymap_get_all
129	local lang="${LC_ALL:-${LC_CTYPE:-${LANG:-$DEFAULT_LANG}}}"
130	[ "$lang" = "C" ] && lang="$DEFAULT_LANG"
131
132	f_dprintf "%s: Looking for keymap files..." $fname
133	f_dialog_info "$msg_looking_for_keymap_files"
134	f_dprintf "DEFAULT_LANG=[%s]" "$DEFAULT_LANG"
135
136	eval "$( awk -F: -v lang="$lang" -v lang_default="$DEFAULT_LANG" '
137		BEGIN {
138			# en_US.ISO8859-1 -> en_..\.ISO8859-1
139			dialect = lang
140			if (length(dialect) >= 6 &&
141			    substr(dialect, 3, 1) == "_")
142				dialect = substr(dialect, 1, 3) ".." \
143				          substr(dialect, 6)
144			printf "f_dprintf \"dialect=[%%s]\" \"%s\";\n", dialect
145
146			# en_US.ISO8859-1 -> en
147			lang_abk = lang
148			if (length(lang_abk) >= 3 &&
149			    substr(lang_abk, 3, 1) == "_")
150				lang_abk = substr(lang_abk, 1, 2)
151			printf "f_dprintf \"lang_abk=[%%s]\" \"%s\";\n",
152			       lang_abk
153		}
154		function find_token(buffer, token)
155		{
156			if (split(buffer, tokens, /,/) == 0) return 0
157			found = 0
158			for (t in tokens)
159				if (token == tokens[t]) { found = 1; break }
160			return found
161		}
162		function add_keymap(desc,mark,keym)
163		{
164			marks[keym] = mark
165			name = keym
166			gsub(/[^[:alnum:]_]/, "_", name)
167			gsub(/'\''/, "'\''\\'\'''\''", desc);
168			printf "f_keymap_checkfile %s && " \
169			       "f_keymap_register %s '\'%s\'' %s %u\n",
170			       keym, name, desc, keym, mark
171		}
172		!/^[[:space:]]*(#|$)/ {
173			sub(/^[[:space:]]*/, "", $0)
174			keym = $1
175			if (keym ~ /^(MENU|FONT)$/) next
176			lg = ($2 == "" ? lang_default : $2)
177
178			# Match the entry and store the type of match we made
179			# as the mark value (so that if we make a better match
180			# later on with a higher mark, it overwrites previous)
181
182			mark = marks[keym];
183			if (find_token(lg, lang))
184				add_keymap($3, 4, keym) # Best match
185			else if (mark <= 3 && find_token(lg, dialect))
186				add_keymap($3, 3, keym)
187			else if (mark <= 2 && find_token(lg, lang_abk))
188				add_keymap($3, 2, keym)
189			else if (mark <= 1 && find_token(lg, lang_default))
190				add_keymap($3, 1, keym)
191			else if (mark <= 0)
192				add_keymap($3, 0, keym)
193		}
194	' "$DEFAULT_KEYMAP_DIR/INDEX.${DEFAULT_KEYMAP_DIR##*/}" )"
195
196
197	#
198	# Look for keymaps not in database
199	#
200	local direntry keym name
201	set +f # glob
202	for direntry in "$DEFAULT_KEYMAP_DIR"/*; do
203		[ "${direntry##*.}" = ".kbd" ] || continue
204		keym="${direntry##*/}"
205		f_str2varname "$keym" name
206		f_struct keymap_$name && continue
207		f_keymap_checkfile "$keym" &&
208			f_keymap_register $name "${keym%.*}" "$keym" 0
209		f_dprintf "%s: not in kbdmap(5) database" "$keym"
210	done
211
212	#
213	# Sort the items by their descriptions
214	#
215	f_dprintf "%s: Sorting keymap entries by description..." $fname
216	KEYMAPS=$(
217		for k in $KEYMAPS; do
218			echo -n "$k "
219			# NOTE: Translate '8x8' to '8x08' before sending to
220			# sort(1) so that things work out as we might expect.
221			debug= keymap_$k get desc | sed -e 's/8x8/8x08/g'
222		done | sort -k2 | awk '{
223			printf "%s%s", (started ? " " : ""), $1; started = 1
224		}'
225	)
226
227	return $SUCCESS
228}
229
230# f_keymap_kbdcontrol $keymap
231#
232# Install keyboard map file from $keymap.
233#
234f_keymap_kbdcontrol()
235{
236	local keymap="$1"
237
238	[ "$keymap" ] || return $SUCCESS
239
240	# Fixup keymap if it doesn't already contain at least one `/'
241	[ "${keymap#*/}" = "$keymap" ] && keymap="$DEFAULT_KEYMAP_DIR/$keymap"
242
243	[ "$USE_XDIALOG" ] || kbdcontrol -l "$keymap"
244}
245
246############################################################ MAIN
247
248#
249# Scan for keymaps unless requeted otherwise
250#
251f_dprintf "%s: KEYMAP_SELF_SCAN_ALL=[%s]" keymap.subr "$KEYMAP_SELF_SCAN_ALL"
252case "$KEYMAP_SELF_SCAN_ALL" in
253""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
254*) f_keymap_get_all
255esac
256
257f_dprintf "%s: Found %u keymap file(s)." keymap.subr \
258          "$( set -- $KEYMAPS; echo $# )"
259
260f_dprintf "%s: Successfully loaded." keymap.subr
261
262fi # ! $_KEYMAP_SUBR
263