xref: /freebsd/usr.sbin/bsdconfig/share/keymap.subr (revision 35994c42c3473d6b9b18d873aa442e4b54f5bb4f)
13636c235SDevin Teskeif [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1
23636c235SDevin Teske#
3*35994c42SDevin Teske# Copyright (c) 2013-2015 Devin Teske
43636c235SDevin Teske# All rights reserved.
53636c235SDevin Teske#
63636c235SDevin Teske# Redistribution and use in source and binary forms, with or without
73636c235SDevin Teske# modification, are permitted provided that the following conditions
83636c235SDevin Teske# are met:
93636c235SDevin Teske# 1. Redistributions of source code must retain the above copyright
103636c235SDevin Teske#    notice, this list of conditions and the following disclaimer.
113636c235SDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
123636c235SDevin Teske#    notice, this list of conditions and the following disclaimer in the
133636c235SDevin Teske#    documentation and/or other materials provided with the distribution.
143636c235SDevin Teske#
153636c235SDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163636c235SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173636c235SDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183636c235SDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193636c235SDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203636c235SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213636c235SDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223636c235SDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233636c235SDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243636c235SDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253636c235SDevin Teske# SUCH DAMAGE.
263636c235SDevin Teske#
273636c235SDevin Teske# $FreeBSD$
283636c235SDevin Teske#
293636c235SDevin Teske############################################################ INCLUDES
303636c235SDevin Teske
313636c235SDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig"
323636c235SDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
333636c235SDevin Teskef_dprintf "%s: loading includes..." keymap.subr
343636c235SDevin Teskef_include $BSDCFG_SHARE/struct.subr
353636c235SDevin Teske
363636c235SDevin Teske############################################################ CONFIGURATION
373636c235SDevin Teske
383636c235SDevin Teske#
393636c235SDevin Teske# Defaults taken from usr.sbin/kbdmap/kbdmap.h
403636c235SDevin Teske#
413636c235SDevin Teske: ${DEFAULT_LANG:=en}
423636c235SDevin Teske: ${DEFAULT_KEYMAP_DIR:=/usr/share/syscons/keymaps}
433636c235SDevin Teske
443636c235SDevin Teske############################################################ GLOBALS
453636c235SDevin Teske
463636c235SDevin TeskeKEYMAPS=
47d4ae33f0SDevin TeskeNKEYMAPS=0
483636c235SDevin Teske
493636c235SDevin Teske# A "keymap" from kbdmap's point of view
503636c235SDevin Teskef_struct_define KEYMAP \
513636c235SDevin Teske	desc \
523636c235SDevin Teske	keym \
533636c235SDevin Teske	mark
543636c235SDevin Teske
553636c235SDevin Teske#
563636c235SDevin Teske# Default behavior is to call f_keymap_get_all() automatically when loaded.
573636c235SDevin Teske#
583636c235SDevin Teske: ${KEYMAP_SELF_SCAN_ALL=1}
593636c235SDevin Teske
603636c235SDevin Teske############################################################ FUNCTIONS
613636c235SDevin Teske
623636c235SDevin Teske# f_keymap_register $name $desc $keym $mark
633636c235SDevin Teske#
643636c235SDevin Teske# Register a keymap. A `structure' (see struct.subr) is created with the name
653636c235SDevin Teske# keymap_$name (so make sure $name contains only alpha-numeric characters or
663636c235SDevin Teske# the underscore, `_'). The remaining arguments after $name correspond to the
673636c235SDevin Teske# propertise of the `KEYMAP' structure-type (defined above).
683636c235SDevin Teske#
693636c235SDevin Teske# If not already registered, the keymap is then appended to the KEYMAPS
703636c235SDevin Teske# environment variable, a space-separated list of all registered keymaps.
713636c235SDevin Teske#
723636c235SDevin Teskef_keymap_register()
733636c235SDevin Teske{
743636c235SDevin Teske	local name="$1" desc="$2" keym="$3" mark="$4"
753636c235SDevin Teske
763636c235SDevin Teske	f_struct_new KEYMAP "keymap_$name" || return $FAILURE
773636c235SDevin Teske	keymap_$name set desc "$desc"
783636c235SDevin Teske	keymap_$name set keym "$keym"
793636c235SDevin Teske	keymap_$name set mark "$mark"
803636c235SDevin Teske
813636c235SDevin Teske	# Scan our global register to see if needs ammending
823636c235SDevin Teske	local k found=
833636c235SDevin Teske	for k in $KEYMAPS; do
843636c235SDevin Teske		[ "$k" = "$name" ] || continue
853636c235SDevin Teske		found=1 && break
863636c235SDevin Teske	done
873636c235SDevin Teske	[ "$found" ] || KEYMAPS="$KEYMAPS $name"
883636c235SDevin Teske
893636c235SDevin Teske	return $SUCCESS
903636c235SDevin Teske}
913636c235SDevin Teske
923636c235SDevin Teske# f_keymap_checkfile $keymap
933636c235SDevin Teske#
943636c235SDevin Teske# Check that $keymap is a readable kbdmap(5) file. Returns success if $keymap
953636c235SDevin Teske# is a file, is readable, and exists in $DEFAULT_KEYMAP_DIR; otherwise failure.
963636c235SDevin Teske# If debugging is enabled, an appropriate debug error message is printed if
973636c235SDevin Teske# $keymap is not available.
983636c235SDevin Teske#
993636c235SDevin Teskef_keymap_checkfile()
1003636c235SDevin Teske{
1013636c235SDevin Teske	local keym="$1"
1023636c235SDevin Teske
1033636c235SDevin Teske	# Fixup keymap if it doesn't already contain at least one `/'
1043636c235SDevin Teske	[ "${keym#*/}" = "$keym" ] && keym="$DEFAULT_KEYMAP_DIR/$keym"
1053636c235SDevin Teske
1063636c235SDevin Teske	# Short-cuts
1073636c235SDevin Teske	[ -f "$keym" -a -r "$keym" ] && return $SUCCESS
1083636c235SDevin Teske	f_debugging || return $FAILURE
1093636c235SDevin Teske
1103636c235SDevin Teske	# Print an appropriate debug error message
1113636c235SDevin Teske	if [ ! -e "$keym" ]; then
1123636c235SDevin Teske		f_dprintf "%s: No such file or directory" "$keym"
1133636c235SDevin Teske	elif [ ! -f "$keym" ]; then
1143636c235SDevin Teske		f_dprintf "%s: Not a file!" "$keym"
1153636c235SDevin Teske	elif [ ! -r "$keym" ]; then
1163636c235SDevin Teske		f_dprintf "%s: Permission denied" "$keym"
1173636c235SDevin Teske	fi
1183636c235SDevin Teske
1193636c235SDevin Teske	return $FAILURE
1203636c235SDevin Teske}
1213636c235SDevin Teske
1223636c235SDevin Teske# f_keymap_get_all
1233636c235SDevin Teske#
1243636c235SDevin Teske# Get all keymap information for kbdmap(5) entries both in the database and
1253636c235SDevin Teske# loosely existing in $DEFAULT_KEYMAP_DIR.
1263636c235SDevin Teske#
1273636c235SDevin Teskef_keymap_get_all()
1283636c235SDevin Teske{
1293636c235SDevin Teske	local fname=f_keymap_get_all
1303636c235SDevin Teske	local lang="${LC_ALL:-${LC_CTYPE:-${LANG:-$DEFAULT_LANG}}}"
1313636c235SDevin Teske	[ "$lang" = "C" ] && lang="$DEFAULT_LANG"
1323636c235SDevin Teske
1333636c235SDevin Teske	f_dprintf "%s: Looking for keymap files..." $fname
1343636c235SDevin Teske	f_dialog_info "$msg_looking_for_keymap_files"
1353636c235SDevin Teske	f_dprintf "DEFAULT_LANG=[%s]" "$DEFAULT_LANG"
1363636c235SDevin Teske
1373636c235SDevin Teske	eval "$( awk -F: -v lang="$lang" -v lang_default="$DEFAULT_LANG" '
1383636c235SDevin Teske		BEGIN {
1393636c235SDevin Teske			# en_US.ISO8859-1 -> en_..\.ISO8859-1
1403636c235SDevin Teske			dialect = lang
1413636c235SDevin Teske			if (length(dialect) >= 6 &&
1423636c235SDevin Teske			    substr(dialect, 3, 1) == "_")
1433636c235SDevin Teske				dialect = substr(dialect, 1, 3) ".." \
1443636c235SDevin Teske				          substr(dialect, 6)
1453636c235SDevin Teske			printf "f_dprintf \"dialect=[%%s]\" \"%s\";\n", dialect
1463636c235SDevin Teske
1473636c235SDevin Teske			# en_US.ISO8859-1 -> en
1483636c235SDevin Teske			lang_abk = lang
1493636c235SDevin Teske			if (length(lang_abk) >= 3 &&
1503636c235SDevin Teske			    substr(lang_abk, 3, 1) == "_")
1513636c235SDevin Teske				lang_abk = substr(lang_abk, 1, 2)
1523636c235SDevin Teske			printf "f_dprintf \"lang_abk=[%%s]\" \"%s\";\n",
1533636c235SDevin Teske			       lang_abk
1543636c235SDevin Teske		}
1553636c235SDevin Teske		function find_token(buffer, token)
1563636c235SDevin Teske		{
1573636c235SDevin Teske			if (split(buffer, tokens, /,/) == 0) return 0
1583636c235SDevin Teske			found = 0
1593636c235SDevin Teske			for (t in tokens)
1603636c235SDevin Teske				if (token == tokens[t]) { found = 1; break }
1613636c235SDevin Teske			return found
1623636c235SDevin Teske		}
1633636c235SDevin Teske		function add_keymap(desc,mark,keym)
1643636c235SDevin Teske		{
1653636c235SDevin Teske			marks[keym] = mark
1663636c235SDevin Teske			name = keym
1673636c235SDevin Teske			gsub(/[^[:alnum:]_]/, "_", name)
168bc3f5ec9SDevin Teske			gsub(/'\''/, "'\''\\'\'\''", desc);
1693636c235SDevin Teske			printf "f_keymap_checkfile %s && " \
1703636c235SDevin Teske			       "f_keymap_register %s '\'%s\'' %s %u\n",
1713636c235SDevin Teske			       keym, name, desc, keym, mark
1723636c235SDevin Teske		}
1733636c235SDevin Teske		!/^[[:space:]]*(#|$)/ {
1743636c235SDevin Teske			sub(/^[[:space:]]*/, "", $0)
1753636c235SDevin Teske			keym = $1
1763636c235SDevin Teske			if (keym ~ /^(MENU|FONT)$/) next
1773636c235SDevin Teske			lg = ($2 == "" ? lang_default : $2)
1783636c235SDevin Teske
1793636c235SDevin Teske			# Match the entry and store the type of match we made
1803636c235SDevin Teske			# as the mark value (so that if we make a better match
1813636c235SDevin Teske			# later on with a higher mark, it overwrites previous)
1823636c235SDevin Teske
1833636c235SDevin Teske			mark = marks[keym];
1843636c235SDevin Teske			if (find_token(lg, lang))
1853636c235SDevin Teske				add_keymap($3, 4, keym) # Best match
1863636c235SDevin Teske			else if (mark <= 3 && find_token(lg, dialect))
1873636c235SDevin Teske				add_keymap($3, 3, keym)
1883636c235SDevin Teske			else if (mark <= 2 && find_token(lg, lang_abk))
1893636c235SDevin Teske				add_keymap($3, 2, keym)
1903636c235SDevin Teske			else if (mark <= 1 && find_token(lg, lang_default))
1913636c235SDevin Teske				add_keymap($3, 1, keym)
1923636c235SDevin Teske			else if (mark <= 0)
1933636c235SDevin Teske				add_keymap($3, 0, keym)
1943636c235SDevin Teske		}
1953636c235SDevin Teske	' "$DEFAULT_KEYMAP_DIR/INDEX.${DEFAULT_KEYMAP_DIR##*/}" )"
1963636c235SDevin Teske
1973636c235SDevin Teske
1983636c235SDevin Teske	#
1993636c235SDevin Teske	# Look for keymaps not in database
2003636c235SDevin Teske	#
2013636c235SDevin Teske	local direntry keym name
2023636c235SDevin Teske	set +f # glob
2033636c235SDevin Teske	for direntry in "$DEFAULT_KEYMAP_DIR"/*; do
2043636c235SDevin Teske		[ "${direntry##*.}" = ".kbd" ] || continue
2053636c235SDevin Teske		keym="${direntry##*/}"
2063636c235SDevin Teske		f_str2varname "$keym" name
2073636c235SDevin Teske		f_struct keymap_$name && continue
2083636c235SDevin Teske		f_keymap_checkfile "$keym" &&
2093636c235SDevin Teske			f_keymap_register $name "${keym%.*}" "$keym" 0
2103636c235SDevin Teske		f_dprintf "%s: not in kbdmap(5) database" "$keym"
2113636c235SDevin Teske	done
2123636c235SDevin Teske
2133636c235SDevin Teske	#
2143636c235SDevin Teske	# Sort the items by their descriptions
2153636c235SDevin Teske	#
2163636c235SDevin Teske	f_dprintf "%s: Sorting keymap entries by description..." $fname
2173636c235SDevin Teske	KEYMAPS=$(
2183636c235SDevin Teske		for k in $KEYMAPS; do
2193636c235SDevin Teske			echo -n "$k "
2203636c235SDevin Teske			# NOTE: Translate '8x8' to '8x08' before sending to
2213636c235SDevin Teske			# sort(1) so that things work out as we might expect.
22294f2a70eSDevin Teske			debug= keymap_$k get desc | awk 'gsub(/8x8/,"8x08")||1'
2233636c235SDevin Teske		done | sort -k2 | awk '{
2243636c235SDevin Teske			printf "%s%s", (started ? " " : ""), $1; started = 1
2253636c235SDevin Teske		}'
2263636c235SDevin Teske	)
2273636c235SDevin Teske
2283636c235SDevin Teske	return $SUCCESS
2293636c235SDevin Teske}
2303636c235SDevin Teske
2313636c235SDevin Teske# f_keymap_kbdcontrol $keymap
2323636c235SDevin Teske#
2333636c235SDevin Teske# Install keyboard map file from $keymap.
2343636c235SDevin Teske#
2353636c235SDevin Teskef_keymap_kbdcontrol()
2363636c235SDevin Teske{
2373636c235SDevin Teske	local keymap="$1"
2383636c235SDevin Teske
2393636c235SDevin Teske	[ "$keymap" ] || return $SUCCESS
2403636c235SDevin Teske
2413636c235SDevin Teske	# Fixup keymap if it doesn't already contain at least one `/'
2423636c235SDevin Teske	[ "${keymap#*/}" = "$keymap" ] && keymap="$DEFAULT_KEYMAP_DIR/$keymap"
2433636c235SDevin Teske
2443636c235SDevin Teske	[ "$USE_XDIALOG" ] || kbdcontrol -l "$keymap"
2453636c235SDevin Teske}
2463636c235SDevin Teske
2473636c235SDevin Teske############################################################ MAIN
2483636c235SDevin Teske
2493636c235SDevin Teske#
2503636c235SDevin Teske# Scan for keymaps unless requeted otherwise
2513636c235SDevin Teske#
2523636c235SDevin Teskef_dprintf "%s: KEYMAP_SELF_SCAN_ALL=[%s]" keymap.subr "$KEYMAP_SELF_SCAN_ALL"
2533636c235SDevin Teskecase "$KEYMAP_SELF_SCAN_ALL" in
2543636c235SDevin Teske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
2553636c235SDevin Teske*) f_keymap_get_all
2563636c235SDevin Teskeesac
2573636c235SDevin Teske
258d4ae33f0SDevin Teskef_count NKEYMAPS $KEYMAPS
259d4ae33f0SDevin Teskef_dprintf "%s: Found %u keymap file(s)." keymap.subr $NKEYMAPS
2603636c235SDevin Teske
2613636c235SDevin Teskef_dprintf "%s: Successfully loaded." keymap.subr
2623636c235SDevin Teske
2633636c235SDevin Teskefi # ! $_KEYMAP_SUBR
264