#!/usr/bin/env bash
# Installs the dvorak-qwerty keyboard layout (Dvorak, with QWERTY's [ ] { } - _ = + keys, and QWERTY
# letters while Ctrl or Meta is held) into /etc/xkb and adds it after your current KDE layouts. Turns
# on the XKB option custom:types for its key types, and sets Meta+Alt+K (Switch to Next Keyboard
# Layout) when that shortcut is empty. KWin only searches /etc/xkb if it existed when KWin started,
# so on the first install, log out and back in. Run as yourself, not with sudo: it asks for the
# password once. Safe to run again. KDE Plasma 6 on Wayland.
set -euo pipefail

here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
name=dvorak-qwerty
fail() { echo "🔴 $*"; echo "🔴 FAILED"; exit 1; }
[[ $EUID -ne 0 ]] || fail "run it as yourself, not root: it changes your KDE settings"
for f in "$name" custom-types evdev.xml; do [[ -f "$here/$f" ]] || fail "missing $here/$f (keep it next to this script)"; done

# 1. Compile check
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
mkdir "$tmp/symbols" "$tmp/types" && cp "$here/$name" "$tmp/symbols/" && cp "$here/custom-types" "$tmp/types/custom"
cat > "$tmp/km.xkb" <<EOF
xkb_keymap {
  xkb_keycodes { include "evdev+aliases(qwerty)" };
  xkb_types    { include "complete+custom" };
  xkb_compat   { include "complete" };
  xkb_symbols  { include "pc+us+$name:2+inet(evdev)" };
};
EOF
xkbcomp -w0 -I"$tmp" -xkb "$tmp/km.xkb" "$tmp/out.xkb" || fail "layout doesn't compile"
echo "🟢 Layout compiles"

# 2. KWin reads /etc/xkb/symbols and /etc/xkb/types; System Settings lists layouts from
#    /etc/xkb/rules/evdev.xml. types/custom is a shared name: don't overwrite someone else's.
if [[ -f /etc/xkb/types/custom ]] && ! grep -q DVQ_ALPHA /etc/xkb/types/custom; then
  fail "/etc/xkb/types/custom exists and isn't this layout's: merge custom-types into it by hand"
fi
sudo install -Dm644 "$here/$name" "/etc/xkb/symbols/$name"
sudo install -Dm644 "$here/custom-types" /etc/xkb/types/custom
sudo install -Dm644 "$here/evdev.xml" /etc/xkb/rules/evdev.xml
echo "🟢 Copied to /etc/xkb"

# 3. KDE settings in kxkbrc. --notify makes KWin reload, but only when a value changes.
kr() { kreadconfig6 --file kxkbrc --group Layout --key "$1"; }
kw() { kwriteconfig6 --notify --file kxkbrc --group Layout --key "$1" "$2"; }

# 3a. Option custom:types (loads types/custom). KWin only uses Options when ResetOldOptions is true;
#     otherwise it uses the system's (localectl), so start from those.
options="$(kr Options)"
[[ "$(kr ResetOldOptions)" == true ]] || options="$(localectl status | sed -n 's/^ *X11 Options: //p')"
if [[ ",$options," == *",custom:types,"* ]]; then
  echo "🟢 Option custom:types already on"
else
  options="${options:+$options,}custom:types"
  kw ResetOldOptions true
  kw Options "$options"
  echo "🟢 Options now: $options"
fi

# 3b. Add the layout after the current ones. With no LayoutList yet, KWin uses the system layout.
layouts="$(kr LayoutList)"; variants="$(kr VariantList)"
if [[ -z "$layouts" ]]; then
  layouts="$(localectl status | sed -n 's/^ *X11 Layout: //p')"
  variants="$(localectl status | sed -n 's/^ *X11 Variant: //p')"
  layouts="${layouts:-us}"
fi
if [[ ",$layouts," == *",$name,"* ]]; then
  echo "🟢 Already in your layouts: $layouts"
else
  IFS=, read -ra L <<< "$layouts"; IFS=, read -ra V <<< "$variants"; IFS=, read -ra N <<< "$(kr DisplayNames)"
  for i in "${!L[@]}"; do V[i]="${V[i]:-}"; N[i]="${N[i]:-}"; done
  L+=("$name"); V+=(""); N+=("dvq")
  kw Use true
  kw VariantList "$(IFS=,; echo "${V[*]}")"
  kw DisplayNames "$(IFS=,; echo "${N[*]}")"
  kw LayoutList "$(IFS=,; echo "${L[*]}")"
  echo "🟢 Layouts now: $(IFS=,; echo "${L[*]}")"
fi
for _ in 1 2 3 4 5; do
  sleep 1
  loaded="$(qdbus6 --literal org.kde.keyboard /Layouts org.kde.KeyboardLayouts.getLayoutsList)"
  [[ "$loaded" == *"\"$name\""* ]] && break
done
if [[ "$loaded" == *"\"$name\""* ]]; then
  echo "🟢 KWin has loaded it"
else
  # The layout compiled in step 1, so it's KWin's search paths: journalctl -b _COMM=kwin_wayland | grep XKB-338
  echo "🟠 KWin hasn't loaded it yet: it only searches /etc/xkb if that existed when KWin started. Log out and back in"
fi

# 4. Shortcut: kglobalaccel keys are a(ai), Meta+Alt+K = 0x10000000 + 0x08000000 + 0x4b
action=("KDE Keyboard Layout Switcher" "Switch to Next Keyboard Layout" "Keyboard Layout Switcher" "Switch to Next Keyboard Layout")
gacc=(busctl --user call org.kde.kglobalaccel /kglobalaccel org.kde.KGlobalAccel)
case "$("${gacc[@]}" shortcutKeys as 4 "${action[@]}")" in
  "a(ai) 0" | "a(ai) 1 4 0 0 0 0")
    "${gacc[@]}" setForeignShortcutKeys 'asa(ai)' 4 "${action[@]}" 1 4 402653259 0 0 0
    echo "🟢 Shortcut set: Meta+Alt+K" ;;
  *) echo "🟢 Layout shortcut already set, left as is" ;;
esac

echo "🟢 SUCCESS: switch layouts with Meta+Alt+K or the tray icon (dvq), after a log-out if KWin hasn't loaded it"
