xref: /freebsd/usr.sbin/bsdconfig/share/keymap.subr (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
13636c235SDevin Teskeif [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1
23636c235SDevin Teske#
335994c42SDevin 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#
283636c235SDevin Teske############################################################ INCLUDES
293636c235SDevin Teske
303636c235SDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig"
313636c235SDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
323636c235SDevin Teskef_dprintf "%s: loading includes..." keymap.subr
333636c235SDevin Teskef_include $BSDCFG_SHARE/struct.subr
343636c235SDevin Teske
353636c235SDevin Teske############################################################ CONFIGURATION
363636c235SDevin Teske
373636c235SDevin Teske#
383636c235SDevin Teske# Defaults taken from usr.sbin/kbdmap/kbdmap.h
393636c235SDevin Teske#
403636c235SDevin Teske: ${DEFAULT_LANG:=en}
41*ab00ac32SDevin Teskecase "$( sysctl -n kern.vty )" in
42*ab00ac32SDevin Teskevt)	: ${DEFAULT_KEYMAP_DIR:=/usr/share/vt/keymaps}		;;
43*ab00ac32SDevin Teske*)	: ${DEFAULT_KEYMAP_DIR:=/usr/share/syscons/keymaps}	;;
44*ab00ac32SDevin Teskeesac
453636c235SDevin Teske
463636c235SDevin Teske############################################################ GLOBALS
473636c235SDevin Teske
483636c235SDevin TeskeKEYMAPS=
49d4ae33f0SDevin TeskeNKEYMAPS=0
503636c235SDevin Teske
513636c235SDevin Teske# A "keymap" from kbdmap's point of view
523636c235SDevin Teskef_struct_define KEYMAP \
533636c235SDevin Teske	desc \
543636c235SDevin Teske	keym \
553636c235SDevin Teske	mark
563636c235SDevin Teske
573636c235SDevin Teske#
583636c235SDevin Teske# Default behavior is to call f_keymap_get_all() automatically when loaded.
593636c235SDevin Teske#
603636c235SDevin Teske: ${KEYMAP_SELF_SCAN_ALL=1}
613636c235SDevin Teske
623636c235SDevin Teske############################################################ FUNCTIONS
633636c235SDevin Teske
643636c235SDevin Teske# f_keymap_register $name $desc $keym $mark
653636c235SDevin Teske#
663636c235SDevin Teske# Register a keymap. A `structure' (see struct.subr) is created with the name
673636c235SDevin Teske# keymap_$name (so make sure $name contains only alpha-numeric characters or
683636c235SDevin Teske# the underscore, `_'). The remaining arguments after $name correspond to the
693636c235SDevin Teske# propertise of the `KEYMAP' structure-type (defined above).
703636c235SDevin Teske#
713636c235SDevin Teske# If not already registered, the keymap is then appended to the KEYMAPS
723636c235SDevin Teske# environment variable, a space-separated list of all registered keymaps.
733636c235SDevin Teske#
743636c235SDevin Teskef_keymap_register()
753636c235SDevin Teske{
763636c235SDevin Teske	local name="$1" desc="$2" keym="$3" mark="$4"
773636c235SDevin Teske
783636c235SDevin Teske	f_struct_new KEYMAP "keymap_$name" || return $FAILURE
793636c235SDevin Teske	keymap_$name set desc "$desc"
803636c235SDevin Teske	keymap_$name set keym "$keym"
813636c235SDevin Teske	keymap_$name set mark "$mark"
823636c235SDevin Teske
833636c235SDevin Teske	# Scan our global register to see if needs ammending
843636c235SDevin Teske	local k found=
853636c235SDevin Teske	for k in $KEYMAPS; do
863636c235SDevin Teske		[ "$k" = "$name" ] || continue
873636c235SDevin Teske		found=1 && break
883636c235SDevin Teske	done
893636c235SDevin Teske	[ "$found" ] || KEYMAPS="$KEYMAPS $name"
903636c235SDevin Teske
913636c235SDevin Teske	return $SUCCESS
923636c235SDevin Teske}
933636c235SDevin Teske
943636c235SDevin Teske# f_keymap_checkfile $keymap
953636c235SDevin Teske#
963636c235SDevin Teske# Check that $keymap is a readable kbdmap(5) file. Returns success if $keymap
973636c235SDevin Teske# is a file, is readable, and exists in $DEFAULT_KEYMAP_DIR; otherwise failure.
983636c235SDevin Teske# If debugging is enabled, an appropriate debug error message is printed if
993636c235SDevin Teske# $keymap is not available.
1003636c235SDevin Teske#
1013636c235SDevin Teskef_keymap_checkfile()
1023636c235SDevin Teske{
1033636c235SDevin Teske	local keym="$1"
1043636c235SDevin Teske
1053636c235SDevin Teske	# Fixup keymap if it doesn't already contain at least one `/'
1063636c235SDevin Teske	[ "${keym#*/}" = "$keym" ] && keym="$DEFAULT_KEYMAP_DIR/$keym"
1073636c235SDevin Teske
1083636c235SDevin Teske	# Short-cuts
1093636c235SDevin Teske	[ -f "$keym" -a -r "$keym" ] && return $SUCCESS
1103636c235SDevin Teske	f_debugging || return $FAILURE
1113636c235SDevin Teske
1123636c235SDevin Teske	# Print an appropriate debug error message
1133636c235SDevin Teske	if [ ! -e "$keym" ]; then
1143636c235SDevin Teske		f_dprintf "%s: No such file or directory" "$keym"
1153636c235SDevin Teske	elif [ ! -f "$keym" ]; then
1163636c235SDevin Teske		f_dprintf "%s: Not a file!" "$keym"
1173636c235SDevin Teske	elif [ ! -r "$keym" ]; then
1183636c235SDevin Teske		f_dprintf "%s: Permission denied" "$keym"
1193636c235SDevin Teske	fi
1203636c235SDevin Teske
1213636c235SDevin Teske	return $FAILURE
1223636c235SDevin Teske}
1233636c235SDevin Teske
1243636c235SDevin Teske# f_keymap_get_all
1253636c235SDevin Teske#
1263636c235SDevin Teske# Get all keymap information for kbdmap(5) entries both in the database and
1273636c235SDevin Teske# loosely existing in $DEFAULT_KEYMAP_DIR.
1283636c235SDevin Teske#
1293636c235SDevin Teskef_keymap_get_all()
1303636c235SDevin Teske{
1313636c235SDevin Teske	local fname=f_keymap_get_all
1323636c235SDevin Teske	local lang="${LC_ALL:-${LC_CTYPE:-${LANG:-$DEFAULT_LANG}}}"
1333636c235SDevin Teske	[ "$lang" = "C" ] && lang="$DEFAULT_LANG"
1343636c235SDevin Teske
1353636c235SDevin Teske	f_dprintf "%s: Looking for keymap files..." $fname
1363636c235SDevin Teske	f_dialog_info "$msg_looking_for_keymap_files"
1373636c235SDevin Teske	f_dprintf "DEFAULT_LANG=[%s]" "$DEFAULT_LANG"
1383636c235SDevin Teske
1393636c235SDevin Teske	eval "$( awk -F: -v lang="$lang" -v lang_default="$DEFAULT_LANG" '
1403636c235SDevin Teske		BEGIN {
1413636c235SDevin Teske			# en_US.ISO8859-1 -> en_..\.ISO8859-1
1423636c235SDevin Teske			dialect = lang
1433636c235SDevin Teske			if (length(dialect) >= 6 &&
1443636c235SDevin Teske			    substr(dialect, 3, 1) == "_")
1453636c235SDevin Teske				dialect = substr(dialect, 1, 3) ".." \
1463636c235SDevin Teske				          substr(dialect, 6)
1473636c235SDevin Teske			printf "f_dprintf \"dialect=[%%s]\" \"%s\";\n", dialect
1483636c235SDevin Teske
1493636c235SDevin Teske			# en_US.ISO8859-1 -> en
1503636c235SDevin Teske			lang_abk = lang
1513636c235SDevin Teske			if (length(lang_abk) >= 3 &&
1523636c235SDevin Teske			    substr(lang_abk, 3, 1) == "_")
1533636c235SDevin Teske				lang_abk = substr(lang_abk, 1, 2)
1543636c235SDevin Teske			printf "f_dprintf \"lang_abk=[%%s]\" \"%s\";\n",
1553636c235SDevin Teske			       lang_abk
1563636c235SDevin Teske		}
1573636c235SDevin Teske		function find_token(buffer, token)
1583636c235SDevin Teske		{
1593636c235SDevin Teske			if (split(buffer, tokens, /,/) == 0) return 0
1603636c235SDevin Teske			found = 0
1613636c235SDevin Teske			for (t in tokens)
1623636c235SDevin Teske				if (token == tokens[t]) { found = 1; break }
1633636c235SDevin Teske			return found
1643636c235SDevin Teske		}
1653636c235SDevin Teske		function add_keymap(desc,mark,keym)
1663636c235SDevin Teske		{
1673636c235SDevin Teske			marks[keym] = mark
1683636c235SDevin Teske			name = keym
1693636c235SDevin Teske			gsub(/[^[:alnum:]_]/, "_", name)
170bc3f5ec9SDevin Teske			gsub(/'\''/, "'\''\\'\'\''", desc);
1713636c235SDevin Teske			printf "f_keymap_checkfile %s && " \
1723636c235SDevin Teske			       "f_keymap_register %s '\'%s\'' %s %u\n",
1733636c235SDevin Teske			       keym, name, desc, keym, mark
1743636c235SDevin Teske		}
1753636c235SDevin Teske		!/^[[:space:]]*(#|$)/ {
1763636c235SDevin Teske			sub(/^[[:space:]]*/, "", $0)
1773636c235SDevin Teske			keym = $1
1783636c235SDevin Teske			if (keym ~ /^(MENU|FONT)$/) next
1793636c235SDevin Teske			lg = ($2 == "" ? lang_default : $2)
1803636c235SDevin Teske
1813636c235SDevin Teske			# Match the entry and store the type of match we made
1823636c235SDevin Teske			# as the mark value (so that if we make a better match
1833636c235SDevin Teske			# later on with a higher mark, it overwrites previous)
1843636c235SDevin Teske
1853636c235SDevin Teske			mark = marks[keym];
1863636c235SDevin Teske			if (find_token(lg, lang))
1873636c235SDevin Teske				add_keymap($3, 4, keym) # Best match
1883636c235SDevin Teske			else if (mark <= 3 && find_token(lg, dialect))
1893636c235SDevin Teske				add_keymap($3, 3, keym)
1903636c235SDevin Teske			else if (mark <= 2 && find_token(lg, lang_abk))
1913636c235SDevin Teske				add_keymap($3, 2, keym)
1923636c235SDevin Teske			else if (mark <= 1 && find_token(lg, lang_default))
1933636c235SDevin Teske				add_keymap($3, 1, keym)
1943636c235SDevin Teske			else if (mark <= 0)
1953636c235SDevin Teske				add_keymap($3, 0, keym)
1963636c235SDevin Teske		}
1973636c235SDevin Teske	' "$DEFAULT_KEYMAP_DIR/INDEX.${DEFAULT_KEYMAP_DIR##*/}" )"
1983636c235SDevin Teske
1993636c235SDevin Teske
2003636c235SDevin Teske	#
2013636c235SDevin Teske	# Look for keymaps not in database
2023636c235SDevin Teske	#
2033636c235SDevin Teske	local direntry keym name
2043636c235SDevin Teske	set +f # glob
2053636c235SDevin Teske	for direntry in "$DEFAULT_KEYMAP_DIR"/*; do
2063636c235SDevin Teske		[ "${direntry##*.}" = ".kbd" ] || continue
2073636c235SDevin Teske		keym="${direntry##*/}"
2083636c235SDevin Teske		f_str2varname "$keym" name
2093636c235SDevin Teske		f_struct keymap_$name && continue
2103636c235SDevin Teske		f_keymap_checkfile "$keym" &&
2113636c235SDevin Teske			f_keymap_register $name "${keym%.*}" "$keym" 0
2123636c235SDevin Teske		f_dprintf "%s: not in kbdmap(5) database" "$keym"
2133636c235SDevin Teske	done
2143636c235SDevin Teske
2153636c235SDevin Teske	#
2163636c235SDevin Teske	# Sort the items by their descriptions
2173636c235SDevin Teske	#
2183636c235SDevin Teske	f_dprintf "%s: Sorting keymap entries by description..." $fname
2193636c235SDevin Teske	KEYMAPS=$(
2203636c235SDevin Teske		for k in $KEYMAPS; do
2213636c235SDevin Teske			echo -n "$k "
2223636c235SDevin Teske			# NOTE: Translate '8x8' to '8x08' before sending to
2233636c235SDevin Teske			# sort(1) so that things work out as we might expect.
22494f2a70eSDevin Teske			debug= keymap_$k get desc | awk 'gsub(/8x8/,"8x08")||1'
2253636c235SDevin Teske		done | sort -k2 | awk '{
2263636c235SDevin Teske			printf "%s%s", (started ? " " : ""), $1; started = 1
2273636c235SDevin Teske		}'
2283636c235SDevin Teske	)
2293636c235SDevin Teske
2303636c235SDevin Teske	return $SUCCESS
2313636c235SDevin Teske}
2323636c235SDevin Teske
2333636c235SDevin Teske# f_keymap_kbdcontrol $keymap
2343636c235SDevin Teske#
2353636c235SDevin Teske# Install keyboard map file from $keymap.
2363636c235SDevin Teske#
2373636c235SDevin Teskef_keymap_kbdcontrol()
2383636c235SDevin Teske{
2393636c235SDevin Teske	local keymap="$1"
2403636c235SDevin Teske
2413636c235SDevin Teske	[ "$keymap" ] || return $SUCCESS
2423636c235SDevin Teske
2433636c235SDevin Teske	# Fixup keymap if it doesn't already contain at least one `/'
2443636c235SDevin Teske	[ "${keymap#*/}" = "$keymap" ] && keymap="$DEFAULT_KEYMAP_DIR/$keymap"
2453636c235SDevin Teske
2463636c235SDevin Teske	[ "$USE_XDIALOG" ] || kbdcontrol -l "$keymap"
2473636c235SDevin Teske}
2483636c235SDevin Teske
2493636c235SDevin Teske############################################################ MAIN
2503636c235SDevin Teske
2513636c235SDevin Teske#
2523636c235SDevin Teske# Scan for keymaps unless requeted otherwise
2533636c235SDevin Teske#
2543636c235SDevin Teskef_dprintf "%s: KEYMAP_SELF_SCAN_ALL=[%s]" keymap.subr "$KEYMAP_SELF_SCAN_ALL"
2553636c235SDevin Teskecase "$KEYMAP_SELF_SCAN_ALL" in
2563636c235SDevin Teske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
2573636c235SDevin Teske*) f_keymap_get_all
2583636c235SDevin Teskeesac
2593636c235SDevin Teske
260d4ae33f0SDevin Teskef_count NKEYMAPS $KEYMAPS
261d4ae33f0SDevin Teskef_dprintf "%s: Found %u keymap file(s)." keymap.subr $NKEYMAPS
2623636c235SDevin Teske
2633636c235SDevin Teskef_dprintf "%s: Successfully loaded." keymap.subr
2643636c235SDevin Teske
2653636c235SDevin Teskefi # ! $_KEYMAP_SUBR
266