#!/bin/bash

# Copyright Jean-Philippe Guillemin <jp.guillemin@free.fr>. This program is free software;
# you can redistribute it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version. Please take a look at http://www.gnu.org/copyleft/gpl.htm

# This script asks for the preferred keyboard map and configures rc.keymap and xorg.conf


if ! command -v yad >/dev/null 2>&1; then
  echo "yad is required but was not found in PATH." >&2
  exit 1
fi

if [ ! "$DISPLAY" ]; then
  echo "This program requires a running X session." >&2
  exit 1
fi

# create the tmpDir directory
export tmpDir="$(mktemp -d -p /tmp temp.XXXXXXXX)"

# remove the tmpDir directory on any type of exit
trap 'rm -rf $tmpDir 2>/dev/null' TERM INT EXIT

backToHome=$(pwd)

# Path needs to be extended in case you're only half a root :)
export PATH="${PATH}:/usr/sbin:/sbin"

if [ "$(id -u)" != "0" ]; then
  yad --center --title "Root only" --text "You need to be root to run $(basename $0)" --button="OK:0"
  exit
fi

keymapDir='/usr/share/kbd/keymaps/i386'
cd $keymapDir

# Probing the current keymap

if [ ! -e /etc/rc.d/rc.keymap ] ; then
cat << "EORC" > /etc/rc.d/rc.keymap
#!/bin/sh
# Load the keyboard map.  More maps are in /usr/share/kbd/keymaps.
if [ -x /usr/bin/loadkeys ]; then
 /usr/bin/loadkeys us.map
fi
EORC
fi

currentKeymap=$(cat /etc/rc.d/rc.keymap \
    | grep "^[[:space:]]*\/usr\/bin\/loadkeys.*" \
    | sed -e 's/^.*loadkeys *\(.*\)$/\1/')

if [ "$currentKeymap" ] ; then
  [ ! "$(echo $currentKeymap | grep 'map')" ] && currentKeymap="${currentKeymap}.map"

  # We get the corresponding current path/key.map
  currentPathKeymap="$(ls */* \
  | egrep "azerty|qwerty|dvorak|qwertz" \
  | grep "\/$currentKeymap" \
  | sed -e 's/^\(.*\).gz$/\1/')"

fi

[ ! "$currentPathKeymap" ] && currentPathKeymap="qwerty/us.map"

# Read current numlock state (best-effort: on if rc.numlock is executable)
if [ -x /etc/rc.d/rc.numlock ] ; then
  numlockState="TRUE"
else
  numlockState="FALSE"
fi

# Build the keymap row list, putting the currently active keymap first and pre-selected
kmList="$(ls */* 2>/dev/null | egrep "azerty|qwerty|dvorak|qwertz" | egrep 'map.gz' | sed -e 's/\.gz$//')"
kmList="$(printf '%s\n' "$kmList" | grep -vFx "$currentPathKeymap")"
kmList="$(printf '%s\n%s' "$currentPathKeymap" "$kmList")"

rowArgs=()
first="TRUE"
while IFS= read -r kmPath; do
  [ ! "$kmPath" ] && continue
  rowArgs+=("$first" "$kmPath" " ")
  first="FALSE"
done <<< "$kmList"

pathKeymap=$(yad --center --width=520 --height=520 \
  --title "Keyboard configuration" \
  --text "Please select your preferred keyboard map (current: <b>$currentPathKeymap</b>):" \
  --list --no-headers --radiolist \
  --column="Select" --column="Keymap" --column="Description" \
  --button="Exit:1" --button="Select:0" \
  --print-column=2 \
  "${rowArgs[@]}")
rc=$?
pathKeymap="${pathKeymap%|*}"

if [ $rc -eq 0 ] && [ "$pathKeymap" ] ; then

  # Ask for numlock state as a separate toggle (pre-filled with current state)
  if [ "$numlockState" = "TRUE" ]; then
    numlockDefault="TRUE"
  else
    numlockDefault="FALSE"
  fi
  numlockResult=$(yad --center --title "Numlock" \
    --text "Enable Num Lock at boot?" \
    --form --field="Enable Num Lock:CHK" "$numlockDefault" \
    --button="OK:0")
  if [ "$(echo "$numlockResult" | cut -d'|' -f1)" = "TRUE" ]; then
    numlock="checked"
  else
    numlock="unchecked"
  fi

  if [ "$numlock" = "checked" ] ; then
    [ -e /etc/rc.d/rc.numlock ] && chmod 755 /etc/rc.d/rc.numlock
    [ -x /usr/bin/numlockx ] && /usr/bin/numlockx on
    for t in 1 2 3 4 5 6 7 8 ; do
      setleds +num < /dev/tty$t > /dev/null
    done
  else
    [ -e /etc/rc.d/rc.numlock ] && chmod 644 /etc/rc.d/rc.numlock
    [ -x /usr/bin/numlockx ] && /usr/bin/numlockx off
    for t in 1 2 3 4 5 6 7 8 ; do
      setleds -num < /dev/tty$t > /dev/null
    done
  fi

  keymap="$(basename $pathKeymap)"

  # We need the keymap without ".map"
  key=${keymap%.map}

  # We convert keymap into XkbLayout  -- The fields are  keymap | XkbLayout | XkbOptions

  cat << "EOF" | grep "^$key|.*|.*" \
    | sed -e "s/^.*|\(.*\)|\(.*\)|\(.*\)/\1|\2|\3/" > $tmpDir/xkb
