#!/bin/sh
# 10 Feb 2010 by shinobar (Masaki Shinomiya <shino@pos.to>)
# 15 Feb 2010 remove include dir etc. from list
# 18 Jul 2010 work without layouts file, remove error messages from dialog reply
# 21 Jul 2010 opton '-load' force sets X properties
# 24 Jul 2010 add input section if not exists (thanks to Abnormalter), variant qwerty|qwertz
# 11 Aug 2010 keymap_previous to prevent xwin rewrites
# 12 Aug 2010 azerty(fr) fixed
#  5 Jan 2011 Allow keymaps work with with X but do not on the consile
#111020 fix spelling typo.
#120627 handle different path to keymaps in kbd pkg.
#120715 fix wrong pattern, 'de' was finding 'de-latin1'. fix symbols different location.

MYNAME=$(basename $0)
VERSION=20100812
usage() {
	echo "$MYNAME ver.-$VERSION
usage: $MYNAME [ somekeymap ]
		set keymap to 'somekeymap' or ask with dialog
	$MYNAME cli
		ask keymap with console dialog
	$MYNAME --load
	    set keymap according to /etc/keymap
	$MYNAME --xopt [ somekeymap ]
		show xorg.conf xkb options for 'somekeymap' or according to /etc/keymap
	$MYNAME --list
		show available key maps"
	exit 1
}
xmap() {
  M=$1
  case "$M" in
    az*) M="fr";;	#azerty
    cf*) M="ca";;	#canadian french
    cr*) M="hr";;	#croat
    dv*) M="us";;	#dvorak
    mk*) M="mkd";;	#macedonia
    sl*) M="si";;	#slovene
    sv) M="se";;	#sweden
    uk) M="gb";;	#united kingdom
    wa*) M="be";;	#wangbe
    *)  M=$(echo $M|cut -b 1-2)
        echo "$SYMBOLS" | grep -q "$M" || M="us"
      ;;
  esac
  echo $M
}
makelist() {
    DEFMAP="us"
    MAPS=$(echo "$MAPS"| grep -v "^$OLDMAP\$"| grep -v "^$DEFMAP"| sed -e 's/\.map//')
    OLDMAP=$(basename $OLDMAP .map)
   [ "$OLDMAP" = "$DEFMAP" ] && DEFMAP=""
    if [ -f /usr/share/i18n/layouts ]; then
      for MP in $OLDMAP $DEFMAP $MAPS; do
        M=$(echo $MP| tr '1' '-'| cut -d'-' -f1)
        M=$(xmap $M)
        M=$(grep "^[[:blank:]]*$M " /usr/share/i18n/layouts| sed -e 's/^[[:blank:]]*[a-z-]*[ ]*//')
        echo -n "$MP"
        [ "$M" != "" ] && echo " ($M)" || echo " ."
      done
    else
      #echo "$OLDMAP"
      #[ "$DEFMAP" != "" ] && echo "$DEFMAP" 
      #echo "$MAPS"
      for MP in $OLDMAP $DEFMAP $MAPS; do
        echo "$MP ."
      done
    fi
}

[ $# -le 2 ] || usage
LANGORG=$LANG
LANG=C

KMAPPATH='/lib/keymaps'
[ -d /usr/share/kbd/keymaps/i386 ] && KMAPPATH='/usr/share/kbd/keymaps/i386'
[ -d /usr/share/keymaps/i386 ] && KMAPPATH='/usr/share/keymaps/i386' #debian, gentoo. note, debian files have extension .kmap.gz, gentoo have .map.gz
case $KMAPPATH in #120627
 /lib/keymaps) KMAPFILES="`find /lib/keymaps -mindepth 1 -maxdepth 1 -name '*.gz' | sort`" ;; #ex: us.gz
 *) KMAPFILES="`find ${KMAPPATH}/[^i]* -name '*.map' -o -name '*.kmap' -o -name '*.map.gz' -o -name '*.kmap.gz' -not -name 'defkeymap*' | sort`" ;;
