1256325Sdteskeif [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1
2256325Sdteske#
3256325Sdteske# Copyright (c) 2013 Devin Teske
4256325Sdteske# All rights reserved.
5256325Sdteske#
6256325Sdteske# Redistribution and use in source and binary forms, with or without
7256325Sdteske# modification, are permitted provided that the following conditions
8256325Sdteske# are met:
9256325Sdteske# 1. Redistributions of source code must retain the above copyright
10256325Sdteske#    notice, this list of conditions and the following disclaimer.
11256325Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12256325Sdteske#    notice, this list of conditions and the following disclaimer in the
13256325Sdteske#    documentation and/or other materials provided with the distribution.
14256325Sdteske#
15256325Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16256325Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17256325Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18256325Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19256325Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20256325Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21256325Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22256325Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23256325Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24256325Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25256325Sdteske# SUCH DAMAGE.
26256325Sdteske#
27256325Sdteske# $FreeBSD$
28256325Sdteske#
29256325Sdteske############################################################ INCLUDES
30256325Sdteske
31256325SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32256325Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33256325Sdteskef_dprintf "%s: loading includes..." keymap.subr
34256325Sdteskef_include $BSDCFG_SHARE/struct.subr
35256325Sdteske
36256325Sdteske############################################################ CONFIGURATION
37256325Sdteske
38256325Sdteske#
39256325Sdteske# Defaults taken from usr.sbin/kbdmap/kbdmap.h
40256325Sdteske#
41256325Sdteske: ${DEFAULT_LANG:=en}
42256325Sdteske: ${DEFAULT_KEYMAP_DIR:=/usr/share/syscons/keymaps}
43256325Sdteske
44256325Sdteske############################################################ GLOBALS
45256325Sdteske
46256325SdteskeKEYMAPS=
47260678SdteskeNKEYMAPS=0
48256325Sdteske
49256325Sdteske# A "keymap" from kbdmap's point of view
50256325Sdteskef_struct_define KEYMAP \
51256325Sdteske	desc \
52256325Sdteske	keym \
53256325Sdteske	mark
54256325Sdteske
55256325Sdteske#
56256325Sdteske# Default behavior is to call f_keymap_get_all() automatically when loaded.
57256325Sdteske#
58256325Sdteske: ${KEYMAP_SELF_SCAN_ALL=1}
59256325Sdteske
60256325Sdteske############################################################ FUNCTIONS
61256325Sdteske
62256325Sdteske# f_keymap_register $name $desc $keym $mark
63256325Sdteske#
64256325Sdteske# Register a keymap. A `structure' (see struct.subr) is created with the name
65256325Sdteske# keymap_$name (so make sure $name contains only alpha-numeric characters or
66256325Sdteske# the underscore, `_'). The remaining arguments after $name correspond to the
67256325Sdteske# propertise of the `KEYMAP' structure-type (defined above).
68256325Sdteske#
69256325Sdteske# If not already registered, the keymap is then appended to the KEYMAPS
70256325Sdteske# environment variable, a space-separated list of all registered keymaps.
71256325Sdteske#
72256325Sdteskef_keymap_register()
73256325Sdteske{
74256325Sdteske	local name="$1" desc="$2" keym="$3" mark="$4"
75256325Sdteske
76256325Sdteske	f_struct_new KEYMAP "keymap_$name" || return $FAILURE
77256325Sdteske	keymap_$name set desc "$desc"
78256325Sdteske	keymap_$name set keym "$keym"
79256325Sdteske	keymap_$name set mark "$mark"
80256325Sdteske
81256325Sdteske	# Scan our global register to see if needs ammending
82256325Sdteske	local k found=
83256325Sdteske	for k in $KEYMAPS; do
84256325Sdteske		[ "$k" = "$name" ] || continue
85256325Sdteske		found=1 && break
86256325Sdteske	done
87256325Sdteske	[ "$found" ] || KEYMAPS="$KEYMAPS $name"
88256325Sdteske
89256325Sdteske	return $SUCCESS
90256325Sdteske}
91256325Sdteske
92256325Sdteske# f_keymap_checkfile $keymap
93256325Sdteske#
94256325Sdteske# Check that $keymap is a readable kbdmap(5) file. Returns success if $keymap
95256325Sdteske# is a file, is readable, and exists in $DEFAULT_KEYMAP_DIR; otherwise failure.
96256325Sdteske# If debugging is enabled, an appropriate debug error message is printed if
97256325Sdteske# $keymap is not available.
98256325Sdteske#
99256325Sdteskef_keymap_checkfile()
100256325Sdteske{
101256325Sdteske	local keym="$1"
102256325Sdteske	
103256325Sdteske	# Fixup keymap if it doesn't already contain at least one `/'
104256325Sdteske	[ "${keym#*/}" = "$keym" ] && keym="$DEFAULT_KEYMAP_DIR/$keym"
105256325Sdteske
106256325Sdteske	# Short-cuts
107256325Sdteske	[ -f "$keym" -a -r "$keym" ] && return $SUCCESS
108256325Sdteske	f_debugging || return $FAILURE
109256325Sdteske
110256325Sdteske	# Print an appropriate debug error message
111256325Sdteske	if [ ! -e "$keym" ]; then
112256325Sdteske		f_dprintf "%s: No such file or directory" "$keym"
113256325Sdteske	elif [ ! -f "$keym" ]; then
114256325Sdteske		f_dprintf "%s: Not a file!" "$keym"
115256325Sdteske	elif [ ! -r "$keym" ]; then
116256325Sdteske		f_dprintf "%s: Permission denied" "$keym"
117256325Sdteske	fi
118256325Sdteske
119256325Sdteske	return $FAILURE
120256325Sdteske}
121256325Sdteske
122256325Sdteske# f_keymap_get_all
123256325Sdteske#
124256325Sdteske# Get all keymap information for kbdmap(5) entries both in the database and
125256325Sdteske# loosely existing in $DEFAULT_KEYMAP_DIR.
126256325Sdteske#
127256325Sdteskef_keymap_get_all()
128256325Sdteske{
129256325Sdteske	local fname=f_keymap_get_all
130256325Sdteske	local lang="${LC_ALL:-${LC_CTYPE:-${LANG:-$DEFAULT_LANG}}}"
131256325Sdteske	[ "$lang" = "C" ] && lang="$DEFAULT_LANG"
132256325Sdteske
133256325Sdteske	f_dprintf "%s: Looking for keymap files..." $fname
134256325Sdteske	f_dialog_info "$msg_looking_for_keymap_files"
135256325Sdteske	f_dprintf "DEFAULT_LANG=[%s]" "$DEFAULT_LANG"
136256325Sdteske
137256325Sdteske	eval "$( awk -F: -v lang="$lang" -v lang_default="$DEFAULT_LANG" '
138256325Sdteske		BEGIN {
139256325Sdteske			# en_US.ISO8859-1 -> en_..\.ISO8859-1
140256325Sdteske			dialect = lang
141256325Sdteske			if (length(dialect) >= 6 &&
142256325Sdteske			    substr(dialect, 3, 1) == "_")
143256325Sdteske				dialect = substr(dialect, 1, 3) ".." \
144256325Sdteske				          substr(dialect, 6)
145256325Sdteske			printf "f_dprintf \"dialect=[%%s]\" \"%s\";\n", dialect
146256325Sdteske
147256325Sdteske			# en_US.ISO8859-1 -> en
148256325Sdteske			lang_abk = lang
149256325Sdteske			if (length(lang_abk) >= 3 &&
150256325Sdteske			    substr(lang_abk, 3, 1) == "_")
151256325Sdteske				lang_abk = substr(lang_abk, 1, 2)
152256325Sdteske			printf "f_dprintf \"lang_abk=[%%s]\" \"%s\";\n",
153256325Sdteske			       lang_abk
154256325Sdteske		}
155256325Sdteske		function find_token(buffer, token)
156256325Sdteske		{
157256325Sdteske			if (split(buffer, tokens, /,/) == 0) return 0
158256325Sdteske			found = 0
159256325Sdteske			for (t in tokens)
160256325Sdteske				if (token == tokens[t]) { found = 1; break }
161256325Sdteske			return found
162256325Sdteske		}
163256325Sdteske		function add_keymap(desc,mark,keym)
164256325Sdteske		{
165256325Sdteske			marks[keym] = mark
166256325Sdteske			name = keym
167256325Sdteske			gsub(/[^[:alnum:]_]/, "_", name)
168263980Sdteske			gsub(/'\''/, "'\''\\'\'\''", desc);
169256325Sdteske			printf "f_keymap_checkfile %s && " \
170256325Sdteske			       "f_keymap_register %s '\'%s\'' %s %u\n",
171256325Sdteske			       keym, name, desc, keym, mark
172256325Sdteske		}
173256325Sdteske		!/^[[:space:]]*(#|$)/ {
174256325Sdteske			sub(/^[[:space:]]*/, "", $0)
175256325Sdteske			keym = $1
176256325Sdteske			if (keym ~ /^(MENU|FONT)$/) next
177256325Sdteske			lg = ($2 == "" ? lang_default : $2)
178256325Sdteske
179256325Sdteske			# Match the entry and store the type of match we made
180256325Sdteske			# as the mark value (so that if we make a better match
181256325Sdteske			# later on with a higher mark, it overwrites previous)
182256325Sdteske
183256325Sdteske			mark = marks[keym];
184256325Sdteske			if (find_token(lg, lang))
185256325Sdteske				add_keymap($3, 4, keym) # Best match
186256325Sdteske			else if (mark <= 3 && find_token(lg, dialect))
187256325Sdteske				add_keymap($3, 3, keym)
188256325Sdteske			else if (mark <= 2 && find_token(lg, lang_abk))
189256325Sdteske				add_keymap($3, 2, keym)
190256325Sdteske			else if (mark <= 1 && find_token(lg, lang_default))
191256325Sdteske				add_keymap($3, 1, keym)
192256325Sdteske			else if (mark <= 0)
193256325Sdteske				add_keymap($3, 0, keym)
194256325Sdteske		}
195256325Sdteske	' "$DEFAULT_KEYMAP_DIR/INDEX.${DEFAULT_KEYMAP_DIR##*/}" )"
196256325Sdteske
197256325Sdteske
198256325Sdteske	#
199256325Sdteske	# Look for keymaps not in database
200256325Sdteske	#
201256325Sdteske	local direntry keym name
202256325Sdteske	set +f # glob
203256325Sdteske	for direntry in "$DEFAULT_KEYMAP_DIR"/*; do
204256325Sdteske		[ "${direntry##*.}" = ".kbd" ] || continue
205256325Sdteske		keym="${direntry##*/}"
206256325Sdteske		f_str2varname "$keym" name
207256325Sdteske		f_struct keymap_$name && continue
208256325Sdteske		f_keymap_checkfile "$keym" &&
209256325Sdteske			f_keymap_register $name "${keym%.*}" "$keym" 0
210256325Sdteske		f_dprintf "%s: not in kbdmap(5) database" "$keym"
211256325Sdteske	done
212256325Sdteske
213256325Sdteske	#
214256325Sdteske	# Sort the items by their descriptions
215256325Sdteske	#
216256325Sdteske	f_dprintf "%s: Sorting keymap entries by description..." $fname
217256325Sdteske	KEYMAPS=$(
218256325Sdteske		for k in $KEYMAPS; do
219256325Sdteske			echo -n "$k "
220256325Sdteske			# NOTE: Translate '8x8' to '8x08' before sending to
221256325Sdteske			# sort(1) so that things work out as we might expect.
222256325Sdteske			debug= keymap_$k get desc | sed -e 's/8x8/8x08/g'
223256325Sdteske		done | sort -k2 | awk '{
224256325Sdteske			printf "%s%s", (started ? " " : ""), $1; started = 1
225256325Sdteske		}'
226256325Sdteske	)
227256325Sdteske
228256325Sdteske	return $SUCCESS
229256325Sdteske}
230256325Sdteske
231256325Sdteske# f_keymap_kbdcontrol $keymap
232256325Sdteske#
233256325Sdteske# Install keyboard map file from $keymap.
234256325Sdteske#
235256325Sdteskef_keymap_kbdcontrol()
236256325Sdteske{
237256325Sdteske	local keymap="$1"
238256325Sdteske
239256325Sdteske	[ "$keymap" ] || return $SUCCESS
240256325Sdteske
241256325Sdteske	# Fixup keymap if it doesn't already contain at least one `/'
242256325Sdteske	[ "${keymap#*/}" = "$keymap" ] && keymap="$DEFAULT_KEYMAP_DIR/$keymap"
243256325Sdteske
244256325Sdteske	[ "$USE_XDIALOG" ] || kbdcontrol -l "$keymap"
245256325Sdteske}
246256325Sdteske
247256325Sdteske############################################################ MAIN
248256325Sdteske
249256325Sdteske#
250256325Sdteske# Scan for keymaps unless requeted otherwise
251256325Sdteske#
252256325Sdteskef_dprintf "%s: KEYMAP_SELF_SCAN_ALL=[%s]" keymap.subr "$KEYMAP_SELF_SCAN_ALL"
253256325Sdteskecase "$KEYMAP_SELF_SCAN_ALL" in
254256325Sdteske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
255256325Sdteske*) f_keymap_get_all
256256325Sdteskeesac
257256325Sdteske
258260678Sdteskef_count NKEYMAPS $KEYMAPS
259260678Sdteskef_dprintf "%s: Found %u keymap file(s)." keymap.subr $NKEYMAPS
260256325Sdteske
261256325Sdteskef_dprintf "%s: Successfully loaded." keymap.subr
262256325Sdteske
263256325Sdteskefi # ! $_KEYMAP_SUBR
264