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