esac
MAPS="$(echo "$KMAPFILES" | sed -e 's%^.*/%%' -e 's%\.gz$%%')"

if [ -d /etc/X11/xkb/symbols/pc ];then #120715 fix symbols different location.
 SYMBOLS=$(ls -1 /etc/X11/xkb/symbols/pc)
else
 SYMBOLS="$(find /etc/X11/xkb/symbols -mindepth 1 -maxdepth 1 -type f | sed -e 's%/etc/X11/xkb/symbols/%%')"
fi
OLDMAP=""
[ -f /etc/keymap ] && OLDMAP=$(cat /etc/keymap)
[ "$OLDMAP" = "" ] && OLDMAP="us"
[ "$DISPLAY" ] && XSTATUS="yes" || XSTATUS=""

# options
NEWMAP=""
XOPT=""
VERBOSE=""
case "$1" in
  *-li*) # show available key maps
    makelist
    exit ;;
  *-lo*) # load keymap according /etc/keymap
    NEWMAP=$(cat /etc/keymap 2>/dev/null)
    VERBOSE="yes"
    ;;
  *-x*)
    XOPT="yes"
    shift
    [ "$1" != "" ] ||  NEWMAP=$(cat /etc/keymap 2>/dev/null)
   ;;
  cli) XSTATUS=""; shift;;
  -ver)	echo "$MYNAME ver.-$VERSION"; exit;;
  -*) usage;;
esac
[ $# -le 1 ] || usage

# verify
[ "$NEWMAP" != "" ] || NEWMAP=$(basename "$1" .gz)
if [ "$NEWMAP" = "" ] ; then
  DIALOG="dialog --aspect 10"
  MENUOPT="--menu"
  REP=/tmp/$(basename $0).txt
  [ "$XSTATUS" = "yes" ] && DIALOG="Xdialog" && MENUOPT="--menubox"
  CHOICES=$(makelist)
  CHOICES=$(echo $CHOICES|sed -e "s/(/'(/g" -e "s/)/)'/g")
  eval "$DIALOG --title \"$(gettext 'Setting keyboard layout')\"  $MENUOPT \"$(gettext 'Choose keyboard layout for your country...')\" 0 0 0 $CHOICES" 2>$REP #111020 typo.
  NEWMAP=$(tail -n 1 $REP)
  rm -f $REP
fi
NEW=$(echo "$MAPS"|grep "^${NEWMAP}$"| head -n 1) #120715 wrong, fix.
if [ "$NEW" = "" ];then
  NEWMAP=$(echo $NEWMAP| cut -b 1-2)
  NEW=$(echo "$MAPS"|grep -w "^$NEWMAP"| head -n 1)
fi
#echo "NEWMAP=$NEWMAP"
# keymap for X. NEWMAP can be *.map
XKEYMAP=$(basename $NEWMAP .kmap) #120627
XKEYMAP=$(basename $XKEYMAP .map)
MODEL="pc102"
VARIANT=""
if ! echo "$SYMBOLS" | grep -q "$XKEYMAP"; then 
  XK1=$(echo $XKEYMAP | cut -d'-' -f1)
  XK2=$(echo $XKEYMAP | cut -d'-' -f2)
  XK3=$(echo $XKEYMAP | cut -d'-' -f3)
  XKEYMAP=$(xmap $XK1)
  if [ "$XK2" != "" ]; then
    for K in $XK1 $XK2 $XK3; do
      case "$K" in
        dvorak|qwerty|qwertz) VARIANT="$K";;
      esac
    done
  fi
fi
LAYOUT=$XKEYMAP
case $XKEYMAP in
  br*) MODEL="abnt2"
       LAYOUT="br";;
  jp*) MODEL="jp106"
       LAYOUT="jp";;
esac