ANSI-dvorak|dvorak||
al|al||
am|am||
ar|ar||
azerty|fr||
az|az||
be-latin1|be||
bg-cp1251|bg||
bg-cp855|bg||
bg_bds-cp1251|bg||
bg_bds-utf8|bg||
bg_pho-cp1251|bg||
bg_pho-utf8|bg||
br-abnt2|br||
br-abnt|br||
br-latin1-abnt2|br||
br-latin1-us|br||
brdk|brdk||
by|by||
by|by||
cf|ca_enhanced||
croat|hr||
cz-cp1250|cz||
cz-lat2-prog|cz||
cz-lat2|cz||
cz-us-qwertz|cz_qwerty||
cz|cz||
de-latin1-nodeadkeys|de||
de-latin1|de||
de_CH-latin1|de_CH||
de|de||
dk-latin1|dk||
dk|dk||
dvorak-l|dvorak||
dvorak-r|dvorak||
dvorak|dvorak||
es-cp850|es||
es|es||
fi-latin1|fi-latin1||
fi-latin9|fi-latin9||
fi|fi||
fr-latin0|fr-latin0||
fr-latin1|fr-latin1||
fr-latin9|fr-latin9||
fr-pc|fr||
fr_CH-latin1|fr_CH||
fr_CH|fr_CH||
fr|fr||
gr-pc|us,el|grp:alt_shift_toggle|
gr|us,el|grp:alt_shift_toggle|
hu|hu||
il|us,il|grp:alt_shift_toggle|
il-heb|us,il-heb|grp:alt_shift_toggle|
il-phonetic|us,il-phonetic|grp:alt_shift_toggle|
is-latin1-us|us,is|grp:alt_shift_toggle|
is-latin1|is||
it-ibm|it||
it2|it||
it|it||
jp106|jp||
lt.baltic|lt_std||
lt.l4|lt_std||
lt|lt_std||
lt|lt||
lv|lv||
lv-latin7|lv||
mk-cp1251|mk||
mk-utf|mk||
mk0|mk||
mk|mk||
nl2|nl|
nl|nl||
nl|nl||
no-latin1|no||
no|no||
pl2|pl2||
pl|pl||
pt-latin1|pt||
pt-latin9|pt||
ro_win|ro_microsoft||
ru-cp1251|ru|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru-ms|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru-yawerty|ru||
ru1|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru2|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru3|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru4|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru_win|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
se-fi-ir209|se_FI||
se-fi-lat6|se_FI||
se-ir209|se_SE||
se-lat6|se_SE||
sg-latin1-lk450|sg||
sg-latin1|de_CH||
sg|de_CH||
sk-prog-qwerty|sk_qwerty||
sk-prog-qwertz|sk_qwerty||
sk-prog-qwertz|sk||
sk-qwerty|sk_qwerty||
sk-qwertz|sk_qwerty||
slovene|si||
sr-cy|sry||
sv-latin1|se||
syr|syr||
tel|tel||
th_pat|th_pat||
th_tis|th_tis||
th|th||
tj|tj||
tml|tml||
tr_f-latin5|tr_f||
tr_q-latin5|tr||
tralt|tr||
tralt|tr||
trq|tr||
ua-utf-ws|ua||
ua-utf|ua||
ua-ws|ua||
ua|ua||
ua|ua||
uk|gb||
us-acentos|us||
us|us||
uz|uz||
vn|vn||
wangbe2|fr||
wangbe|fr||
fr-dvorak-bepo|fr|grp:alt_shift_toggle|bepo
fr-dvorak-bepo-utf8|fr|grp:alt_shift_toggle|bepo
EOF

  xkbLayout="$(sed -e "s/^\(.*\)|.*|.*$/\1/" $tmpDir/xkb)"
  xkbOptions="terminate:ctrl_alt_bksp"
  specialXkbOptions="$(sed -e "s/^.*|\(.*\)|.*$/\1/" $tmpDir/xkb)"
  [ "${specialXkbOptions}" ] && xkbOptions="${xkbOptions},${specialXkbOptions}"
  xkbVariant="$(sed -e "s/^.*|.*|\(.*\)$/\1/" $tmpDir/xkb)"

  rm -f $tmpDir/xkb
  # Fall back to keymap if no xkb maping available
  if [ ! "$xkbLayout" ]; then
    xkbLayout="$key"
  fi

  /usr/bin/loadkeys $keymap 1>&2 2>/dev/null
  /usr/bin/setxkbmap -layout "$xkbLayout" -option "$xkbOptions" -variant "$xkbVariant" 1>&2 2>/dev/null

# Saving configs

  sed -i "s/\(^[ \t]*\/usr\/bin\/loadkeys\).*$/\1 $keymap/" /etc/rc.d/rc.keymap

cat << EOF > /etc/X11/xorg.conf.d/90-keyboard-layout.conf
Section "InputClass"
  Identifier "keyboard-all"
  MatchIsKeyboard "on"
  MatchDevicePath "/dev/input/event*"
  Driver "evdev"
  Option "XkbLayout" "$xkbLayout"
  Option "XkbVariant" "$xkbVariant"
  Option "XkbOptions" "$xkbOptions"
EndSection
EOF

fi

cd $backToHome

# end