# xopt
if [ "$XOPT" = "yes" ]; then
  echo "XKBMODEL=\"$MODEL\""
  echo "XKBLAYOUT=\"$LAYOUT\""
  echo "XKBVARIANT=\"$VARIANT\""
  exit 0
fi

# update
if [ "$NEW" != "" ];then
  NEWMAP=$NEW
  #[ "$NEWMAP" = "$OLDMAP" ] && exit 0
  [ "$VERBOSE" ] && echo -ne "Loading \"$NEWMAP\" keyboard map... "
  echo -n $NEWMAP > /etc/keymap
  cp -f /etc/keymap /etc/keymap_previous	# prevent xwin rewrites
  case $NEWMAP in
    *.map|*.kmap) loadkeys $NEWMAP || exit 1 #120627
    ;;
    *) /bin/gzip -dcf /lib/keymaps/$NEWMAP.gz | /sbin/loadkmap || exit 1
    ;;
  esac
elif [ -s /usr/share/i18n/layouts ]; then
  NEW=$(grep -w "$NEWMAP" /usr/share/i18n/layouts| head -n 1 | tr -s ' ' |cut -d ' ' -f2)
  [ "$NEW" != "" ] && echo "Warning: The keymap '$NEW' does not act on the console(without X)." >&2
fi
[ "$NEW" != "" ] && NEWMAP=$NEW || exit 1
echo -n $NEWMAP > /etc/keymap

#[ "$NEWMAP" = "$OLDMAP" ] && exit 0
# apply xkeymap now
XVARIANT=""
[ "$VARIANT" != "" ] && XVARIANT="-variant $VARIANT"
setxkbmap -rules xorg -model "$MODEL" -layout "$LAYOUT" $XVARIANT || exit 1

# rewrite xorg.conf
F=/etc/X11/xorg.conf
TMPF=/tmp/xorg.conf
# read old settings
ALINE=$(grep -i '^[[:blank:]]*Option.*XkbModel' $F| head -n 1| cut -d'#' -f1)
for W in $ALINE; do :; done	# set last word to W
OLDMODEL=$(echo $W|tr -d '"')
ALINE=$(grep -i '^[[:blank:]]*Option.*XkbLayOut' $F| head -n 1| cut -d'#' -f1)
for W in $ALINE; do :; done
OLDLAYOUT=$(echo $W|tr -d '"')
ALINE=$(grep -i '^[[:blank:]]*Option.*XkbVariant' $F| head -n 1| cut -d'#' -f1)
for W in $ALINE; do :; done	# set last word to W
OLDVARIANT=$(echo $W|tr -d '"')
#[ "$OLDMODEL" =  "" -a "$OLDLAYOUT" = "" ] && exit
# rewrite xorg.conf
if [ "$MODEL" != "$OLDMODEL" -o "$LAYOUT" != "$OLDLAYOUT" -o "$VARIANT" != "$OLDVARIANT" ]; then
  (while read ALINE; do
    FOUND="yes"
    echo $ALINE| grep -v '^[[:blank:]]*Option.*Xkb' || break
    FOUND=""
   done
   if [ "$FOUND" = "" ]; then
   echo 'Section "InputDevice"
	Identifier  "Keyboard0"
	Driver      "kbd"'
   fi
   echo "    Option         \"XkbRules\" \"xorg\""
   echo "    Option         \"XkbModel\" \"$MODEL\""
   echo "    Option         \"XkbLayout\" \"$LAYOUT\" #xkeymap0"
   [ "$VARIANT" != "" ] && echo "    Option         \"XkbVariant\" \"$VARIANT\""
   if [ "$FOUND" = "" ]; then
   echo 'EndSection'
   fi
   while read ALINE; do
	 echo $ALINE| grep -v '^[[:blank:]]*Option.*Xkb' && break
   done
   while read ALINE; do echo $ALINE; done) <$F >$TMPF
  [ -s $TMPF ] && mv -f $F $F.bak && mv $TMPF $F
fi