#!/bin/sh

# /!\ ATTENTION : l’appel de ce script sans argument change immédiatement et
# radicalement la disposition du clavier.
# Ce n’est certainement pas une bonne idée si vous ne savez pas ce que vous
# faites ou si vous n’avez pas sauvegardé vos travaux en cours.

# beop
# Auteur : Laurent Dudouеt
# $Revision: 1.83 $
# $Date: 2022/09/08 04:59:51 $
# Ce script est fourni sans aucune garantie.
# Vous pouvez l’utiliser selon les termes de la licence GNU GPL version 2 ou
# ultérieure de la Free Software Foundation
# (http://www.gnu.org/licenses/licenses.html#GPL).

# Ce script charge immédiatement ou installe la disposition de clavier Béop
# (voir http://beop.free.fr/), suivant les options avec lesquelles il est
# appelé, sous X.org ou la console de GNU/Linux.
# Pour obtenir l’aide, appelez-le avec l’option -h
# Pour voir la disposition, appelez-le avec l’option -carte dans un terminal en
# UTF-8. Ça devrait l’afficher sous une forme plus lisible que ci-dessous et en
# tenant compte d’éventuelles options.

# Disposition Béop, version par défaut :
# ┏━━━━┱────┬────┬────┬────┬────┬────┰────┬────┬────┬────┬────┬────┲━━━━━━━━┓
# ┃Alt ┃ § →│ W ⇒│ « ¯│ » Ñ│ “ „│ ” Þ┃ Ù ˘│ Ç °│ – ′│ — ″│ µ ˙│ ‰ ®┃        ┃
# ┃Comp┃ # ʒ│ w ĳ│ - ‑│ ' ñ│ " ð│ ` þ┃ ù ŭ│ ç 8│ ( 9│ ) ,│ ¨ .│ % =┃   ⌫    ┃
# ┣━━━━┻━━┱─┴──┬─┴──┬─┴──┬─┴──┬─┴──┰─┸──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┺━━┳━━━━━┫
# ┃   ⇤   ┃ B ʼ│ É Æ│ O Œ│ P ˚│ È ẞ┃ ! ˇ│ V ±│ D ᵈ│ L ᵉ│ J ˝│ Z º│ × †┃     ┃
# ┃   ⇥   ┃ b |│ é æ│ o œ│ p &│ è ß┃ ˆ ¡│ v +│ d 4│ l 5│ j 6│ z 7│ ´ *┃     ┃
# ┣━━━━━━━┻┱───┴┬───┴┬───┴┬───┴┬───┸┰───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┺┓ ↲  ┃
# ┃ Verr.  ┃ A ≤│ U ≃│ E ¤│ I ≥│ ; /┃ C ©│ T –│ S ˢ│ R ʳ│ N ᵒ│ F ª│ ÷ ‡┃    ┃
# ┃ Maj.   ┃ a <│ u =│ e €│ i >│ , /┃ c @│ t -│ s 0│ r 1│ n 2│ f 3│ ` /┃    ┃
# ┣━━━━━┳━━┹─┬──┴─┬──┴─┬──┴─┯━─┴─┬──┸─┰──┴─┯━─┴─┬──┴─┬──┴─┬──┴─┲━━┷━━━━┻━━━━┫
# ┃     ┃ Ê  │ À ‐│ Y ≠│ X •│ : ·│ K ˜┃ ? ‘│ Q ˛│ G ¸│ H ,│ M ․┃            ┃
# ┃  ⇧  ┃ ê *│ à \│ y {│ x }│ . …│ k ~┃ ’ ¿│ q [│ g ]│ h ^│ m $┃     ⇧      ┃
# ┣━━━━━┻┳━━━┷━━┳━┷━━━━┷┱───┴────┴────┸────┴───┲┷━━━━┷━┳━━┷━━━┳┻━━━━━┳━━━━━━┫
# ┃      ┃      ┃       ┃ insécable  ins. fine ┃       ┃ WinD ┃ Menu ┃      ┃
# ┃ Ctrl ┃ Alt  ┃ AltGr ┃ Espace         _     ┃ AltGr ┃ Menu ┃ WinG ┃ Ctrl ┃
# ┗━━━━━━┻━━━━━━┻━━━━━━━┹──────────────────────┺━━━━━━━┻━━━━━━┻━━━━━━┻━━━━━━┛
# ┌────┐
# │ O Œ│  Maj. (⇧) + touche → O , AltGr + Maj. (⇧) + touche → Œ
# │ o œ│  touche seule      → o , AltGr + touche            → œ
# └────┘

# Ce script essaie autant que possible d’être en « shell portable », dans la
# mesure ou Perl n’est pas installé en standard sur les systèmes les plus
# hostiles et qu’un shell évolué n’est pas forcément disponible non plus, ou
# alors pas à un emplacement standard.
# Ça implique beaucoup de limitations : pas de tableaux, pas de fonctions de
# traitement de chaînes pratiques, pas de variables locales (/bin/sh
# d’OpenIndiana)…
# Ce script essaie aussi d’éviter au maximum les dépendances externes.
# Il a été mis au point sur plusieurs distributions GNU/Linux courantes (Arch,
# CentOS, Debian, Fedora, Ubuntu) et sur FreeBSD, OpenBSD et OpenIndiana.
# Cependant la dernière version n’a pas forcément été testée sur tous ces
# systèmes. Merci de prévenir si vous constatez une régresison ou si vous
# essayez sur un autre système (beop chez free point fr).


# Adaptations suivant le système
analyse_systeme() {
    # On détermine les répertoires concernés pour X.
    # Ils correspondent normalement à cette expression :
    # /usr{,/local}{,/X11R6,/X11R7)/{share,lib}/X11/xkb (qu’on évite d’utiliser
    # pour limiter les risques d’incompatibilité avec les shells les moins
    # évolués).
    as_fich_fr='' # variable utilisée pour savoir si on installe pour X
    for as_rep_local in '' '/local'; do
        for as_rep_X11R in '' '/X11R6' '/X11R7'; do
            for as_rep_share in 'share' 'lib'; do
                as_rep="$rep_install/usr$as_rep_local$as_rep_X11R/$as_rep_share/X11/xkb"
                if [ -d "$as_rep" ]; then
                    as_rep_xkb="$as_rep"
                    as_rep_symbols="$as_rep_xkb/symbols"
                    as_rep_rules="$as_rep_xkb/rules"
                    if [ -f "$as_rep_symbols/pc/fr" ]; then
                        as_fich_fr="$as_rep_symbols/pc/fr"
                    else
                        as_fich_fr="$as_rep_symbols/fr"
                    fi
                    break 3
                fi
            done
        done
    done

    # L’existence d’un fichier séparé pour la disposition fr latin9
    # permet de savoir si les dispositions sont installées séparément ou
    # comme variantes ; on agit en fonction.
    if [ -n "$as_fich_fr" ] && [ -f "${as_fich_fr}-latin9" ]; then
        as_fich_X="${as_fich_fr}-beop"
        as_fich_X_separe=true
    else
        as_fich_X="$as_fich_fr"
        as_fich_X_separe=false
    fi

    # Fichier pour tester l’existence des symboles
    # S’il est présent sur le système, on utilise l’include qui les définit,
    if [ -f /usr/include/X11/keysymdef.h ]; then
        as_symb_fich='/usr/include/X11/keysymdef.h'
    # sinon on se rabat sur le fichier de définition des claviers français (sur
    # un système relativement récent, il contient la disposition Bépo qui
    # utilise les caractères qu’on recherche ; sur un système ancien, il ne
    # contient rien d’intéressant, mais la plupart des symboles récents
    # n’existent pas (en tout cas dead_greek, postérieur à l’intégration de la
    # disposition Bépo).
    else
        as_symb_fich="$as_fich_fr"
    fi

    # Suivant l’existence ou non de certain symboles, on les utilise ou on passe
    # à une solution de repli.
    if [ -n "$as_symb_fich" ]; then
        if grep dead_greek $as_symb_fich > /dev/null 2>&1; then
            as_dead_greek='dead_greek'
        else
            as_dead_greek='mu'
        fi

        if grep dead_stroke $as_symb_fich > /dev/null 2>&1; then
            as_dead_stroke='dead_stroke'
        else
            as_dead_stroke='UFDD0'
        fi

        if grep dead_currency $as_symb_fich > /dev/null 2>&1; then
            as_dead_currency='dead_currency'
        else
            as_dead_currency='currency'
        fi

        if grep dead_belowcomma $as_symb_fich > /dev/null 2>&1; then
            as_dead_belowcomma='dead_belowcomma'
        else
            as_dead_belowcomma='UFDD3'
        fi
    fi

    # On détermine l’éventuel fichier de déclaration spécifique à Debian et ses
    # dérivées.
    as_fich_debian=''
    for as_nom_fich in keyboard-configuration.config console-setup.config; do
        as_fich="$rep_install/var/lib/dpkg/info/$as_nom_fich"
        if [ -f "$as_fich" ] && grep bepo "$as_fich" > /dev/null 2>&1; then
            as_fich_debian="$as_fich"
            break
        fi
    done
}


# Réglage des éventuelles couleurs d’affichage
couleurs() {
    co_couleurs="$1"

    # Si les couleurs ne sont pas prises en charge, on affiche en noir et blanc
    { $co_couleurs && [ -t 1 ] && { tput colors || tput Co ; } > /dev/null 2>&1; } || co_couleurs=false

    if $co_couleurs; then
        co_ecr_norm='\033[39m'
        co_fond_norm='\033[49m'
        case "$co_couleurs" in
            # Note : certains terminaux ne prennent pas en charge les codes de
            # couleurs claires (à partir de 90 pour l’écriture et 100 pour le fond),
            # on fixe donc auparavant une couleur de repli.
            # Fond blanc, écriture noire
            *fond_clair)
                if [ "$COLORTERM" = "truecolor" ]; then
                    co_ecr='\033[30;38;2;0;0;0m'
                    co_fond='\033[47;107;48;2;255;255;255m'
                    co_mort='\033[31;91;38;2;223;0;0m'
                    co_insec='\033[47;48;2;191;191;191m'
                    co_grise='\033[34;90;38;2;127;127;127m'
                else
                    co_ecr='\033[30m'
                    co_fond='\033[47;107m'
                    co_mort='\033[31m'
                    co_insec='\033[47m'
                    co_grise='\033[34;90m'
                fi
                ;;
            # Fond noir, écriture blanche
            *fond_sombre)
                if [ "$COLORTERM" = "truecolor" ]; then
                    co_ecr='\033[37;97;38;2;255;255;255m'
                    co_fond='\033[40;48;2;0;0;0m'
                    co_mort='\033[31;38;2;255;63;31m'
                    co_insec='\033[44;100;48;2;63;63;63m'
                    co_grise='\033[37;38;2;127;127;127m'
                else
                    co_ecr='\033[37;97m'
                    co_fond='\033[40m'
                    co_mort='\033[31;91m'
                    co_insec='\033[44;100m'
                    co_grise='\033[37m'
                fi
                ;;
            # Couleurs relativement passe-partout
            *)
                co_ecr="$co_ecr_norm"
                co_fond="$co_fond_norm"
                co_mort='\033[31;91m'
                co_insec='\033[44m'
                co_grise='\033[34m'
                ;;
        esac
        co_fmort="$co_ecr"
        co_finsec="$co_fond"
        co_fgrise="$co_ecr"
    else
        # Pas de couleurs
        co_ecr_norm=''
        co_fond_norm=''
        co_ecr=''
        co_fond=''
        co_mort=''
        co_fmort=''
        co_insec=''
        co_finsec=''
        co_grise=''
        co_fgrise=''
    fi
}


# Adaptation des caractères suivant la version et la variante de la disposition
version() {
    ve_version="$1"; ve_variante="$2"; ve_altgr_sur_win="$3"
    ve_guillemets_avec_espaces_norm="$4"; ve_guillemets_avec_espaces_typo="$5"
    ve_large="$6"; ve_couleurs="$7"; ve_prefixe="$8"

    $debug && echo "version '$1' '$2' '$3' '$4' '$5' '$6' '$7' '$8'" >&2

    couleurs "$ve_couleurs"

    # Selon l’option choisie, on met les guillemets français tels quels ou on
    # les remplace par des codes qui leur associeront les espaces insécables
    # normale et fine. Cela nécessite d’avoir les définitions suivantes dans
    # .XCompose :
    # <UFDE8> : "« "
    # <UFDE9> : " »"
    # <UFDEA> : "« "
    # <UFDEB> : " »"

    # ve_guillemets_avec_espaces_norm et _typo n’ont pas été forcément été
    # définies par la fonction appelante, mais si elles ne l’ont pas été, c’est
    # qu’elle n’a pas besoin des variables qui en dépendent.
    # Par contre, une fonction parente pourrait en avoir besoin. On évite donc
    # de les écraser au cas ou les appels ne seraient pas faits dans le « bon »
    # ordre.
    if [ -n "$ve_guillemets_avec_espaces_norm" ]; then
        if $ve_guillemets_avec_espaces_norm; then
            ve_guil_ouvr="UFDE8"
            ve_guil_ferm="UFDE9"
        else
            ve_guil_ouvr="guillemotleft"
            ve_guil_ferm="guillemotright"
        fi
    fi

    if [ -n "$ve_guillemets_avec_espaces_typo" ]; then
        if $ve_guillemets_avec_espaces_typo; then
            ve_guil_ouvr_typo="UFDEA"
            ve_guil_ferm_typo="UFDEB"
        else
            ve_guil_ouvr_typo="guillemotleft"
            ve_guil_ferm_typo="guillemotright"
        fi
    fi

    # On adapte suivant la version.
    case "$ve_version" in
        1.0)
            ve_AE01_a='ə'
            ve_AE01_a_symb='schwa'
            ve_AE01_a_symbc='U+0259'
            ve_AE02_a='ð'
            ve_AE02_a_symb='eth'
            ve_AE02_a_symbc="$ve_AE02_a_symb"
            ve_AE03_a='ĳ'
            ve_AE03_a_symb='U0133'
            ve_AE03_a_symbc='U+0133'
            ve_AE03_ma="${co_insec}‑${co_finsec}"
            ve_AE03_ma_symb='U2011'
            ve_AE03_ma_symbc='U+2011'
            ve_AE04_a='æ'
            ve_AE04_a_symb='ae'
            ve_AE04_a_symbc="+ae"
            ve_AE04_ma='Æ'
            ve_AE04_ma_symb='AE'
            ve_AE04_ma_symbc="+AE"
            ve_AE05_a='ñ'
            ve_AE05_a_symb='ntilde'
            ve_AE05_a_symbc="+ntilde"
            ve_AE05_ma='Ñ'
            ve_AE05_ma_symb='Ntilde'
            ve_AE05_ma_symbc="+Ntilde"
            # En couleurs, la couleur permettra de distinguer le point souscrit
            # et il sera plus lisible en gros.
            if $co_couleurs; then
                ve_AE07_ma="${co_mort}.${co_fmort}"
            else
                ve_AE07_ma='․'
            fi
            ve_AE07_ma_symb='dead_belowdot'
            ve_AE07_ma_symbc='U+0323'
            ve_AE12_ma='º'
            ve_AE12_ma_symb='masculine'
            ve_AE12_ma_symbc="$ve_AE12_ma_symb"

            ve_AD01_ma='¦'
            ve_AD01_ma_symb='brokenbar'
            ve_AD01_ma_symbc='U+00a6'
            ve_AD02_type='"FOUR_LEVEL_SEMIALPHABETIC"'
            ve_AD02_a="${co_mort}´${co_fmort}"
            ve_AD02_a_symb='dead_acute'
            ve_AD02_a_symbc="$ve_AD02_a_symb"
            ve_AD02_ma="${co_mort}˝${co_fmort}"
            ve_AD02_ma_symb='dead_doubleacute'
            ve_AD02_ma_symbc="$ve_AD02_ma_symb"
            ve_AD04_ma='„'
            ve_AD04_ma_symb='doublelowquotemark'
            ve_AD04_ma_symbc='U+201e'
            ve_AD05_type='"FOUR_LEVEL_SEMIALPHABETIC"'
            ve_AD05_a="${co_mort}\`${co_fmort}"
            ve_AD05_a_symb='dead_grave'
            ve_AD05_a_symbc="$ve_AD05_a_symb"
            ve_AD05_ma="${co_mort}˚${co_fmort}"
            ve_AD05_ma_symb='dead_abovering'
            ve_AD05_ma_symbc='degree'
            ve_AD08_ma='™'
            ve_AD08_ma_symb='trademark'
            ve_AD08_ma_symbc="$ve_AD08_ma_symb" # U+2122
            ve_AD09_ma="${co_mort}/${co_fmort}"
            ve_AD09_ma_symb="$as_dead_stroke"
            ve_AD09_ma_symbc='slash'
            ve_AD10_ma='ᵒ'
            ve_AD10_ma_symb='U1D52'
            ve_AD10_ma_symbc='U+1d52' # U+00ba
            ve_AD11_ma='ˢ'
            ve_AD11_ma_symb='U02E2'
            ve_AD11_ma_symbc='U+02e2'
            ve_AD12='*'
            ve_AD12_symb='asterisk'
            ve_AD12_symbc="$ve_AD12_symb"

            ve_AC05_ma="${co_mort}˘${co_fmort}"
            ve_AC05_ma_symb='dead_breve'
            ve_AC05_ma_symbc="$ve_AC05_ma_symb"
            ve_AC08_ma='ß'
            ve_AC08_ma_symb='ssharp'
            ve_AC08_ma_symbc="$ve_AC08_ma_symb"
            ve_AC09_ma='®'
            ve_AC09_ma_symb='registered'
            ve_AC09_ma_symbc="$ve_AC09_ma_symb"
            ve_AC10_ma='¬'
            ve_AC10_ma_symb='notsign'
            ve_AC10_ma_symbc="$ve_AC10_ma_symb"
            ve_BKSL='/'
            ve_BKSL_symb='slash'
            ve_BKSL_symbc="$ve_BKSL_symb"

            ve_AB10_ma="${co_mort}¯${co_fmort}"
            ve_AB10_ma_symb='dead_macron'
            ve_AB10_ma_symbc='macron'
            ;;
        *)
            ve_AE01_a='ʒ'
            ve_AE01_a_symb='ezh'
            ve_AE01_a_symbc="$ve_AE01_a_symb"
            ve_AE02_a='ĳ'
            ve_AE02_a_symb='U0133'
            ve_AE02_a_symbc='U+0133'
            ve_AE03_a="${co_insec}‑${co_finsec}"
            ve_AE03_a_symb='U2011'
            ve_AE03_a_symbc='U+2011'
            ve_AE03_ma="${co_mort}¯${co_fmort}"
            ve_AE03_ma_symb='dead_macron'
            ve_AE03_ma_symbc='macron'
            ve_AE04_a='ñ'
            ve_AE04_a_symb='ntilde'
            ve_AE04_a_symbc='+ntilde'
            ve_AE04_ma='Ñ'
            ve_AE04_ma_symb='Ntilde'
            ve_AE04_ma_symbc='+Ntilde'
            # Légère adaptation suivant la variante.
            case "$ve_variante" in
                prog)
                    ve_AE05_a='_'
                    ve_AE05_a_symb='underscore'
                    ve_AE05_a_symbc="$ve_AE05_a_symb"
                    ;;
                *)
                    ve_AE05_a='ð'
                    ve_AE05_a_symb='eth'
                    ve_AE05_a_symbc="$ve_AE05_a_symb"
                    ;;
            esac
            ve_AE05_ma='„'
            ve_AE05_ma_symb='doublelowquotemark'
            ve_AE05_ma_symbc='U+201e'
            ve_AE07_ma="${co_mort}˘${co_fmort}"
            ve_AE07_ma_symb='dead_breve'
            ve_AE07_ma_symbc="$ve_AE07_ma_symb"
            ve_AE12_ma='®'
            ve_AE12_ma_symb='registered'
            ve_AE12_ma_symbc="$ve_AE12_ma_symb"

            ve_AD01_ma='ʼ'
            ve_AD01_ma_symb='U02BC'
            ve_AD01_ma_symbc='U+02bc'
            ve_AD02_type='"FOUR_LEVEL_ALPHABETIC"    '
            ve_AD02_a='æ'
            ve_AD02_a_symb='ae'
            ve_AD02_a_symbc='+ae'
            ve_AD02_ma='Æ'
            ve_AD02_ma_symb='AE'
            ve_AD02_ma_symbc='+AE'
            ve_AD04_ma="${co_mort}˚${co_fmort}"
            ve_AD04_ma_symb='dead_abovering'
            ve_AD04_ma_symbc='degree'
            ve_AD05_type='"FOUR_LEVEL_ALPHABETIC"    '
            ve_AD05_a='ß'
            ve_AD05_a_symb='ssharp'
            ve_AD05_a_symbc="$ve_AD05_a_symb"
            ve_AD05_ma='ẞ'
            ve_AD05_ma_symb='U1E9E'
            ve_AD05_ma_symbc='U+1e9e'
            ve_AD08_ma='ᵈ'
            ve_AD08_ma_symb='U1D48'
            ve_AD08_ma_symbc='U+1d48'
            ve_AD09_ma='ᵉ'
            ve_AD09_ma_symb='U1D49'
            ve_AD09_ma_symbc='U+1d49'
            ve_AD10_ma="${co_mort}˝${co_fmort}"
            ve_AD10_ma_symb='dead_doubleacute'
            ve_AD10_ma_symbc="$ve_AD10_ma_symb"
            ve_AD11_ma='º'
            ve_AD11_ma_symb='masculine'
            ve_AD11_ma_symbc="$ve_AD11_ma_symb"
            ve_AD12="${co_mort}´${co_fmort}"
            ve_AD12_symb='dead_acute'
            ve_AD12_symbc="$ve_AD12_symb"

            ve_AC05_ma="${co_mort}/${co_fmort}"
            ve_AC05_ma_symb="$as_dead_stroke"
            ve_AC05_ma_symbc='slash'
            ve_AC08_ma='ˢ'
            ve_AC08_ma_symb='U02E2'
            ve_AC08_ma_symbc='U+02e2'
            ve_AC09_ma='ʳ'
            ve_AC09_ma_symb='U02B3'
            ve_AC09_ma_symbc='U+02b3'
            ve_AC10_ma='ᵒ'
            ve_AC10_ma_symb='U1D52'
            ve_AC10_ma_symbc='U+1d52'
            ve_BKSL="${co_mort}\`${co_fmort}"
            ve_BKSL_symb='dead_grave'
            ve_BKSL_symbc="$ve_BKSL_symb"

            # En couleurs, la couleur permettra de distinguer le point souscrit
            # et il sera plus lisible en gros.
            if $co_couleurs; then
                ve_AB10_ma="${co_mort}.${co_fmort}"
            else
                ve_AB10_ma='․'
            fi
            ve_AB10_ma_symb='dead_belowdot'
            ve_AB10_ma_symbc='U+0323'
            ;;
    esac

    # On adapte suivant la variante.
    case "$ve_variante" in
        prog)
            ve_AE01_ma='→'
            ve_AE01_ma_symb='U2192'
            ve_AE01_ma_symbc='U+2192'
            ve_AE02_ma='⇒'
            ve_AE02_ma_symb='U21D2'
            ve_AE02_ma_symbc='U+21d2'
            ve_AE03='-'
            ve_AE03_symb='minus'
            ve_AE03_symbc='minus'

            ve_AC01_ma='≤'
            ve_AC01_ma_symb='lessthanequal'
            ve_AC01_ma_symbc='U+2264'
            ve_AC04_ma='≥'
            ve_AC04_ma_symb='greaterthanequal'
            ve_AC04_ma_symbc='U+2265'

            ve_AB01_ma_carte="${co_insec}⍽${co_finsec}"
            ve_AB01_ma='(espace insécable fine)'
            ve_AB01_ma_symb='U202F'
            ve_AB01_ma_symbc='U+202f'

            ve_SPCE_m='␣'
            ve_SPCE_m_symb='space'
            ve_SPCE_m_symbc="$ve_SPCE_m_symb"
            ve_SPCE_ma='⍽'
            ve_SPCE_ma_symb='nobreakspace'
            ve_SPCE_ma_symbc="$ve_SPCE_ma_symb"
            if $ve_large; then
                ve_SPCE_m_carte="           ${co_insec}Espace insécable${co_finsec}"
                ve_SPCE_a_carte='_  '
            else
                ve_SPCE_m_carte="       ${co_insec}Esp. insécable${co_finsec}"
                ve_SPCE_a_carte='_ '
            fi
            ;;
        typo)
            [ -n "$ve_guil_ouvr_typo" ] && ve_guil_ouvr="$ve_guil_ouvr_typo"
            [ -n "$ve_guil_ferm_typo" ] && ve_guil_ferm="$ve_guil_ferm_typo"

            ve_AE01_ma='‹'
            ve_AE01_ma_symb='U2039'
            ve_AE01_ma_symbc='U+2039'
            ve_AE02_ma='›'
            ve_AE02_ma_symb='U203A'
            ve_AE02_ma_symbc='U+203a'
            ve_AE03='‐'
            ve_AE03_symb='U2010'
            ve_AE03_symbc='U+2010'

            ve_AC01_ma='⩽'
            ve_AC01_ma_symb='U2A7D'
            ve_AC01_ma_symbc='U+2a7d'
            ve_AC04_ma='⩾'
            ve_AC04_ma_symb='U2A7E'
            ve_AC04_ma_symbc='U+2a7e'

            case "$ve_version" in
                1.0)
                    ve_AB01_ma_carte='℃'
                    ve_AB01_ma='℃'
                    ve_AB01_ma_symb='U2103'
                    ve_AB01_ma_symbc='U+2103'
                    ;;
                *)
                    ve_AB01_ma_carte="${co_grise}‐${co_fgrise}"
                    ve_AB01_ma='‐'
                    ve_AB01_ma_symb='hyphen'
                    ve_AB01_ma_symbc="$ve_AB01_ma_symb"
                    ;;
            esac

            ve_SPCE_m='(espace insécable fine)'
            ve_SPCE_m_symb='U202F'
            ve_SPCE_m_symbc='U+202F'
            ve_SPCE_ma='⍽'
            ve_SPCE_ma_symb='nobreakspace'
            ve_SPCE_ma_symbc="$ve_SPCE_ma_symb"
            if $ve_large; then
                ve_SPCE_m_carte="${co_insec}inséc. fine${co_finsec}  ${co_insec}Esp. insécable${co_finsec}"
                ve_SPCE_a_carte=' _ '
            else
                ve_SPCE_m_carte="${co_insec}ins. fine${co_finsec}  ${co_insec}insécable${co_finsec} "
                ve_SPCE_a_carte=' _'
            fi
            ;;
        *)
            ve_AE01_ma='→'
            ve_AE01_ma_symb='U2192'
            ve_AE01_ma_symbc='U+2192'
            ve_AE02_ma='⇒'
            ve_AE02_ma_symb='U21D2'
            ve_AE02_ma_symbc='U+21d2'
            ve_AE03='-'
            ve_AE03_symb='minus'
            ve_AE03_symbc='minus'

            ve_AC01_ma='≤'
            ve_AC01_ma_symb='lessthanequal'
            ve_AC01_ma_symbc="U+2264"
            ve_AC04_ma='≥'
            ve_AC04_ma_symb='greaterthanequal'
            ve_AC04_ma_symbc='U+2265'

            case "$ve_version" in
                1.0)
                    ve_AB01_ma_carte='℃'
                    ve_AB01_ma='℃'
                    ve_AB01_ma_symb='U2103'
                    ve_AB01_ma_symbc='U+2103'
                    ;;
                *)
                    ve_AB01_ma_carte="${co_grise}‐${co_fgrise}"
                    ve_AB01_ma='‐'
                    ve_AB01_ma_symb='hyphen'
                    ve_AB01_ma_symbc="$ve_AB01_ma_symb"
                    ;;
            esac

            ve_SPCE_m='⍽'
            ve_SPCE_m_symb='nobreakspace'
            ve_SPCE_m_symbc="$ve_SPCE_m_symb"
            ve_SPCE_ma='(espace insécable fine)'
            ve_SPCE_ma_symb='U202F'
            ve_SPCE_ma_symbc="U+202F"
            if $ve_large; then
                ve_SPCE_m_carte="${co_insec}Esp. insécable${co_finsec}  ${co_insec}inséc. fine${co_finsec}"
                ve_SPCE_a_carte='  _'
            else
                ve_SPCE_m_carte="${co_insec}insécable${co_finsec}  ${co_insec}ins. fine${co_finsec} "
                ve_SPCE_a_carte=' _'
            fi
            ;;
    esac

    # On adapte suivant la position d’AltGr à gauche.
    if $ve_altgr_sur_win; then
        ve_t_incl_altgr='lwin ralt'
        ve_LWIN_def='"ONE_LEVEL"                , [ ISO_Level3_Shift ]';
        ve_LALT_def='"TWO_LEVEL"                , [ Alt_L, Meta_L ]';
        ve_Mod1='<LALT>';
        ve_Mod5='<LWIN>';
        ve_LWIN_symbc='AltGr';
        ve_LALT_symbc='Alt';
        ve_TLDE='   '
        ve_LWIN='AltGr'
        ve_LALT=' Alt '
    else
        ve_t_incl_altgr='alt'
        ve_LWIN_def='"TWO_LEVEL"                , [ Alt_L, Meta_L ]';
        ve_LALT_def='"ONE_LEVEL"                , [ ISO_Level3_Shift ]';
        ve_Mod1='<LWIN>, <TLDE>';
        ve_Mod5='<LALT>';
        ve_LWIN_symbc='Alt';
        ve_LALT_symbc='AltGr';
        ve_TLDE="${co_grise}Alt${co_fgrise}"
        if $ve_large; then
            ve_LWIN=' Alt '
        else
            ve_LWIN='Alt  '
        fi
        ve_LALT='AltGr'
    fi

    # On adapte suivant si on affiche la carte large ou pas.
    if $ve_large; then
        ve_AE00_carte="${co_mort}Comp.${co_fmort}"
    else
        ve_AE00_carte="${co_mort}Comp${co_fmort}"
    fi
}


# Affichage de la carte sur la sortie standard
affiche_carte() {
    ac_version="$1"; ac_variante="$2"; ac_altgr_sur_win="$3"
    ac_large="$4"; ac_couleurs="$5"; ac_prefixe="$6"

    $debug && echo "affiche_carte '$1' '$2' '$3' '$4' '$5' '$6'" >&2

    [ -z "$ac_couleurs" ] && ac_couleurs=true

    # Si printf n’est pas disponible, on se rabat sur la version de base,
    # affichée par cat.
    if printf '' > /dev/null 2>&1; then
        ac_cat=false
    else
        ac_cat=true
        ac_large=false
        ac_couleurs=false
    fi

    # On adapte suivant la version, la variante et les options.
    version "$ac_version" "$ac_variante" "$ac_altgr_sur_win" '' '' "$ac_large" "$ac_couleurs" "$ac_prefixe"

    # Avertissement pour la variante typographique
    if [ "$ac_variante" = "typo" ]; then
        if $ac_large; then
            cat <<AVERTISSEMENT_LARGE_TIRET
${ac_prefixe}ATTENTION : le tiret situé sur la même touche que « est le trait d’union Unicode.
${ac_prefixe}Il n’est pas utilisable avec une calculatrice, un tableur ou un langage informatique.
${ac_prefixe}Seul le moins ASCII situé en AltGr+t assure ces fonctions.
AVERTISSEMENT_LARGE_TIRET
        else
            cat <<AVERTISSEMENT_ETROIT_TIRET
${ac_prefixe}ATTENTION : le tiret situé sur la même touche que « est le trait d’union
${ac_prefixe}Unicode. Il n’est pas utilisable avec une calculatrice, un tableur ou un
${ac_prefixe}langage informatique. Seul le moins ASCII situé en AltGr+t assure ces
${ac_prefixe}fonctions.
AVERTISSEMENT_ETROIT_TIRET
        fi
    fi

    # Si un préfixe est défini, c’est qu’on produit la carte pour XKB.
    if [ -n "$ac_prefixe" ]; then
        ac_xkb=true
    else
        ac_xkb=false
    fi

    # Si on est en couleurs,
    if $co_couleurs; then
        # on efface chaque ligne pour s’assurer qu’elle prenne bien la couleur
        # de fond,
        ac_prefixe="\033[K${ac_prefixe}"
        # on affiche la légende sur la composition,
        ac_composition="${ac_prefixe} ${co_mort}ˆ${co_fmort}o → ô\n"
        # on rétablit les couleurs normales après l’affichage de la carte.
        ac_fin="${co_fond_norm}${co_ecr_norm}\033[K"
    # Sinon,
    else
        # la légende de composition serait illisible.
        ac_composition=''
        ac_fin=''
    fi

    # S’il s’agit d’afficher la carte en commentaire dans le fichier de XKB, on
    # utilise le format classique pour la légende.
    if $ac_xkb; then
        ac_legende=\
"${ac_prefixe}┌─────┐
${ac_prefixe}│ O Œ │   O = Maj.  , Œ = AltGr + Maj.
${ac_prefixe}│ o œ │   o = normal, œ = AltGr
${ac_prefixe}└─────┘
${ac_composition}"
    # Sinon, on utilise un format plus sympathique, en large s’il y a lieu…
    elif $ac_large; then
        ac_legende=\
"${ac_prefixe}┌─────┐
${ac_prefixe}│ O Œ │  Maj. (⇧) + touche → O , AltGr + Maj. (⇧) + touche → Œ 
${ac_prefixe}│ o œ │  touche seule      → o , AltGr + touche            → œ 
${ac_prefixe}└─────┘
${ac_composition}"
    # ou en étroit.
    else
        ac_legende=\
"${ac_prefixe}┌────┐
${ac_prefixe}│ O Œ│  Maj. (⇧) + touche → O , AltGr + Maj. (⇧) + touche → Œ 
${ac_prefixe}│ o œ│  touche seule      → o , AltGr + touche            → œ 
${ac_prefixe}└────┘
${ac_composition}"
    fi

    # S’il faut se rabattre sur cat, on affiche la carte de secours.
    if $ac_cat; then
        cat <<CARTE_BASIQUE
${ac_prefixe}┏━━━━┱────┬────┬────┬────┬────┬────┰────┬────┬────┬────┬────┬────┲━━━━━━━━┓
${ac_prefixe}┃${ve_TLDE} ┃ § ${ve_AE01_ma}│ W ${ve_AE02_ma}│ « ${ve_AE03_ma}│ » ${ve_AE04_ma}│ “ ${ve_AE05_ma}│ ” Þ┃ Ù ${ve_AE07_ma}│ Ç °│ – ′│ — ″│ µ ˙│ ‰ ${ve_AE12_ma}┃        ┃
${ac_prefixe}┃Comp┃ # ${ve_AE01_a}│ w ${ve_AE02_a}│ ${ve_AE03} ${ve_AE03_a}│ ' ${ve_AE04_a}│ " ${ve_AE05_a}│ \` þ┃ ù ŭ│ ç 8│ ( 9│ ) ,│ ¨ .│ % =┃   ⌫    ┃
${ac_prefixe}┣━━━━┻━━┱─┴──┬─┴──┬─┴──┬─┴──┬─┴──┰─┸──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┺━━┳━━━━━┫
${ac_prefixe}┃   ⇤   ┃ B ${ve_AD01_ma}│ É ${ve_AD02_ma}│ O Œ│ P ${ve_AD04_ma}│ È ${ve_AD05_ma}┃ ! ˇ│ V ±│ D ${ve_AD08_ma}│ L ${ve_AD09_ma}│ J ${ve_AD10_ma}│ Z ${ve_AD11_ma}│ × †┃     ┃
${ac_prefixe}┃   ⇥   ┃ b |│ é ${ve_AD02_a}│ o œ│ p &│ è ${ve_AD05_a}┃ ˆ ¡│ v +│ d 4│ l 5│ j 6│ z 7│ ${ve_AD12} *┃     ┃
${ac_prefixe}┣━━━━━━━┻┱───┴┬───┴┬───┴┬───┴┬───┸┰───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┺┓ ↲  ┃
${ac_prefixe}┃ Verr.  ┃ A ${ve_AC01_ma}│ U ≃│ E ¤│ I ${ve_AC04_ma}│ ; ${ve_AC05_ma}┃ C ©│ T –│ S ${ve_AC08_ma}│ R ${ve_AC09_ma}│ N ${ve_AC10_ma}│ F ª│ ÷ ‡┃    ┃
${ac_prefixe}┃ Maj.   ┃ a <│ u =│ e €│ i >│ , /┃ c @│ t -│ s 0│ r 1│ n 2│ f 3│ ${ve_BKSL} /┃    ┃
${ac_prefixe}┣━━━━━┳━━┹─┬──┴─┬──┴─┬──┴─┯━─┴─┬──┸─┰──┴─┯━─┴─┬──┴─┬──┴─┬──┴─┲━━┷━━━━┻━━━━┫
${ac_prefixe}┃     ┃ Ê  │ À ${ve_AB01_ma_carte}│ Y ≠│ X •│ : ·│ K ˜┃ ? ‘│ Q ˛│ G ¸│ H ,│ M ${ve_AB10_ma}┃            ┃
${ac_prefixe}┃  ⇧  ┃ ê *│ à \\│ y {│ x }│ . …│ k ~┃ ’ ¿│ q [│ g ]│ h ^│ m \$┃     ⇧      ┃
${ac_prefixe}┣━━━━━┻┳━━━┷━━┳━┷━━━━┷┱───┴────┴────┸────┴───┲┷━━━━┷━┳━━┷━━━┳┻━━━━━┳━━━━━━┫
${ac_prefixe}┃      ┃      ┃       ┃ ${ve_SPCE_m_carte}┃       ┃ WinD ┃ Menu ┃      ┃
${ac_prefixe}┃ Ctrl ┃ ${ve_LWIN}┃ ${ve_LALT} ┃ Espace        ${ve_SPCE_a_carte}     ┃ AltGr ┃ Menu ┃ WinG ┃ Ctrl ┃
${ac_prefixe}┗━━━━━━┻━━━━━━┻━━━━━━━┹──────────────────────┺━━━━━━━┻━━━━━━┻━━━━━━┻━━━━━━┛
${ac_legende}
CARTE_BASIQUE

    # Si la carte choisie est la large, on l’affiche.
    elif $ac_large; then

        printf \
"${co_fond}${co_ecr}${ac_prefixe}┏━━━━━┱─────┬─────┬─────┬─────┬─────┬─────┰─────┬─────┬─────┬─────┬─────┬─────┲━━━━━━━━━┓
${ac_prefixe}┃ ${ve_TLDE} ┃ § ${ve_AE01_ma} │ W ${ve_AE02_ma} │ « ${ve_AE03_ma} │ » ${ve_AE04_ma} │ “ ${ve_AE05_ma} │ ” Þ ┃ Ù ${ve_AE07_ma} │ Ç ° │ – ′ │ — ″ │ ${co_mort}µ${co_fmort} "${co_mort}˙${co_fmort}" │ ‰ ${ve_AE12_ma} ┃         ┃
${ac_prefixe}┃${ve_AE00_carte}┃ # ${ve_AE01_a} │ w ${ve_AE02_a} │ ${ve_AE03} ${ve_AE03_a} │ ' ${ve_AE04_a} │ \" ${ve_AE05_a} │ \` þ ┃ ù ŭ │ ç 8 │ ( 9 │ ) , │ ${co_mort}¨${co_fmort} . │ %% = ┃    ⌫    ┃
${ac_prefixe}┣━━━━━┻━━┱──┴──┬──┴──┬──┴──┬──┴──┬──┴──┰──┸──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┺━━┳━━━━━━┫
${ac_prefixe}┃   ⇤    ┃ B ${ve_AD01_ma} │ É ${ve_AD02_ma} │ O Œ │ P ${ve_AD04_ma} │ È ${ve_AD05_ma} ┃ ! ${co_mort}ˇ${co_fmort} │ V ± │ D ${ve_AD08_ma} │ L ${ve_AD09_ma} │ J ${ve_AD10_ma} │ Z ${ve_AD11_ma} │ × † ┃      ┃
${ac_prefixe}┃   ⇥    ┃ b | │ é ${ve_AD02_a} │ o œ │ p & │ è ${ve_AD05_a} ┃ ${co_mort}ˆ${co_fmort} ¡ │ v + │ d 4 │ l 5 │ j 6 │ z 7 │ ${ve_AD12} * ┃      ┃
${ac_prefixe}┣━━━━━━━━┻┱────┴┬────┴┬────┴┬────┴┬────┸┰────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┺┓  ↲  ┃
${ac_prefixe}┃ Verr.   ┃ A ${ve_AC01_ma} │ U ≃ │ E ${co_mort}¤${co_fmort} │ I ${ve_AC04_ma} │ ; ${ve_AC05_ma} ┃ C © │ T – │ S ${ve_AC08_ma} │ R ${ve_AC09_ma} │ N ${ve_AC10_ma} │ F ª │ ÷ ‡ ┃     ┃
${ac_prefixe}┃ Maj.    ┃ a < │ u = │ e € │ i > │ , / ┃ c @ │ t - │ s 0 │ r 1 │ n 2 │ f 3 │ ${ve_BKSL} / ┃     ┃
${ac_prefixe}┣━━━━━━┳━━┹──┬──┴──┬──┴──┬──┴─╼┯╾─┴──┬──┸──┰──┴─╼┯╾─┴──┬──┴──┬──┴──┬──┴──┲━━┷━━━━━┻━━━━━┫
${ac_prefixe}┃      ┃ Ê   │ À ${ve_AB01_ma_carte} │ Y ≠ │ X • │ : · │ K ${co_mort}˜${co_fmort} ┃ ? ‘ │ Q ${co_mort}˛${co_fmort} │ G ${co_mort}¸${co_fmort} │ H ${co_mort},${co_fmort} │ M ${ve_AB10_ma} ┃              ┃
${ac_prefixe}┃  ⇧   ┃ ê * │ à \\\\ │ y { │ x } │ . … │ k ~ ┃ ’ ¿ │ q [ │ g ] │ h ^ │ m \$ ┃       ⇧      ┃
${ac_prefixe}┣━━━━━━┻━┳━━━┷━━━┳━┷━━━━━╅─────┴─────┴─────┸─────┴─────╆━━━━━┷━┳━━━┷━━━┳━┻━━━━━┳━━━━━━━━┫
${ac_prefixe}┃        ┃       ┃       ┃ ${ve_SPCE_m_carte} ┃       ┃ WinD  ┃ Menu  ┃        ┃
${ac_prefixe}┃  Ctrl  ┃ ${ve_LWIN} ┃ ${ve_LALT} ┃ Espace             ${ve_SPCE_a_carte}      ┃ AltGr ┃ Menu  ┃ WinG  ┃  Ctrl  ┃
${ac_prefixe}┗━━━━━━━━┻━━━━━━━┻━━━━━━━┹─────────────────────────────┺━━━━━━━┻━━━━━━━┻━━━━━━━┻━━━━━━━━┛
${ac_legende}${ac_fin}"

    else
        # Sinon, on affiche la carte étroite (compatible avec un terminal en 80×25).
        printf \
"${co_fond}${co_ecr}${ac_prefixe}┏━━━━┱────┬────┬────┬────┬────┬────┰────┬────┬────┬────┬────┬────┲━━━━━━━━┓
${ac_prefixe}┃${ve_TLDE} ┃ § ${ve_AE01_ma}│ W ${ve_AE02_ma}│ « ${ve_AE03_ma}│ » ${ve_AE04_ma}│ “ ${ve_AE05_ma}│ ” Þ┃ Ù ${ve_AE07_ma}│ Ç °│ – ′│ — ″│ ${co_mort}µ${co_fmort} "${co_mort}˙${co_fmort}"│ ‰ ${ve_AE12_ma}┃        ┃
${ac_prefixe}┃${ve_AE00_carte}┃ # ${ve_AE01_a}│ w ${ve_AE02_a}│ ${ve_AE03} ${ve_AE03_a}│ ' ${ve_AE04_a}│ \" ${ve_AE05_a}│ \` þ┃ ù ŭ│ ç 8│ ( 9│ ) ,│ ${co_mort}¨${co_fmort} .│ %% =┃   ⌫    ┃
${ac_prefixe}┣━━━━┻━━┱─┴──┬─┴──┬─┴──┬─┴──┬─┴──┰─┸──┬─┴──┬─┴──┬─┴──┬─┴──┬─┴──┬─┺━━┳━━━━━┫
${ac_prefixe}┃   ⇤   ┃ B ${ve_AD01_ma}│ É ${ve_AD02_ma}│ O Œ│ P ${ve_AD04_ma}│ È ${ve_AD05_ma}┃ ! ${co_mort}ˇ${co_fmort}│ V ±│ D ${ve_AD08_ma}│ L ${ve_AD09_ma}│ J ${ve_AD10_ma}│ Z ${ve_AD11_ma}│ × †┃     ┃
${ac_prefixe}┃   ⇥   ┃ b |│ é ${ve_AD02_a}│ o œ│ p &│ è ${ve_AD05_a}┃ ${co_mort}ˆ${co_fmort} ¡│ v +│ d 4│ l 5│ j 6│ z 7│ ${ve_AD12} *┃     ┃
${ac_prefixe}┣━━━━━━━┻┱───┴┬───┴┬───┴┬───┴┬───┸┰───┴┬───┴┬───┴┬───┴┬───┴┬───┴┬───┺┓ ↲  ┃
${ac_prefixe}┃ Verr.  ┃ A ${ve_AC01_ma}│ U ≃│ E ${co_mort}¤${co_fmort}│ I ${ve_AC04_ma}│ ; ${ve_AC05_ma}┃ C ©│ T –│ S ${ve_AC08_ma}│ R ${ve_AC09_ma}│ N ${ve_AC10_ma}│ F ª│ ÷ ‡┃    ┃
${ac_prefixe}┃ Maj.   ┃ a <│ u =│ e €│ i >│ , /┃ c @│ t -│ s 0│ r 1│ n 2│ f 3│ ${ve_BKSL} /┃    ┃
${ac_prefixe}┣━━━━━┳━━┹─┬──┴─┬──┴─┬──┴─┯━─┴─┬──┸─┰──┴─┯━─┴─┬──┴─┬──┴─┬──┴─┲━━┷━━━━┻━━━━┫
${ac_prefixe}┃     ┃ Ê  │ À ${ve_AB01_ma_carte}│ Y ≠│ X •│ : ·│ K ${co_mort}˜${co_fmort}┃ ? ‘│ Q ${co_mort}˛${co_fmort}│ G ${co_mort}¸${co_fmort}│ H ${co_mort},${co_fmort}│ M ${ve_AB10_ma}┃            ┃
${ac_prefixe}┃  ⇧  ┃ ê *│ à \\\\│ y {│ x }│ . …│ k ~┃ ’ ¿│ q [│ g ]│ h ^│ m \$┃     ⇧      ┃
${ac_prefixe}┣━━━━━┻┳━━━┷━━┳━┷━━━━┷┱───┴────┴────┸────┴───┲┷━━━━┷━┳━━┷━━━┳┻━━━━━┳━━━━━━┫
${ac_prefixe}┃      ┃      ┃       ┃ ${ve_SPCE_m_carte}┃       ┃ WinD ┃ Menu ┃      ┃
${ac_prefixe}┃ Ctrl ┃ ${ve_LWIN}┃ ${ve_LALT} ┃ Espace        ${ve_SPCE_a_carte}     ┃ AltGr ┃ Menu ┃ WinG ┃ Ctrl ┃
${ac_prefixe}┗━━━━━━┻━━━━━━┻━━━━━━━┹──────────────────────┺━━━━━━━┻━━━━━━┻━━━━━━┻━━━━━━┛
${ac_legende}${ac_fin}"

    fi

    # Valeur de retour OK
    return 0
}


# Affichage de l’usage
usage() {
    us_version="$1"; us_variante="$2"; us_altgr_sur_win="$3"; us_large="$4"
    us_couleurs="$5"

    cat <<'DEBUT_USAGE'
Disposition de clavier Béop
http://beop.free.fr/

DEBUT_USAGE
    affiche_carte "$us_version" "$us_variante" "$us_altgr_sur_win" "$us_large" "$us_couleurs"
    cat <<'FIN_USAGE'

La disposition Béop dérive de la disposition Bépo (voir http://bepo.fr/).
Tout comme elle, cette disposition est placée sous double licence GFDL et
CC-BY-SA.
Ce script en tant que tel est fourni sans aucune garantie et placé sous la
licence GPL version 2 ou ultérieure.

Il permet de changer dynamiquement la disposition du clavier sous X.org depuis
la session de l’utilisateur ou sous la console texte Linux.
Depuis le compte root ou avec sudo, il permet d’installer la disposition sur le
système.

Sans arguments,
– s’il est lancé sous le nom "azerty" ou "auei", il rétablit la disposition
  Azerty.
– s’il se se termine par _switch ou contient _switch_, il bascule entre les
  dispositions Azerty et Béop.
– s’il contient _install(_*), il installe la disposition Béop sur le système.
Par défaut, il charge la disposition Béop (s’il contient _1.0(_*) la version
1.0, sinon la version 1.1 ; s’il contient _prog(_*), la variante programmation ;
s’il contient _typo(_*), la variante typographie).

Il est conseillé de créer des liens symboliques dessus nommés qsdf et auei,
afin de pouvoir basculer entre les dispositions Béop et Azerty simplement en
entrant la commande formée par les touches de la position de repos de la main
gauche.

Ce script supporte les arguments suivants (prioritaires sur le nom) :
-h  ou --help        : affichage de cette aide
--carte              : affichage de la carte de la disposition (en couleur si
                       possible)
-a  ou --azerty      : passage en Azerty
-b  ou --beop        : passage en Béop (action par défaut)
-1.0                 : version 1.0 de la disposition
-1.1                 : version 1.1 (par défaut)
-pr ou --prog        : variante destinée à la programmation (en mode chargement
                       immédiat ; en mode installation, les deux versions sont
                       systématiquement installées)
-ty ou --typo        : variante pour une meilleure typographie (mais moins bien
                       supportée par certains logiciels)
-s  ou --switch      : passage en Béop si l’on est en Azerty et vice-versa
--installe           : installation de la disposition Béop sur le système
--installerep rep    : installation sur un système monté sur le répertoire rep
--desinstalle        : désinstallation de la disposition Béop du système (par
                       restauration des fichiers d’origine)
                       ATTENTION : si vous avez modifié des fichiers où la
                       disposition Béop a été installée ou déclarée, vos
                       modifications seront perdues !
--desinstallerep rep : désinstallation d’un système monté sur le répertoire rep
--reinstalle         : désinstallation puis réinstallation de la disposition
                       Béop sur le système
--reinstallerep rep  : réinstallation sur un système monté sur le répertoire rep

Prérequis : bash ou un autre shell POSIX, grep -E ou egrep, et
– pour X.org : xkbcomp, setxkbmap, awk (pour l’installation),
– pour la console, loadkeys et dumpkeys.
FIN_USAGE
}


# Fonctions de traitement de chaînes en shell POSIX
# Permettent d’éviter de lancer des commandes externes pour s’affranchir des
# dépendances.


# Test d’inclusion d’une chaîne dans une autre
chaine_incluse() {
    # Paramètres : 'sous-chaîne' 'chaîne'
    # Utiliser une commande interne pour le test évite de plomber le temps
    # d’exécution en cas d’appel de la fonction dans une boucle.
    case "$2" in
        *$1*)
            return 0
            ;;
        *)
            return 1
            ;;
    esac
}


# Remplacement d’une sous-chaîne par une nouvelle
remplace_chaine() {
    # Paramètres : nom_variable_chaine 'ancienne sous-chaîne' 'nouvelle'
    #local __rc_chaine

    # On déréférence la chaîne
    eval __rc_chaine="\"\$$1\""

    # Si la chaîne n’est pas incluse, on retourne faux (important pour la
    # fonction de remplacement multiple).
    chaine_incluse "$2" "$__rc_chaine" || return 1

    # Remplacement de la première occurrence avec les moyens du bord en shell
    # POSIX.
    __rc_chaine="${__rc_chaine%%$2*}$3${__rc_chaine#*$2}"
    eval $1="'$__rc_chaine'"

    # On récupère la variable interne (certains shells ne permettent pas les
    # variables locales).
    unset __rc_chaine

    # On retourne vrai explicitement (important pour la fonction de remplacement
    # multiple).
    return 0
}


# Remplacement multiple d’une sous-chaîne par une nouvelle
# Fonction à usage interne uniquement : si l’ancienne sous-chaîne était
# incluse dans la nouvelle, la fonction bouclerait !
__remplace_multiple_chaine() {
    # Paramètres : nom_variable_chaine 'ancienne sous-chaîne' 'nouvelle'

    # On remplace la sous-chaîne tant qu’on peut.
    while remplace_chaine "$1" "$2" "$3"; do
        true
    done
}


# Remplacement multiple d’une sous-chaîne par une nouvelle
remplace_multiple_chaine() {
    # Paramètres : nom_variable_chaine 'ancienne sous-chaîne' 'nouvelle'
    # Si l’ancienne chaîne est incluse dans la nouvelle, c’est problématique.
    if chaine_incluse "$2" "$3"; then
        # On utilise une chaîne intermédiaire improbable pour éviter de boucler,
        # après avoir vérifié que l’ancienne sous-chaîne n’y est pas incluse.
        if chaine_incluse "$2" '%w_7Z.y/U^'; then
            # Sinon, on en utilise une autre sans caractère commun.
            __remplace_multiple_chaine "$1" "$2" '6K=Dz,<+Y@'
            __remplace_multiple_chaine "$1" '6K=Dz,<+Y@' "$3"
        else
            __remplace_multiple_chaine "$1" "$2" '%w_7Z.y/U^'
            __remplace_multiple_chaine "$1" '%w_7Z.y/U^' "$3"
        fi
    else
        # Dans le cas normal, on fait le remplacement directement.
        __remplace_multiple_chaine "$1" "$2" "$3"
    fi
}


# Ajout de la disposition Béop à un fichier (attendu en paramètre)
cat_beop() {
    cb_nom_fich="$1"; cb_version="$2"; cb_variante="$3"; cb_altgr_sur_win="$4"
    cb_mode_install="$5"; cb_mode_principale="$6"
    # Il sera utile par la suite de pouvoir distinguer si la fonction a été
    # appelée pour un chargement à la volée de la disposition ou pour son
    # installation, et si elle est installée comme variante ou disposition
    # principale.
    cb_guillemets_avec_espaces_norm="$7"; cb_guillemets_avec_espaces_typo="$8"

    $debug && echo "cat_beop '$1' '$2' '$3' '$4' '$5' '$6' '$7' '$8'" >&2

    # On ajoute la définition de la disposition Béop au fichier passé en paramètre.

    # Prise en charge du mode installation
    if $cb_mode_install; then

        # En mode installation, on installe systématiquement les trois versions,
        # on ne modifie pas celle de base.
        cb_variante="norm"

        # On ajoute le commentaire
        cat >> "$cb_nom_fich" <<COMMENT_BEOP
// Béop
// Ergonomic layout derived from Bépo
COMMENT_BEOP
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret

        affiche_carte "$cb_version" "norm" "$cb_altgr_sur_win" true false '// ' >> "$cb_nom_fich"
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret

        # Si chaque disposition est installée comme disposition à part entière
        # (anciennes versions de X), la disposition est celle par défaut.
        if $cb_mode_principale; then
            cb_default='default '
        else
            cb_default=''
        fi

        # En mode installation, la définition se présente comme une redéfinition
        # partielle par rapport à la définition basique du clavier.
        cat >> "$cb_nom_fich" <<DISPO_1
partial ${cb_default}alphanumeric_keys modifier_keys
DISPO_1
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # Écriture du reste de l’entête.
    cat >> "$cb_nom_fich" <<DISPO_2
xkb_symbols "beop" {

DISPO_2
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # En chargement dynamique, il n’y a pas de définition de base du clavier, on
    # en inclut donc une.
    if ! $cb_mode_install; then
        if setxkbmap -print | grep 'xkb_symbols.*pc/pc' > /dev/null 2>&1; then
            cb_include_base='pc/pc(pc105)'
        else
            cb_include_base='pc(pc105)'
        fi
        cat >> "$cb_nom_fich" <<DISPO_3
    include "$cb_include_base"
DISPO_3
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret

        # Si les touches multimédia étaient prise en charge, on les inclut.
        cb_inet=`setxkbmap -print | grep 'xkb_symbols.*inet' 2> /dev/null`
        if [ -n "$cb_inet" ]; then
            cb_inet="inet(${cb_inet#*inet(}"
            cb_inet="${cb_inet%%)*})"
            cat >> "$cb_nom_fich" <<DISPO_4
    include "$cb_inet"
DISPO_4
            # Si l’écriture a échoué, on retourne une erreur.
            cb_val_ret=$?
            [ $cb_val_ret -ne 0 ] && return $cb_val_ret
        fi

    fi

    # Adaptation à la version, la variante et les options
    version "$cb_version" "$cb_variante" "$cb_altgr_sur_win" "$cb_guillemets_avec_espaces_norm" "$cb_guillemets_avec_espaces_typo" true false '// '

    # On ajoute les includes pour les touches Alt(Gr) symétriques s’il existe
    # (par sécurité la disposition définit de toute façon les modificateurs
    #  elle-même).
    for incl in $ve_t_incl_altgr; do
        if $egrep "xkb_symbols +\"${incl}_switch\"" "$as_rep_symbols/level3" > /dev/null 2>&1; then
            cat >> "$cb_nom_fich" <<DISPO_5
    include "level3(${incl}_switch)"
DISPO_5
            # Si l’écriture a échoué, on retourne une erreur.
            cb_val_ret=$?
            [ $cb_val_ret -ne 0 ] && return $cb_val_ret
        fi
    done

    # Avec certaines versions de X.org relativement récentes, l’include suivant
    # fait échouer le chargement dynamique de la disposition avec xkbcomp, mais
    # ne semble pas causer de problème pour une disposition installée.
    if $cb_mode_install && $egrep 'xkb_symbols +"oss"' "$as_rep_symbols/keypad" > /dev/null 2>&1; then
        cat >> "$cb_nom_fich" <<DISPO_6
    include "keypad(oss)"
DISPO_6
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # On ajoute le gros de la définition de la disposition.
    cat >> "$cb_nom_fich" <<DISPO_7

    name[Group1]= "French (Beop, ergonomic, derived from Bepo)";

    key <TLDE> { repeat = no, type = "ONE_LEVEL"   , [ Multi_key ] }; // Compose
    key <AE01> { type = "FOUR_LEVEL"               , [ numbersign, section, $ve_AE01_a_symb, $ve_AE01_ma_symb ] }; // # § $ve_AE01_a $ve_AE01_ma
    key <AE02> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ w, W, $ve_AE02_a_symb, $ve_AE02_ma_symb ] }; // w W $ve_AE02_a $ve_AE02_ma
    key <AE03> { type = "FOUR_LEVEL"               , [ $ve_AE03_symb, $ve_guil_ouvr, $ve_AE03_a_symb, $ve_AE03_ma_symb ] }; // ${ve_AE03} « $ve_AE03_a $ve_AE03_ma
    key <AE04> { type = "FOUR_LEVEL"               , [ apostrophe, $ve_guil_ferm, $ve_AE04_a_symb, $ve_AE04_ma_symb ] }; // ' » $ve_AE04_a $ve_AE04_ma
    key <AE05> { type = "FOUR_LEVEL"               , [ quotedbl , leftdoublequotemark, $ve_AE05_a_symb, $ve_AE05_ma_symb ] }; // " “ $ve_AE05_a $ve_AE05_ma
    key <AE06> { type = "FOUR_LEVEL"               , [ grave, rightdoublequotemark, thorn, THORN ] }; // \` ” þ Þ
    key <AE07> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ ugrave, Ugrave, ubreve, $ve_AE07_ma_symb ] }; // ù Ù ŭ $ve_AE07_ma
    key <AE08> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ ccedilla, Ccedilla, 8, degree ] }; // ç Ç 8 °
    key <AE09> { type = "FOUR_LEVEL"               , [ parenleft, endash, 9, minutes ] }; // ( – 9 ′
    key <AE10> { type = "FOUR_LEVEL"               , [ parenright, emdash, comma, seconds ] }; // ) — , ″
    key <AE11> { type = "FOUR_LEVEL"               , [ dead_diaeresis, $as_dead_greek, period, dead_abovedot ] }; // ¨ µ . ˙
    key <AE12> { type = "FOUR_LEVEL"               , [ percent, U2030, equal, $ve_AE12_ma_symb ] }; // % ‰ = $ve_AE12_ma

    key <AD01> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ b, B, bar, $ve_AD01_ma_symb ] }; // b B | $ve_AD01_ma
    key <AD02> { type = $ve_AD02_type, [ eacute, Eacute, $ve_AD02_a_symb, $ve_AD02_ma_symb ] }; // é É $ve_AD02_a $ve_AD02_ma
    key <AD03> { type = "FOUR_LEVEL_ALPHABETIC"    , [ o, O, oe, OE ] }; // o O œ Œ
    key <AD04> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ p, P, ampersand, $ve_AD04_ma_symb ] }; // p P & $ve_AD04_ma
    key <AD05> { type = $ve_AD05_type, [ egrave, Egrave, $ve_AD05_a_symb, $ve_AD05_ma_symb ] }; // è È $ve_AD05_a $ve_AD05_ma
    key <AD06> { type = "FOUR_LEVEL"               , [ dead_circumflex, exclam, exclamdown, dead_caron ] }; // ^ ! ¡ ˇ
    key <AD07> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ v, V, plus, plusminus ] }; // v V + ±
    key <AD08> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ d, D, 4, $ve_AD08_ma_symb ] }; // d D 4 $ve_AD08_ma
    key <AD09> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ l, L, 5, $ve_AD09_ma_symb ] }; // l L 5 $ve_AD09_ma
    key <AD10> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ j, J, 6, $ve_AD10_ma_symb ] }; // j J 6 $ve_AD10_ma
    key <AD11> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ z, Z, 7, $ve_AD11_ma_symb ] }; // z Z 7 $ve_AD11_ma
    key <AD12> { type = "FOUR_LEVEL"               , [ $ve_AD12_symb, multiply, asterisk, dagger ] }; // $ve_AD12 × * †

    key <AC01> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ a, A, less, $ve_AC01_ma_symb ] }; // a A < $ve_AC01_ma
    key <AC02> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ u, U, equal, U2243 ] }; // u U = ≃
    key <AC03> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ e, E, EuroSign, $as_dead_currency ] }; // e E € ¤
    key <AC04> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ i, I, greater, $ve_AC04_ma_symb ] }; // i I > $ve_AC04_ma
    key <AC05> { type = "FOUR_LEVEL"               , [ comma, semicolon, slash, $ve_AC05_ma_symb ] }; // , ; / $ve_AC05_ma
    key <AC06> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ c, C, at, copyright ] }; // c C @ ©
    key <AC07> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ t, T, minus, U2212 ] }; // t T - −
    key <AC08> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ s, S, 0, $ve_AC08_ma_symb ] }; // s S 0 $ve_AC08_ma
    key <AC09> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ r, R, 1, $ve_AC09_ma_symb ] }; // r R 1 $ve_AC09_ma
    key <AC10> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ n, N, 2, $ve_AC10_ma_symb ] }; // n N 2 $ve_AC10_ma
    key <AC11> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ f, F, 3, ordfeminine ] }; // f F 3 ª
    key <BKSL> { type = "FOUR_LEVEL"               , [ $ve_BKSL_symb, division, slash, doubledagger ] }; // $ve_BKSL ÷ / ‡

    key <LSGT> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ ecircumflex, Ecircumflex, asterisk, U262D ] }; // ê Ê *
    key <AB01> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ agrave, Agrave, backslash, $ve_AB01_ma_symb ] }; // à À \\ $ve_AB01_ma
    key <AB02> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ y, Y, braceleft, notequal ] }; // y Y { ≠
    key <AB03> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ x, X, braceright, U2022 ] }; // x X } •
    key <AB04> { type = "FOUR_LEVEL"               , [ period, colon, ellipsis, periodcentered ] }; // . : … ·
    key <AB05> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ k, K, asciitilde, dead_tilde ] }; // k K ~ ˜
    key <AB06> { type = "FOUR_LEVEL"               , [ rightsinglequotemark, question, questiondown, leftsinglequotemark ] }; // ’ ? ¿ ‘
    key <AB07> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ q, Q, bracketleft, dead_ogonek ] }; // q Q [ ˛
    key <AB08> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ g, G, bracketright, dead_cedilla ] }; // g G ] ¸
    key <AB09> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ h, H, asciicircum, $as_dead_belowcomma ] }; // h H ^ ,
    key <AB10> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ m, M, dollar, $ve_AB10_ma_symb ] }; // m M \$ $ve_AB10_ma
    key <AB11> { type = "THREE_LEVEL"              , [ dead_tilde, dead_tilde, U26BD ] }; // ˜ ˜ (touche spécifique aux claviers brésiliens)

    key <LWIN> { type = $ve_LWIN_def };
    key <LALT> { type = $ve_LALT_def };
    key <SPCE> { type = "FOUR_LEVEL"               , [ space, $ve_SPCE_m_symb, underscore, $ve_SPCE_ma_symb ] }; // ␣ $ve_SPCE_m _ $ve_SPCE_ma
    key <RALT> { type = "ONE_LEVEL"                , [ ISO_Level3_Shift ] };
    key <RWIN> { type = "TWO_LEVEL"                , [ Menu, Super_R ] };
    key <MENU> { type = "TWO_LEVEL"                , [ Super_L, Menu ] };

DISPO_7
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # Si l’option --multimedia_pause est active, on définit le mode muet sur
    # pause.
    if $multimedia_pause; then
        cat >> "$cb_nom_fich" <<DISPO_8
    key <PAUS> { type = "THREE_LEVEL"              , [ XF86AudioMute, Break, Pause ] };

DISPO_8
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # Si l’option --multimedia_curseur est active, on définit des actions
    # en AltGr sur les touches curseur.
    if $multimedia_curseur; then
        cat >> "$cb_nom_fich" <<DISPO_9
    key <UP>   { type = "THREE_LEVEL"              , [ Up, Up, XF86AudioRaiseVolume ] };
    key <LEFT> { type = "THREE_LEVEL"              , [ Left, Left, XF86Back ] };
    key <RGHT> { type = "THREE_LEVEL"              , [ Right, Right, XF86Forward ] };
    key <DOWN> { type = "THREE_LEVEL"              , [ Down, Down, XF86AudioLowerVolume ] };

DISPO_9
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # En chargement dynamique, on définit tout de même les touches de base, par
    # précaution.
    if ! $cb_mode_install; then
        cat >> "$cb_nom_fich" <<DISPO_10
    key <TAB>  { type = "TWO_LEVEL"                , [ Tab, ISO_Left_Tab ] };
    key <RTRN> { type = "ONE_LEVEL"                , [ Return ] };
    key <CAPS> { type = "ONE_LEVEL"                , [ Caps_Lock ] };
    key <LFSH> { type = "ONE_LEVEL"                , [ Shift_L ] };
    key <RTSH> { type = "ONE_LEVEL"                , [ Shift_R ] };
    key <LCTL> { type = "ONE_LEVEL"                , [ Control_L ] };
    key <RCTL> { type = "ONE_LEVEL"                , [ Control_R ] };

    modifier_map Shift   { <LFSH>, <RTSH> };
    modifier_map Control { <LCTL>, <RCTL> };
DISPO_10
        # Si l’écriture a échoué, on retourne une erreur.
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # Pour finir, on définit les modificatrices spécifiques au Béop.
    cat >> "$cb_nom_fich" <<FIN_DISPO
    modifier_map Mod1 { $ve_Mod1 };
    modifier_map Mod5 { $ve_Mod5, <RALT> };
};
FIN_DISPO

    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # Si l’on est en chargement dynamique, on a fini.
    $cb_mode_install || return 0

    # Installation des variantes (traitements communs)

    # On détermine le préfixe éventuel pour l’inclusion de la disposition de
    # base.
    cb_prefixe_inclusion=''
    chaine_incluse '/pc/' "$cb_nom_fich" && cb_prefixe_inclusion='pc/'

    # Installation de la variante programmation

    # Adaptation selon si chaque disposition est installée comme disposition à
    # part entière (anciennes versions de X)…
    if $cb_mode_principale; then
        cb_nom_variante='fr-beop_prog'
        cb_inclusion="${cb_prefixe_inclusion}fr-beop"
        cb_nom_fich_pr="${cb_nom_fich}_prog"
    # … ou comme variante pour une langue (versions récentes de X)
    else
        cb_nom_variante='beop_prog'
        cb_inclusion="${cb_prefixe_inclusion}fr(beop)"
        cb_nom_fich_pr="$cb_nom_fich"
    fi

    # On ajoute le commentaire.
    cat >> "$cb_nom_fich_pr" <<COMMENT_BEOP_PROG

// Béop_prog
// Béop variant for programming (less risk of accidentaly typing a non breakable space)
COMMENT_BEOP_PROG
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    affiche_carte "$cb_version" "prog" "$cb_altgr_sur_win" true false '// ' >> "$cb_nom_fich_pr"
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # On ajoute la disposition.
    cat >> "$cb_nom_fich_pr" <<FIN_BEOP_PROG
partial ${cb_default}alphanumeric_keys modifier_keys
xkb_symbols "$cb_nom_variante" {

    include "$cb_inclusion"

    name[Group1]= "French (Beop, variant for programming)";

    key <AE05> { type = "FOUR_LEVEL"               , [ quotedbl , leftdoublequotemark, $ve_AE05_a_symb, $ve_AE05_ma_symb ] }; // " “ $ve_AE05_a $ve_AE05_ma
    key <AB01> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ agrave, Agrave, backslash, U202F ] }; // à À \\ (espace insécable fine)
    key <SPCE> { type = "FOUR_LEVEL"               , [ space, space, underscore, nobreakspace ] }; // ␣ ␣ _ ⍽
};
FIN_BEOP_PROG
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # Installation de la variante typographique

    # Adaptation selon si chaque disposition est installée comme disposition à
    # part entière (anciennes versions de X)…
    if $cb_mode_principale; then
        cb_nom_variante='fr-beop_typo'
        cb_inclusion="${cb_prefixe_inclusion}fr-beop"
        cb_nom_fich_ty="${cb_nom_fich}_typo"
    # … ou comme variante pour une langue (versions récentes de X)
    else
        cb_nom_variante='beop_typo'
        cb_inclusion="${cb_prefixe_inclusion}fr(beop)"
        cb_nom_fich_ty="$cb_nom_fich"
    fi

    # On ajoute le commentaire.
    cat >> "$cb_nom_fich_ty" <<COMMENT_BEOP_TYPO

// Béop_typo
// Béop variant for better typography (but less supported characters)
COMMENT_BEOP_TYPO
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    affiche_carte "$cb_version" "typo" "$cb_altgr_sur_win" true false '// ' >> "$cb_nom_fich_ty"
    # Si l’écriture a échoué, on retourne une erreur.
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # On ajoute le début de la disposition et les premières touches modifiées.
    cat >> "$cb_nom_fich_ty" <<BEOP_TYPO_1
partial ${cb_default}alphanumeric_keys modifier_keys
xkb_symbols "$cb_nom_variante" {

    include "$cb_inclusion"

    name[Group1]= "French (Beop, variant for better typography)";

    key <AE01> { type = "FOUR_LEVEL"               , [ numbersign, section, $ve_AE01_a_symb, U2039 ] }; // # § $ve_AE01_a ‹
    key <AE02> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ w, W, $ve_AE02_a_symb, U203A ] }; // w W $ve_AE02_a ›
    key <AE03> { type = "FOUR_LEVEL"               , [ U2010, $ve_guil_ouvr_typo, $ve_AE03_a_symb, $ve_AE03_ma_symb ] }; // ‐ « $ve_AE03_a $ve_AE03_ma
BEOP_TYPO_1
    cb_val_ret=$?
    [ $cb_val_ret -ne 0 ] && return $cb_val_ret

    # Selon l’option de guillemets avec espace, on redéfinit la touche
    # éventuellement concernée.
    if $cb_guillemets_avec_espaces_typo || $cb_guillemets_avec_espaces_norm; then
        cat >> "$cb_nom_fich_ty" <<BEOP_TYPO_2
    key <AE04> { type = "FOUR_LEVEL"               , [ apostrophe, $ve_guil_ferm_typo, $ve_AE04_a_symb, $ve_AE04_ma_symb ] }; // ' » $ve_AE04_a $ve_AE04_ma
BEOP_TYPO_2
        cb_val_ret=$?
        [ $cb_val_ret -ne 0 ] && return $cb_val_ret
    fi

    # On ajoute les autres touches modifiées.
    cat >> "$cb_nom_fich_ty" <<FIN_BEOP_TYPO
    key <AC01> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ a, A, less, U2A7D ] }; // a A < ⩽
    key <AC04> { type = "FOUR_LEVEL_SEMIALPHABETIC", [ i, I, greater, U2A7E ] }; // i I > ⩾
    key <SPCE> { type = "FOUR_LEVEL"               , [ space, U202F, underscore, nobreakspace ] }; // ␣ (espace insécable fine) _ ⍽
};
FIN_BEOP_TYPO
}


# Passage en Béop
beop() {
    be_version="$1"; be_variante="$2"; be_altgr_sur_win="$3"
    be_guillemets_avec_espaces_norm="$4"; be_guillemets_avec_espaces_typo="$5"

    # Lancer setxkbmap -print alors qu’on a modifié la disposition avec xkbcomp
    # semble parfois causer des problèmes,donc si on est déjà en Béop, on essaie
    # de restaurer l’Azerty avant.
    xkbcomp -xkb -o - $DISPLAY | $egrep '^xkb_symbols.*beop' > /dev/null && setxkbmap fr

    # Vérification qu’on peut récupérer les paramètres actuels
    setxkbmap -print > /dev/null 2>&1
    be_val_ret=$?
    if [ $be_val_ret -ne 0 ]; then
        echo "Impossible de récupérer les paramètres actuels avec setxkbmap -print"; echo
        return $be_val_ret
    fi

    # Fichier temporaire pour créer la définition Xkb
    be_temp_fich="/tmp/$(basename $0).$$.xkb"

    # On récupère les réglages actuels (hormis la disposition).
    setxkbmap -print | $egrep 'xkb_(keymap|keycodes|types|compat|geometry)' > $be_temp_fich
    be_val_ret=$?
    if [ $be_val_ret -ne 0 ]; then
        echo "Échec de création du fichier temporaire $be_temp_fich"; echo
        exit $be_val_ret
    fi

    # On les complète avec la disposition Béop…
    cat_beop "$be_temp_fich" "$be_version" "$be_variante" "$be_altgr_sur_win" false false "$be_guillemets_avec_espaces_norm" "$be_guillemets_avec_espaces_typo"
    be_val_ret=$?
    if [ $be_val_ret -ne 0 ]; then
        echo "Échec d'écriture dans le fichier temporaire $be_temp_fich"; echo
        exit $be_val_ret
    fi

    # … et l’accolade fermante.
    cat >> $be_temp_fich <<FIN_ACCOL

};
FIN_ACCOL
    be_val_ret=$?
    if [ $be_val_ret -ne 0 ]; then
        echo "Échec d'écriture dans le fichier temporaire $be_temp_fich"; echo
        exit $be_val_ret
    fi

    # On charge les nouveaux réglages.
    xkbcomp -w 0 $be_temp_fich $DISPLAY
    be_val_ret=$?

    if [ $be_val_ret -eq 0 ]; then
        echo 'Disposition Béop chargée'
    else
        echo 'Échec du chargement de la disposition Béop'
    fi

    $debug || rm $be_temp_fich

    return $be_val_ret
}


# Passage en Azerty
azerty() {
    # Tant qu’à faire, on essaie de mettre les meilleures versions d’abord.
    setxkbmap fr oss || setxkbmap fr latin9 || setxkbmap fr
    az_val_ret=$?

    if [ $az_val_ret -eq 0 ]; then
        # On charge le fichier ~/.Xmodmap s’il existe.
        [ -e "$HOME/.Xmodmap" ] && xmodmap $HOME/.Xmodmap
        echo 'Disposition Azerty chargée'
    else
        echo 'Échec du rétablissement de la disposition Azerty'
    fi

    return $az_val_ret
}


# Écriture de la définition console de la disposition Béop dans un fichier
cat_beop_cons() {
    cbc_nom_fich="$1"; cbc_version="$2"; cbc_variante="$3"; cbc_altgr_sur_win="$4"

    # On adapte suivant la version.
    version "$cbc_version" "$cbc_variante" "$cbc_altgr_sur_win" '' '' false false ''

    cat > "$cbc_nom_fich" <<FIN_DISPO_CONS
# beop  http://beop.free.fr
keymaps 0-15

# includes are disabled to work also on debian
# include "linux-with-alt-and-altgr"


################### linux-keys-bare ###################
# Linux-specific (and language-independent) keys
#
# This file describes function keys, console switching keys,
# keypad, cursor keys, and SysRq, ScrollLock, Pause
#
# It does not use the AltGr modifier, so that the user can opt
# to have both Alt keys produce the same effect.
# As a consequence, the Hex_* keys are missing, as are
#	control altgr keycode 83 = Boot
#	control altgr keycode 111 = Boot
#
# One culture-specific item that will be overridden in many keymaps
# is the KP_Period: many countries have a KP_Comma instead.
#
# One user-preference item will be the function of the Delete key.
#
# Old keyboards have 10 function keys, and keymaps have
# sometimes used shift+F1 = F11, and sometimes shift+F1 = F13.
# Here we assume an enhanced keyboard (with 12 function keys).
#
plain keycode  59 = F1
plain keycode  60 = F2
plain keycode  61 = F3
plain keycode  62 = F4
plain keycode  63 = F5
plain keycode  64 = F6
plain keycode  65 = F7
plain keycode  66 = F8
plain keycode  67 = F9
plain keycode  68 = F10
plain keycode  87 = F11
plain keycode  88 = F12
shift keycode  59 = F13
shift keycode  60 = F14
shift keycode  61 = F15
shift keycode  62 = F16
shift keycode  63 = F17
shift keycode  64 = F18
shift keycode  65 = F19
shift keycode  66 = F20
shift keycode  67 = F21
shift keycode  68 = F22
shift keycode  87 = F23
shift keycode  88 = F24
control keycode  59 = F25
control keycode  60 = F26
control keycode  61 = F27
control keycode  62 = F28
control keycode  63 = F29
control keycode  64 = F30
control keycode  65 = F31
control keycode  66 = F32
control keycode  67 = F33
control keycode  68 = F34
control keycode  87 = F35
control keycode  88 = F36
#
# The canonical assignment for F37-F48 uses
#	control shift keycode  59 = F37
# etc. If you want that, load linux-keys-extd.inc
#
# Both Alt+Fn and Control+Alt+Fn switch to Console n
# (in order to please Linux / dosemu / X).
# Here Consoles 1..12. For 13..24 load linux-keys-extd.inc
#
alt keycode  59 = Console_1
alt keycode  60 = Console_2
alt keycode  61 = Console_3
alt keycode  62 = Console_4
alt keycode  63 = Console_5
alt keycode  64 = Console_6
alt keycode  65 = Console_7
alt keycode  66 = Console_8
alt keycode  67 = Console_9
alt keycode  68 = Console_10
alt keycode  87 = Console_11
alt keycode  88 = Console_12
control alt keycode  59 = Console_1
control alt keycode  60 = Console_2
control alt keycode  61 = Console_3
control alt keycode  62 = Console_4
control alt keycode  63 = Console_5
control alt keycode  64 = Console_6
control alt keycode  65 = Console_7
control alt keycode  66 = Console_8
control alt keycode  67 = Console_9
control alt keycode  68 = Console_10
control alt keycode  87 = Console_11
control alt keycode  88 = Console_12

#
# Keypad keys
#
keycode  69 = Num_Lock
keycode  98 = KP_Divide
keycode  55 = KP_Multiply
keycode  74 = KP_Subtract
keycode  78 = KP_Add
keycode  96 = KP_Enter
#
keycode  71 = KP_7
keycode  72 = KP_8
keycode  73 = KP_9
keycode  75 = KP_4
keycode  76 = KP_5
keycode  77 = KP_6
keycode  79 = KP_1
keycode  80 = KP_2
keycode  81 = KP_3
keycode  82 = KP_0
#
keycode  83 = KP_Period			# or KP_Comma
control alt keycode  83 = Boot
#
alt keycode  71 = Ascii_7
alt keycode  72 = Ascii_8
alt keycode  73 = Ascii_9
alt keycode  75 = Ascii_4
alt keycode  76 = Ascii_5
alt keycode  77 = Ascii_6
alt keycode  79 = Ascii_1
alt keycode  80 = Ascii_2
alt keycode  81 = Ascii_3
alt keycode  82 = Ascii_0
#
# The four cursor keys
#
keycode 103 = Up
keycode 105 = Left
keycode 106 = Right
keycode 108 = Down
alt keycode 103 = KeyboardSignal
alt keycode 105 = Decr_Console
alt keycode 106 = Incr_Console
#
# The six edit keys
#
keycode 110 = Insert
keycode 102 = Home		# Find
keycode 104 = PageUp		# Prior
keycode 111 = Remove
keycode 107 = End		# Select
keycode 109 = PageDown		# Next
shift keycode 104 = Scroll_Backward
shift keycode 109 = Scroll_Forward
control	alt keycode 111 = Boot
#
# The three system keys
#
keycode  84 = Last_Console		# Alt+SysRq/PrintScrn
keycode  99 = Control_backslash		# SysRq/PrintScrn

plain   keycode 70 = Scroll_Lock
shift	keycode 70 = Show_Memory
control keycode 70 = Show_State
alt	keycode 70 = Show_Registers

keycode 101 = Break			# Ctrl+Break/Pause
keycode 119 = Pause			# Break/Pause
################################################################

################### linux-with-alt-and-altgr ###################
# For keymaps in which both Alt keys are equivalent
# No convention for Hex_* has been established.

# include "linux-keys-bare"

keycode 100 = AltGr

altgr keycode 70 = Show_Registers
alt keycode 70 = Scroll_Lock

control altgr keycode 83 = Boot
control altgr keycode 111 = Boot

# Hex keypad keys (for giving a Unicode value in 4 hex digits)
# Follow lt.kmap and assign Hex_A .. Hex_F to keypad border.
altgr keycode  55 = Hex_C
altgr keycode  69 = Hex_A
altgr keycode  71 = Hex_7
altgr keycode  72 = Hex_8
altgr keycode  73 = Hex_9
altgr keycode  74 = Hex_D
altgr keycode  75 = Hex_4
altgr keycode  76 = Hex_5
altgr keycode  77 = Hex_6
altgr keycode  78 = Hex_E
altgr keycode  79 = Hex_1
altgr keycode  80 = Hex_2
altgr keycode  81 = Hex_3
altgr keycode  82 = Hex_0
altgr keycode  96 = Hex_F
altgr keycode  98 = Hex_B
################################################################

strings as usual
compose as usual for "iso-8859-1"


keycode 41 = Compose

keycode 2 = numbersign section $ve_AE01_a_symbc $ve_AE01_ma_symbc
  Alt keycode 2 = Meta_numbersign
  Shift Alt keycode 2 = Meta_section

keycode 3 = +w +W $ve_AE02_a_symbc $ve_AE02_ma_symbc
  Control keycode 3 = Control_w

keycode 4 = $ve_AE03_symbc guillemotleft $ve_AE03_a_symbc $ve_AE03_ma_symbc
  Alt keycode 4 = Meta_minus

keycode 5 = apostrophe guillemotright $ve_AE04_a_symbc $ve_AE04_ma_symbc
  Alt keycode 5 = Meta_apostrophe
  Shift keycode 5 = guillemotright

keycode 6 = quotedbl U+201c $ve_AE05_a_symbc $ve_AE05_ma_symbc
  Alt keycode 6 = Meta_quotedbl

keycode 7 = grave U+201d thorn THORN
  Alt keycode 7 = Meta_grave

keycode 8 = +ugrave +Ugrave U+016d $ve_AE07_ma_symbc

keycode 9 = +ccedilla +Ccedilla eight degree
  Altgr Alt keycode 9 = Meta_eight

keycode 10 = parenleft U+2013 nine U+2032
  Alt keycode 10 = Meta_parenleft
  Altgr   Alt keycode 10 = Meta_nine

keycode 11 = parenright U+2014 comma U+2033
  Alt keycode 11 = Meta_parenright
  Altgr   Alt keycode 11 = Meta_comma

keycode 12 = dead_diaeresis mu period U+02d9
  Altgr   Alt keycode 12 = Meta_period

keycode 13 = percent U+2030 equal $ve_AE12_ma_symbc
  Alt keycode 13 = Meta_percent
  Altgr   Alt keycode 16 = Meta_equal

keycode 16 = +b +B bar $ve_AD01_ma_symbc
  Control keycode 16 = Control_b
  Alt keycode 16 = Meta_b
  Control Alt keycode 16 = Meta_Control_b
  Shift   Control keycode 16 = Control_b
  Shift   Alt keycode 16 = Meta_B
  Shift   Control Alt keycode 16 = Meta_Control_b
  Altgr   Alt keycode 16 = Meta_bar

keycode 17 = +eacute +Eacute $ve_AD02_a_symbc $ve_AD02_ma_symbc

keycode 18 = +o +O +0xbd +0xbc
  Control keycode 18 = Control_o
  Alt keycode 18 = Meta_o
  Control Alt keycode 18 = Meta_Control_o
  Shift   Control keycode 18 = Control_o
  Shift   Alt keycode 18 = Meta_O
  Shift   Control Alt keycode 18 = Meta_Control_o

keycode 19 = +p +P ampersand $ve_AD04_ma_symbc
  Control keycode 19 = Control_p
  Alt keycode 19 = Meta_p
  Control Alt keycode 19 = Meta_Control_p
  Shift   Control keycode 19 = Control_p
  Shift   Alt keycode 19 = Meta_P
  Shift   Control Alt keycode 19 = Meta_Control_p
  Altgr   Alt keycode 19 = Meta_ampersand

keycode 20 = +egrave +Egrave $ve_AD05_a_symbc $ve_AD05_ma_symbc
  Altgr   Alt keycode 20 = Meta_grave

keycode 21 = dead_circumflex exclam exclamdown dead_caron
  Control keycode 21 = Control_asciicircum
  Alt keycode 21 = Meta_asciicircum
  Control Alt keycode 21 = Meta_Control_asciicircum
  Shift   Alt keycode 21 = Meta_exclam

keycode 22 = +v +V plus plusminus
  Control keycode 22 = Control_v
  Alt keycode 22 = Meta_v
  Control Alt keycode 22 = Meta_Control_v
  Shift   Control keycode 22 = Control_v
  Shift   Alt keycode 22 = Meta_V
  Shift   Control Alt keycode 22 = Meta_Control_v
  Altgr   Alt keycode 22 = Meta_plus

keycode 23 = +d +D four $ve_AD08_ma_symbc
  Control keycode 23 = Control_d
  Alt keycode 23 = Meta_d
  Control Alt keycode 23 = Meta_Control_d
  Shift   Control keycode 23 = Control_d
  Shift   Alt keycode 23 = Meta_D
  Shift   Control Alt keycode 23 = Meta_Control_d
  Altgr   Alt keycode 23 = Meta_four

keycode 24 = +l +L five $ve_AD09_ma_symbc
  Control keycode 24 = Control_l
  Alt keycode 24 = Meta_l
  Control Alt keycode 24 = Meta_Control_l
  Shift   Control keycode 24 = Control_l
  Shift   Alt keycode 24 = Meta_L
  Shift   Control Alt keycode 24 = Meta_Control_l
  Altgr   Alt keycode 24 = Meta_five
  Shift Altgr   Alt keycode 24 = Meta_slash

keycode 25 = +j +J six $ve_AD10_ma_symbc
  Control keycode 25 = Control_j
  Alt keycode 25 = Meta_j
  Control Alt keycode 25 = Meta_Control_j
  Shift   Control keycode 25 = Control_j
  Shift   Alt keycode 25 = Meta_J
  Shift   Control Alt keycode 25 = Meta_Control_j
  Altgr   Alt keycode 25 = Meta_six

keycode 26 = +z +Z seven $ve_AD11_ma_symbc
  Control keycode 26 = Control_z
  Alt keycode 26 = Meta_z
  Control Alt keycode 26 = Meta_Control_z
  Shift   Control keycode 26 = Control_z
  Shift   Alt keycode 26 = Meta_Z
  Shift   Control Alt keycode 26 = Meta_Control_z
  Altgr   Alt keycode 26 = Meta_seven

keycode 27 = $ve_AD12_symbc multiply asterisk U+2020
  Alt keycode 27 = Meta_asterisk
  Altgr   Alt keycode 27 = Meta_asterisk

keycode 30 = +a +A less $ve_AC01_ma_symbc
  Control keycode 30 = Control_a
  Alt keycode 30 = Meta_a
  Control Alt keycode 30 = Meta_Control_a
  Shift   Control keycode 30 = Control_a
  Shift   Alt keycode 30 = Meta_A
  Shift   Control Alt keycode 30 = Meta_Control_a
  Altgr   Alt keycode 30 = Meta_less

keycode 31 = +u +U equal U+2243
  Control keycode 31 = Control_u
  Alt keycode 31 = Meta_u
  Control Alt keycode 31 = Meta_Control_u
  Shift   Control keycode 31 = Control_u
  Shift   Alt keycode 31 = Meta_U
  Shift   Control Alt keycode 31 = Meta_Control_u
  Altgr   Alt keycode 31 = Meta_equal

keycode 32 = +e +E 0xa4 U+00a4
  Control keycode 32 = Control_e
  Alt keycode 32 = Meta_e
  Control Alt keycode 32 = Meta_Control_e
  Shift   Control keycode 32 = Control_e
  Shift   Alt keycode 32 = Meta_E
  Shift   Control Alt keycode 32 = Meta_Control_e

keycode 33 = +i +I greater $ve_AC04_ma_symbc
  Control keycode 33 = Control_i
  Alt keycode 33 = Meta_i
  Control Alt keycode 33 = Meta_Control_i
  Shift   Control keycode 33 = Control_i
  Shift   Alt keycode 33 = Meta_I
  Altgr   Alt keycode 33 = Meta_greater

keycode 34 = comma semicolon slash $ve_AC05_ma_symbc
  Alt keycode 34 = Meta_comma
  Shift   Alt keycode 34 = Meta_semicolon
  Altgr   Alt keycode 34 = Meta_slash

keycode 35 = +c +C at copyright
  Control keycode 35 = Control_c
  Alt keycode 35 = Meta_c
  Control Alt keycode 35 = Meta_Control_c
  Shift   Control keycode 35 = Control_c
  Shift   Alt keycode 35 = Meta_C
  Shift   Control Alt keycode 35 = Meta_Control_c
  Altgr   Alt keycode 35 = Meta_at

keycode 36 = +t +T minus U+2212
  Control keycode 36 = Control_t
  Alt keycode 36 = Meta_t
  Control Alt keycode 36 = Meta_Control_t
  Shift   Control keycode 36 = Control_t
  Shift   Alt keycode 36 = Meta_T
  Shift   Control Alt keycode 36 = Meta_Control_t
  Altgr   Alt keycode 36 = Meta_minus

keycode 37 = +s +S zero $ve_AC08_ma_symbc
  Control keycode 37 = Control_s
  Alt keycode 37 = Meta_s
  Control Alt keycode 37 = Meta_Control_s
  Shift   Control keycode 37 = Control_s
  Shift   Alt keycode 37 = Meta_S
  Shift   Control Alt keycode 37 = Meta_Control_s
  Altgr   Alt keycode 37 = Meta_zero

keycode 38 = +r +R one $ve_AC09_ma_symbc
  Control keycode 38 = Control_r
  Alt keycode 38 = Meta_r
  Control Alt keycode 38 = Meta_Control_r
  Shift   Control keycode 38 = Control_r
  Shift   Alt keycode 38 = Meta_R
  Shift   Control Alt keycode 38 = Meta_Control_r
  Altgr   Alt keycode 38 = Meta_one

keycode 39 = +n +N two $ve_AC10_ma_symbc
  Control keycode 39 = Control_n
  Alt keycode 39 = Meta_n
  Control Alt keycode 39 = Meta_Control_n
  Shift   Control keycode 39 = Control_n
  Shift   Alt keycode 39 = Meta_N
  Shift   Control Alt keycode 39 = Meta_Control_n
  Altgr   Alt keycode 39 = Meta_two

keycode 40 = +f +F three ordfeminine
  Control keycode 40 = Control_f
  Alt keycode 40 = Meta_f
  Control Alt keycode 40 = Meta_Control_f
  Shift   Control keycode 40 = Control_f
  Shift   Alt keycode 40 = Meta_F
  Shift   Control Alt keycode 40 = Meta_Control_f
  Altgr   Alt keycode 40 = Meta_three

keycode 43 = $ve_BKSL_symbc division slash U+2021
  Alt keycode 43 = Meta_slash
  Altgr   Alt keycode 43 = Meta_slash

keycode 86 = +ecircumflex +Ecircumflex asterisk U+262D
  AltGr   Alt keycode 86 = Meta_asterisk

keycode 44 = +agrave +Agrave backslash $ve_AB01_ma_symbc
  AltGr   Alt keycode 44 = Meta_backslash

keycode 45 = +y +Y braceleft U+2260
  Control keycode 48 = Control_y
  Alt keycode 48 = Meta_y
  Control Alt keycode 48 = Meta_Control_y
  Shift   Control keycode 48 = Control_y
  Shift   Alt keycode 48 = Meta_Y
  Shift   Control Alt keycode 48 = Meta_Control_y
  Altgr   Alt keycode 48 = Meta_braceleft

keycode 46 = +x +X braceright U+2022
  Control keycode 48 = Control_x
  Alt keycode 48 = Meta_x
  Control Alt keycode 48 = Meta_Control_x
  Shift   Control keycode 48 = Control_x
  Shift   Alt keycode 48 = Meta_X
  Shift   Control Alt keycode 48 = Meta_Control_x
  Altgr   Alt keycode 48 = Meta_braceright

keycode 47 = period colon U+2026 periodcentered
  Alt keycode 47 = Meta_period
  Shift   Alt keycode 47 = Meta_colon

keycode 48 = +k +K asciitilde dead_tilde
  Control keycode 48 = Control_k
  Alt keycode 48 = Meta_k
  Control Alt keycode 48 = Meta_Control_k
  Shift   Control keycode 48 = Control_k
  Shift   Alt keycode 48 = Meta_K
  Shift   Control Alt keycode 48 = Meta_Control_k
  Altgr   Alt keycode 48 = Meta_asciitilde
  Shift Altgr   Alt keycode 48 = Meta_asciitilde

keycode 49 = U+2019 question questiondown U+2018
  Alt keycode 49 = Meta_apostrophe
  Shift   Alt keycode 49 = Meta_question

keycode 50 = +q +Q bracketleft dead_ogonek
  Control keycode 50 = Control_q
  Alt keycode 50 = Meta_q
  Control Alt keycode 50 = Meta_Control_q
  Shift   Control keycode 50 = Control_q
  Shift   Alt keycode 50 = Meta_Q
  Shift   Control Alt keycode 50 = Meta_Control_q
  Altgr   Alt keycode 50 = Meta_bracketleft

keycode 51 = +g +G bracketright dead_cedilla
  Control keycode 51 = Control_g
  Alt keycode 51 = Meta_g
  Control Alt keycode 51 = Meta_Control_g
  Shift   Control keycode 51 = Control_g
  Shift   Alt keycode 51 = Meta_G
  Shift   Control Alt keycode 51 = Meta_Control_g
  Altgr   Alt keycode 51 = Meta_bracketright

keycode 52 = +h +H asciicircum
  Control keycode 52 = Control_h
  Alt keycode 52 = Meta_h
  Control Alt keycode 52 = Meta_Control_h
  Shift   Control keycode 52 = Control_h
  Shift   Alt keycode 52 = Meta_H
  Shift   Control Alt keycode 51 = Meta_Control_h
  Altgr   Alt keycode 52 = Meta_asciicircum

keycode 53 = +m +M dollar $ve_AB10_ma_symbc
  Control keycode 53 = Control_m
  Alt keycode 53 = Meta_m
  Control Alt keycode 53 = Meta_Control_m
  Shift   Control keycode 53 = Control_m
  Shift   Alt keycode 53 = Meta_M
  Shift   Control Alt keycode 53 = Meta_Control_m
  Altgr   Alt keycode 53 = Meta_dollar

keycode 57 = space $ve_SPCE_m_symbc underscore $ve_SPCE_ma_symbc
  Control keycode 57 = nul
  Alt keycode 57 = Meta_space

keycode 89 = dead_tilde dead_tilde U+26BD
  Alt keycode 89 = Meta_asciitilde


# include "windowkeys"
################### windowkeys #################################
# Extra 105 windows keys

keycode 125 = $ve_LWIN_symbc
keycode 126 = Decr_Console
keycode 127 = Incr_Console
################################################################


keycode  1 = Escape Escape
keycode 14 = Delete  Delete
keycode 15 = Tab Tab
keycode 28 = Return
keycode 29 = Control
keycode 42 = Shift
keycode 54 = Shift
keycode 56 = $ve_LALT_symbc
keycode 58 = Caps_Lock
keycode 97 = Control
FIN_DISPO_CONS
}


# Passage en Béop des consoles texte
console_beop() {
    cob_version="$1"; cob_variante="$2"; cob_altgr_sur_win="$3"

    # Fichier temporaire pour créer la définition pour loadkeys
    cob_temp_fich="/tmp/$(basename $0).$$.map"

    # On écrit la disposition dans le fichier temporaire.
    cat_beop_cons "$cob_temp_fich" "$cob_version" "$cob_variante" "$cob_altgr_sur_win"
    cob_val_ret=$?
    if [ $cob_val_ret -ne 0 ]; then
        echo "Échec de création du fichier temporaire $cob_temp_fich"; echo
        exit $cob_val_ret
    fi

    # On charge les nouveaux réglages.
    loadkeys $cob_temp_fich > /dev/null 2>&1
    cob_val_ret=$?

    # Suivant le code de retour, on affiche le message approprié.
    if [ $cob_val_ret -eq 0 ]; then
        echo 'Disposition Béop chargée sur les consoles texte'
    else
        echo 'Échec du chargement de la disposition Béop sur les consoles texte'
    fi

    rm $cob_temp_fich

    return $cob_val_ret
}


# Passage en Azerty des consoles texte
console_azerty() {
    # Tant qu’à faire, on essaie de mettre la meilleure version d’abord.
    loadkeys fr-latin9 > /dev/null 2>&1 || loadkeys fr > /dev/null 2>&1
    ca_val_ret=$?

    if [ $ca_val_ret -eq 0 ]; then
        echo 'Disposition Azerty chargée sur les consoles texte'
    else
        echo 'Échec du rétablissement de la disposition Azerty sur les consoles texte'
    fi

    return $ca_val_ret
}


# Insertion de texte avant une ligne contenant un repère
insere_texte_avant() {
    ita_nom_fich_entree="$1"; ita_nom_fich_sortie="$2"; ita_repere="$3"; ita_ajout="$4"

    # On intercale le Béop avec awk ou sed, ou une boucle en shell pour limiter
    # les dépendances (mais ils ne permettent pas de vérifier si le fichier a
    # bien la structure attendue…).
    
    ### Pour test, décommenter à ajuster la variable suivante :
    #commande_insertion='read'
    if [ "$commande_insertion" = "awk" ]; then
        remplace_multiple_chaine ita_repere '/' '\/'
        remplace_multiple_chaine ita_ajout  '"' '\"'
        awk "/$ita_repere/ { print \"$ita_ajout\" } { print }" "$ita_nom_fich_entree" > "$ita_nom_fich_sortie"
        ita_val_ret=$?
    elif [ "$commande_insertion" = "sed" ]; then
        remplace_multiple_chaine ita_repere '~' '\~'
        remplace_multiple_chaine ita_ajout  '~' '\~'
        sed -e "s~^\(.*$ita_repere\)~$ita_ajout\n\1~" < "$ita_nom_fich_entree" > "$ita_nom_fich_sortie"
        ita_val_ret=$?
    else
        # Solution pas dépendante d’awk ou sed… mais de read -r
        ( IFS=''; while read -r ita_ligne || [ -n "$ita_ligne" ]; do
        # La construction read ita_ligne || [ -n "$ita_ligne" ] permet de ne pas
        # rater la dernière ligne si elle ne se termine pas par une fin
        # de ligne comme elle devrait (et c’est le cas avec certaines
        # versions de XKB).
            chaine_incluse "$ita_repere" "$ita_ligne" && printf "$ita_ajout\n"
            echo "$ita_ligne"
        done < "$ita_nom_fich_entree" > "$ita_nom_fich_sortie" )
        ita_val_ret=$?
    fi
    return $ita_val_ret
}


# Ajout de la disposition sous X.org
installe_beop_X() {
    ibx_version="$1"; ibx_altgr_sur_win="$2"
    ibx_guillemets_avec_espaces_norm="$3"; ibx_guillemets_avec_espaces_typo="$4"

    $debug && echo "installe_beop_X '$1' '$2' '$3' '$4'" >&2

    # Si le fichier n’a pas été déterminé, l’installation est impossible.
    if [ -z "$as_fich_X" ]; then
        echo "Pas d’installation pour X.org : répertoire xkb non trouvé"; echo
        return 1
    fi

    # On ajoute la définition de la disposition Béop uniquement si elle n’est
    # pas déjà présente.
    if grep 'xkb_symbols "beop"' "$as_fich_X" > /dev/null 2>&1; then
        echo; echo "Disposition Béop déjà ajoutée au fichier $as_fich_X ;"
        echo "pas de modification."
    else
        if ! $as_fich_X_separe; then
            echo; echo "Sauvegarde du fichier $as_fich_X d'origine en"
            echo "                      $as_fich_X.sans_beop"
            cp -pf "$as_fich_X" "$as_fich_X.sans_beop"
            ibx_val_ret=$?
            if [ $ibx_val_ret -ne 0 ]; then
                echo "Échec !"
                echo "Assurez-vous de lancer la commande en tant que root"
                echo "et qu'il reste de la place sur le disque."; echo
                exit $ibx_val_ret
            fi
        fi
        echo; echo "Ajout de la disposition Béop au fichier $as_fich_X"
        if ! $as_fich_X_separe; then
            cat >> "$as_fich_X" <<'FIN_ESPACE'


FIN_ESPACE
        fi

        # Ajout de la disposition au fichier
        cat_beop "$as_fich_X" "$ibx_version" "norm" "$ibx_altgr_sur_win" true "$as_fich_X_separe" "$ibx_guillemets_avec_espaces_norm" "$ibx_guillemets_avec_espaces_typo"
        ibx_val_ret=$?
        if [ $ibx_val_ret -ne 0 ]; then
            echo "Échec !"
            echo "Assurez-vous de lancer la commande en tant que root"
            echo "et qu'il reste de la place sur le disque."; echo
            exit $ibx_val_ret
        fi
    fi

    # Vérification de la disponibilité d’une commande pour l’insertion
    if echo | awk ''; then
        commande_insertion='awk'
    elif echo a | sed 's/a/b\nc/' | grep '^b$' > /dev/null 2>&1; then
        commande_insertion='sed'
    elif echo | read -r ibx_ligne 2>/dev/null; then
        commande_insertion='while_read'
    else
        echo; echo "ERREUR !"
        echo "awk ou une version de sed supportant \n ou read -r est nécessaire pour la"
        echo "déclaration de la disposition."; echo
        return 1
    fi

    # Déclaration de la disposition dans base.lst, evdev.xml, evdev.lst et
    # base.xml.
    for ibx_fich in base.lst evdev.xml evdev.lst base.xml xorg.lst xorg.xml; do
        # Si le fichier n’existe pas ou que c’est juste un lien (auquel cas le
        # fichier désigné est normalement aussi dans la liste), on passe.
        [ -f "$as_rep_rules/$ibx_fich" ] || continue
        [ -L "$as_rep_rules/$ibx_fich" ] && continue

        # Si la disposition est déjà déclarée, on ne fait rien.
        if grep beop "$as_rep_rules/$ibx_fich" > /dev/null 2>&1; then
            echo; echo "Disposition Béop déjà déclarée dans $as_rep_rules/$ibx_fich ;"
            echo "pas de modification."
            continue
        fi

        # On sauvegarde la version actuelle du fichier.
        echo; echo "Sauvegarde du fichier $as_rep_rules/$ibx_fich d'origine en"
        echo "                      $as_rep_rules/$ibx_fich.sans_beop"
        cp -pf "$as_rep_rules/$ibx_fich" "$as_rep_rules/$ibx_fich.sans_beop"
        ibx_val_ret=$?
        if [ $ibx_val_ret -ne 0 ]; then
            echo "Échec !"
            echo "Assurez-vous de lancer la commande en tant que root"
            echo "et qu'il reste de la place sur le disque."; echo
            exit $ibx_val_ret
        fi

        # On ajoute la déclaration du Bépo.
        echo; echo "Déclaration de la disposition Béop dans $as_rep_rules/$ibx_fich"

        # Traitement des fichiers XML
        if chaine_incluse '.xml' "$ibx_fich"; then
            # Dans les versions récentes de X.org, les dispositions sont
            # considérées comme des variantes pour un pays.
            if ! $as_fich_X_separe; then
                # Si le Bépo apparaît, on l’utilise comme repère,
                if grep '<name>bepo</name>' "$as_rep_rules/$ibx_fich" > /dev/null 2>&1; then
                    ibx_repere='<name>bepo</name>'
                # sinon on utilise la variante latin9 de l’Azerty.
                else
                    ibx_repere='<name>latin9</name>'
                fi

                insere_texte_avant "$as_rep_rules/$ibx_fich.sans_beop" "$as_rep_rules/$ibx_fich" "$ibx_repere" '            <name>beop</name>\n            <description>Français (Béop, ergonomique, dérivée plus radicale de Bépo)</description>\n          </configItem>\n        </variant>\n        <variant>\n          <configItem>\n            <name>beop_prog</name>\n            <description>Français (Béop, ergonomique, variante pour la programmation)</description>\n          </configItem>\n        </variant>\n        <variant>\n          <configItem>\n            <name>beop_typo</name>\n            <description>Français (Béop, ergonomique, variante pour une meilleure typographie)</description>\n          </configItem>\n        </variant>\n        <variant>\n          <configItem>'
                ibx_val_ret=$?

            # Dans les anciennes versions de X.org, les dispositions étaient
            # considérées comme des dispositions à part entière.
            else
                insere_texte_avant "$as_rep_rules/$ibx_fich.sans_beop" "$as_rep_rules/$ibx_fich" "<name>fr-latin9</name>" "        <name>fr-beop</name>\n        <description>Français (Béop, ergonomique, dérivée plus radicale de Bépo)</description>\n      </configItem>\n    </layout>\n    <layout>\n      <configItem>\n        <name>fr-beop_prog</name>\n        <description>Français (Béop, ergonomique, variante pour la programmation)</description>\n      </configItem>\n    </layout>\n    <layout>\n      <configItem>\n        <name>fr-beop_typo</name>\n        <description>Français (Béop, ergonomique, variante pour une meilleure typographie)</description>\n      </configItem>\n    </layout>\n    <layout>\n      <configItem>"
                ibx_val_ret=$?
            fi

        # Traitement des fichiers lst
        else

            # Versions récentes de X.org (variante)
            if ! $as_fich_X_separe; then
                if grep bepo "$as_rep_rules/$ibx_fich" > /dev/null 2>&1; then
                    ibx_repere='bepo '
                else
                    ibx_repere='latin9 '
                fi
                insere_texte_avant "$as_rep_rules/$ibx_fich.sans_beop" "$as_rep_rules/$ibx_fich" "$ibx_repere" "  beop            fr: Français (Béop, ergonomique, dérivée plus radicale de Bépo)\n  beop_prog       fr: Français (Béop, ergonomique, variante pour la programmation)\n  beop_typo       fr: Français (Béop, ergonomique, variante pour une meilleure typographie)"
                ibx_val_ret=$?

            # Versions anciennes (disposition séparée)
            else
                insere_texte_avant "$as_rep_rules/$ibx_fich.sans_beop" "$as_rep_rules/$ibx_fich" 'fr-latin9' "  fr-beop\tFrench (ergonomic)\n  fr-beop_prog\tFrench (ergonomic)\n  fr-beop_typo\tFrench (ergonomic)"
                ibx_val_ret=$?
            fi

        fi

        # On indique une éventuelle erreur.
        if [ $ibx_val_ret -ne 0 ]; then
            mv -f "$as_rep_rules/$ibx_fich.sans_beop" "$as_rep_rules/$ibx_fich"
            echo "Échec !"
            echo "Assurez-vous de lancer la commande en tant que root"
            echo "et qu'il reste de la place sur le disque."
            echo "Il est possible aussi que le fichier $as_rep_rules/$ibx_fich présente un cas non prévu par ce script."
        fi
    done

    return $ibx_val_ret
}


# Ajout de la disposition pour la console
installe_beop_console() {
    ibc_version="$1"; ibc_altgr_sur_win="$2"

    # On détermine le répertoire d’installation.
    ibc_keymaps=''
    for ibc_rep in "$rep_install/usr/share/kbd/keymaps" "$rep_install/usr/share/keymaps" "$rep_install/usr/lib/kbd/keymaps" "$rep_install/lib/kbd/keymaps"; do
        if [ -d "$ibc_rep" ]; then
            ibc_keymaps="$ibc_rep"
            break
        fi
    done

    # En cas d’échec, on sort.
    [ -z "$ibc_keymaps" ] && return 0

    # Si le répertoire est vide aussi.
    for ibc_i in "$ibc_keymaps"/*; do
        break
    done
    [ "$ibc_i" = "$ibc_keymaps/*" ] && return 0

    # Détermination du sous-répertoire approprié
    if [ -d "$ibc_keymaps/xkb" ]; then
        ibc_keymaps="$ibc_keymaps/xkb"
    elif [ -d "$ibc_keymaps/i386" ]; then
        ibc_keymaps="$ibc_keymaps/i386/beop"
    fi

    # Si nécessaire, création du sous-répertoire
    [ -d $ibc_keymaps ] || mkdir -p $ibc_keymaps

    # Vérification que la dispositon n’est pas déjà installée
    if [ -e "$ibc_keymaps/fr-beop.map" ] || [ -e "$ibc_keymaps/fr-beop.map.gz" ]; then
        echo; echo "Disposition Béop déjà installée pour la console ;"
        echo "pas de modification."; echo
        ibc_val_ret_base=0
    # Sinon, installation
    else
        cat_beop_cons "$ibc_keymaps/fr-beop.map" "$ibc_version" "norm" "$ibc_altgr_sur_win"
        ibc_val_ret_base=$?
        echo; echo "Disposition Béop installée pour la console dans $ibc_keymaps/fr-beop.map."; echo
    fi

    # Vérification que la variante programmation n’est pas déjà installée
    if [ -e "$ibc_keymaps/fr-beop_prog.map" ] || [ -e "$ibc_keymaps/fr-beop_prog.map.gz" ]; then
        echo "Disposition Béop (variante programmation) déjà installée pour la console ;"
        echo "pas de modification."; echo
        ibc_val_ret_prog=0
    # Sinon, installation
    else
        cat_beop_cons "$ibc_keymaps/fr-beop_prog.map" "$ibc_version" "prog" "$ibc_altgr_sur_win"
        ibc_val_ret_prog=$?
        echo "Disposition Béop (variante programmation) installée pour la console dans"
        echo "$ibc_keymaps/fr-beop_prog.map."; echo
    fi

    # Vérification que la variante typographique n’est pas déjà installée
    if [ -e "$ibc_keymaps/fr-beop_typo.map" ] || [ -e "$ibc_keymaps/fr-beop_typo.map.gz" ]; then
        echo "Disposition Béop (variante typographique) déjà installée pour la console ;"
        echo "pas de modification."; echo
        ibc_val_ret_typo=0
    # Sinon, installation
    else
        cat_beop_cons "$ibc_keymaps/fr-beop_typo.map" "$ibc_version" "typo" "$ibc_altgr_sur_win"
        ibc_val_ret_typo=$?
        echo "Disposition Béop (variante typographique) installée pour la console dans"
        echo "$ibc_keymaps/fr-beop_typo.map."; echo
    fi

    if [ $ibc_val_ret_base -ne 0 ]; then
        return $ibc_val_ret_base
    elif [ $ibc_val_ret_prog -ne 0 ]; then
        return $ibc_val_ret_prog
    else
        return $ibc_val_ret_typo
    fi
}


# Déclaration complémentaire pour Debian et ses dérivées (Ubuntu, Linux Mint…)
# Permet de choisir Béop comme disposition générale pour le système avec
# dpkg-reconfigure keyboard-configuration
declare_beop_debian() {

    # Si on n’est pas sous Debian ou une distribution dérivée, rien à faire.
    [ -n "$as_fich_debian" ] || return 0
    [ -f "$as_fich_debian" ] || return 0

    # On ajoute la définition de la disposition Béop uniquement si elle n’est
    # pas déjà présente.
    if grep '\*beop\*' "$as_fich_debian" > /dev/null 2>&1; then
        echo; echo "Disposition Béop déjà déclarée dans $as_fich_debian ;"
        echo "pas de modification."
        return 0
    fi

    # Vérification de la disponibilité d’awk
    if echo | awk ''; then
        :
    else
        echo; echo "ERREUR !"
        echo "awk est nécessaire pour la déclaration de la disposition dans $as_fich_debian."; echo
    fi

    echo; echo "Sauvegarde du fichier $as_fich_debian d'origine en"
    echo "                      $as_fich_debian.sans_beop"
    cp -pf "$as_fich_debian" "$as_fich_debian.sans_beop"
    dbd_val_ret=$?
    if [ $dbd_val_ret -ne 0 ]; then
        echo "Échec !"
        echo "Assurez-vous de lancer la commande en tant que root (par exemple avec sudo)"
        echo "et qu'il reste de la place sur le disque."; echo
        exit $dbd_val_ret
    fi

    echo; echo "Déclaration de la disposition Béop dans $as_fich_debian"
    awk '/\*bepo\*/ {
                      l=$0
                      sub(/bepo/, "beop", l)
                      sub(/Bepo/, "Beop", l)
                      sub(/Bépo/, "Béop", l)
                      sub(/ \(BEPO\)/, " (BÉOP, more radical derivative of BÉPO)", l)
                      sub(/, ergonomic, Dvorak way/, ", ergonomic, more radical derivative of Bepo", l)
                      sub(/, komforteca, dvorake/, ", komforteca, pli radikala derivaĵo de Bepo", l)
                      sub(/, ergonomique, façon Dvorak/, ", ergonomique, dérivée plus radicale de Bépo", l)
                      print l
                      sub(/beop/, "beop_prog", l)
                      sub(/Beop/, "Beop_prog", l)
                      sub(/Béop/, "Béop_prog", l)
                      sub(/ \(BÉOP, more radical derivative of BÉPO\)/, " (BÉOP variant for programming)", l)
                      sub(/, ergonomic, more radical derivative of Bepo/, ", ergonomic, Beop variant for programming", l)
                      sub(/, komforteca, pli radikala derivaĵo de Bepo/, ", komforteca, variaĵo de Beop por programado", l)
                      sub(/, ergonomique, dérivée plus radicale de Bépo/, ", ergonomique, variante de Béop pour la programmation", l)
                      print l
                    }
                    { print }
        ' "$as_fich_debian.sans_beop" > "$as_fich_debian"
    dbd_val_ret=$?

    # On indique une éventuelle erreur.
    if [ $dbd_val_ret -ne 0 ]; then
        mv -f "$as_fich_debian.sans_beop" "$as_fich_debian"
        echo "Échec !"
        echo "Assurez-vous de lancer la commande en tant que root"
        echo "et qu'il reste de la place sur le disque."
    fi

    return $dbd_val_ret
}


# Installation de la disposition Béop sur le système
installe_beop() {

    $debug && echo "installe_beop '$1' '$2' '$3' '$4'" >&2

    # Installation pour X.org
    installe_beop_X "$1" "$2" "$3" "$4"
    ib_val_ret_X=$?

    # Si l’on est sous Linux (ou qu’on ne peut être sûr de ne pas l’être),
    # on installe la disposition pour la console.
    ib_systeme=`uname`
    if [ -z "$ib_systeme" ] || echo "$ib_systeme" | grep -i 'Linux' > /dev/null 2>&1; then
        installe_beop_console "$1" "$2"
        ib_val_ret_cons=$?
    else
        ib_val_ret_cons=0
    fi

    # Traitement complémentaire pour Debian et ses dérivées,
    # si l’installation de la disposition a réussi.
    if [ $ib_val_ret_X -eq 0 ] ; then
        declare_beop_debian
        ib_val_ret_deb=$?
    else
        ib_val_ret_deb=0
    fi

    if [ $ib_val_ret_X -ne 0 ]; then
        return $ib_val_ret_X
    elif [ $ib_val_ret_cons -ne 0 ]; then
        return $ib_val_ret_cons
    else
        return $ib_val_ret_deb
    fi
}


# Désinstallation de la disposition Béop du système
desinstalle_beop() {
    # Rétablissement des versions sauvegardées du fichier des dispositions du
    # français et des fichiers de déclaration
    for db_fich_actuel in $as_fich_fr $as_rep_rules/* $as_fich_debian; do
        # On évite le cas où * ne serait pas développé…
        [ -e "$db_fich_actuel" ] || continue
        # On évite les liens.
        [ -L "$db_fich_actuel" ] && continue
        # On évite les fichiers qui n’ont pas une version sauvegardée.
        db_fich="${db_fich_actuel}.sans_beop"
        [ -e "$db_fich" ] || continue

        # Si le fichier actuel contient bien le beop,
        if grep beop $db_fich_actuel > /dev/null 2>&1; then
            # on le remplace par la version sauvegardée.
            if mv -f $db_fich $db_fich_actuel; then
                echo "$db_fich_actuel remplacé par $db_fich"; echo
            else
                echo "Impossible de remplacer $db_fich_actuel par $db_fich"
                echo "Assurez-vous de lancer la commande en root"; echo
                exit 255
            fi
        # Sinon, c’est qu’il a déjà dû être écrasé par une version plus récente.
        else
            echo "La disposition Béop n’est pas installée dans $db_fich_actuel"
            echo "Ce fichier a peut-être été remplacé lors d’une mise à jour du système"
            echo "Pas de modification"
            echo
        fi
    done

    # On supprime les dispositions définies à part (anciennes versions de X).
    for db_fich in "${as_fich_fr}-beop" "${as_fich_fr}-beop_prog" "${as_fich_fr}-beop_typo"; do
        if [ -e $db_fich ]; then
            if rm -f $db_fich; then
                echo "$db_fich supprimé"; echo
            else
                echo "Impossible de supprimer $db_fich_actuel"
                echo "Assurez-vous de lancer la commande en root"; echo
                exit 255
            fi
        fi
    done

    # Suppression des définitions pour la console Linux
    # On commence par déterminer tous les chemiens possibles.
    for db_rep in "$rep_install/usr/share/kbd/keymaps" "$rep_install/usr/share/keymaps" "$rep_install/usr/lib/kbd/keymaps" "$rep_install/lib/kbd/keymaps"; do
        for db_sous_rep in 'xkb' 'i386' 'i386/beop'; do
            for db_fich in 'fr-beop.map' 'fr-beop_prog.map' 'fr-beop_typo.map' 'fr-beop.map.gz' 'fr-beop_prog.map.gz' 'fr-beop_typo.map.gz'; do
                db_fich_actuel="$db_rep/$db_sous_rep/$db_fich"

                # Si le fichier existe, on le supprime.
                [ -e $db_fich_actuel ] || continue

                if rm -f "$db_fich_actuel"; then
                    echo "Fichier $db_fich_actuel supprimé"; echo
                else
                    echo "Impossible de supprimer $db_fich_actuel"
                    echo "Assurez-vous de lancer la commande en root"; echo
                    exit 255
                fi
            done
        done

        # Le cas échéant, on supprime le répertoire spécifique.
        if [ -d "$db_rep/i386/beop" ]; then
            if rmdir "$db_rep/i386/beop"; then
                echo "Répertoire $db_rep/i386/beop supprimé"; echo
            else
                echo "Impossible de supprimer le répertoire $db_rep/i386/beop"; echo
                echo "Assurez-vous de lancer la commande en root"; echo
                exit 255
            fi
        fi
    done

    return 0
}


# Programme principal

# L’action par défaut est de passer en Béop
action='beop'

# Paramètres par défaut
rep_install=''
version='1.1'
variante='norm'
altgr_sur_win=false
guillemets_avec_espaces_norm=false
guillemets_avec_espaces_typo=false
multimedia_curseur=false
multimedia_pause=false
large=false
couleurs=true
debug=false

# Détermination de l’option large par rapport à la largeur du terminal
tput cols > /dev/null 2>&1 && [ `tput cols` -ge 89 ] && large=true
# Rediriger la sortie d’erreur dans les apostrophes inversées causerait le
# lancement dans un sous-shell non interactif et la valeur indiquée par tput
# serait fausse.

# Détermination de l’action à effectuer et des options tout d’abord d’après le
# nom de la commande (attention : pas de vérification syntaxique)
nom=`basename $0`

# Traitement de l’action
case "$nom" in
    # Si le nom sous lequel la commande a été lancée est azerty
    # ou les touches de repos gauches en Béop, on repasse en Azerty.
    azerty|auei|*_azerty|*-azerty)
        action='azerty'
        ;;
    # S’il contient _install, on installe la disposition sur le système.
    *_install|*_install_*|*_installe|*_installe_*)
        action='installe'
        ;;
    # S’il contient _switch, on bascule entre le Béop et l’Azerty.
    *_switch|*_switch_∗|*_bascule|*_bascule_*)
        action='switch'
        ;;
esac

# Traitement des options (elles peuvent être multiples)

case "$nom" in
    *_1.0|*_1.0_*)
        version='1.0'
        ;;
esac

case "$nom" in
    *_1.1|*_1.1_*)
        version='1.1'
        ;;
esac

case "$nom" in
    *_pr|*_pr_*|*_prog|*_prog_*)
        variante=prog
        ;;
esac

case "$nom" in
    *_ty|*_ty_*|*_typo|*_typo_*)
        variante=typo
        ;;
esac

case "$nom" in
    *_gaen|*_gaen_*)
        guillemets_avec_espaces_norm=true
        ;;
esac

case "$nom" in
    *_gaet|*_gaet_*)
        guillemets_avec_espaces_typo=true
        ;;
esac

case "$nom" in
    *_gae|*_gae_*)
        guillemets_avec_espaces_norm=true
        guillemets_avec_espaces_typo=true
        ;;
esac

case "$nom" in
    *_asw|*_asw_*|*_aow|*_aow_*|*_altgr-sur-win|*_altgr-sur-win_*|_*altgr-on-win|*_altgr-on-win_*|*_altgrsurwin|*_altgrsurwin_*|*_altgronwin|*_altgronwin_*)
        altgr_sur_win=true
        ;;
esac

case "$nom" in
    *_mc|*_mc_*|*_multimedia-cursor|*_multimedia-cursor_*|*_multimedia-curseur|*_multimedia-curseur_*)
        multimedia_curseur=true
        ;;
esac

case "$nom" in
    *_mp|*_mp_*|*_multimedia-pause|*_multimedia-pause_*)
        multimedia_pause=true
        ;;
esac

case "$nom" in
    *_m|*_m_*|*_multimedia|*_multimedia_*)
        multimedia_curseur=true
        multimedia_pause=true
        ;;
esac

case "$nom" in
    *_test*)
        debug=true
        ;;
esac

# Détermination de l’action à effectuer et des options suivant les paramètres
# (le dernier paramètre est prioritaire).
while [ $# -gt 0 ]; do
    case "$1" in
        -h|-help|--help|-aide|--aide|-usage|--usage)
            action='usage'
            ;;
        -map|--map|-carte|--carte)
            action='affiche_carte'
            ;;
        -a|-azerty|--azerty)
            action='azerty'
            ;;
        -b|-beop|--beop)
            action='beop'
            ;;
        -s|-switch|--switch|-bascule|--bascule)
            action='switch'
            ;;
        -install|--install|-installe|--installe)
            action='installe'
            ;;
        -installdir|--installdir|-install-dir|--install-dir|-install_dir|--install_dir|-installerep|--installerep|-installe-rep|--installe-rep|-installe_rep|--installe_rep)
            action='installe'
            rep_install="$2"
            shift
            ;;
        -uninstall|--uninstall|-desinstalle|--desinstalle)
            action='desinstalle'
            ;;
        -uninstalldir|--uninstalldir|-uninstall-dir|--urinstall-dir|-uninstall_dir|--uninstall_dir|-desinstallerep|--desinstallerep|-desinstalle-rep|--desinstalle-rep|-desinstalle_rep|--desinstalle_rep)
            action='desinstalle'
            rep_install="$2"
            shift
            ;;
        -reinstall|--reinstall|-reinstalle|--reinstalle)
            action='reinstalle'
            ;;
        -reinstalldir|--reinstalldir|-reinstall-dir|--reinstall-dir|-reinstall_dir|--reinstall_dir|-reinstallerep|--reinstallerep|-reinstalle-rep|--reinstalle-rep|-reinstalle_rep|--reinstalle_rep)
            action='reinstalle'
            rep_install="$2"
            shift
            ;;
        -1.0|--1.0)
            version='1.0'
            ;;
        -1.1|--1.1)
            version='1.1'
            ;;
        -pr|--pr|-prog|--prog)
            variante='prog'
            ;;
        -ty|--ty|-typo|--typo)
            variante='typo'
            ;;
        -gae|--gae|-guillemets-avec-espaces|-guillemets_avec_espaces|-guillemetsavecespaces|--guillemets-avec-espaces|--guillemets_avec_espaces|--guillemetsavecespaces)
            guillemets_avec_espaces_norm=true
            guillemets_avec_espaces_typo=true
            ;;
        -gaen|--gaen|-guillemets-avec-espaces-norm|-guillemets_avec_espaces_norm|-guillemetsavecespacesnorm|--guillemets-avec-espaces-norm|--guillemets_avec_espaces_norm|--guillemetsavecespaces_norm)
            guillemets_avec_espaces_norm=true
            ;;
        -gaet|--gaet|-guillemets-avec-espaces-typo|-guillemets_avec_espaces_typo|-guillemetsavecespacestypo|--guillemets-avec-espaces-typo|--guillemets_avec_espaces_typo|--guillemetsavecespacestypo)
            guillemets_avec_espaces_typo=true
            ;;
        -asw|--asw|-aow|--aow|-altgr-sur-win|-altgr_sur_win|-altgrsurwin|--altgr-sur-win|--altgr_sur_win|--altgrsurwin|altgr-on-win|-altgr_on_win|-altgronwin|--altgr-on-win|--altgr_on_win|--altgronwin)
            altgr_sur_win=true
            ;;
        -mc|--mc|-multimedia-cursor|--multimedia-cursor|-multimedia-curseur|--multimedia-curseur)
            multimedia_curseur=true
            ;;
        -mp|--mp|-multimedia-pause|--multimedia-pause)
            multimedia_pause=true
            ;;
        -m|--m|-multimedia|--multimedia)
            multimedia_curseur=true
            multimedia_pause=true
            ;;
        -large|--large)
            large=true
            ;;
        -etroit|-etroite|--etroit|--etroite)
            large=false
            ;;
        -clair|-claire|--clair|--claire)
            couleurs="true fond_clair"
            ;;
        -sombre|--sombre)
            couleurs="true fond_sombre"
            ;;
        *)
            usage "$version" "$variante" "$altgr_sur_win" "$large" "$couleurs"
            echo; echo "Paramètre non reconnu : $1"; echo
            exit 255
            ;;
    esac
    shift
done

# Si l’action est d’afficher l’usage ou la carte, on le fait tout de suite et on
# sort (les opérations qui suivent ne sont pas utiles pour ça).
case "$action" in
    usage|affiche_carte)
        $action "$version" "$variante" "$altgr_sur_win" "$large" "$couleurs"
        exit 0
        ;;
esac

# Vérification de la disponibilité de grep -E
if echo ab | grep -E '(a)(b)' > /dev/null 2>&1; then
    egrep='grep -E'
elif echo ab | egrep '(a)(b)' > /dev/null 2>&1; then
    egrep='egrep'
else
    echo; echo "ERREUR !"
    echo "Ni grep -E ni egrep ne sont fonctionnels."; echo
    exit 255
fi

# Si l’action est switch,
if [ "$action" = "switch" ]; then
    # on passe en Azerty si l’on était en Béop, sinon en Béop.
    if [ -n "$DISPLAY" ]; then
        if xkbcomp -xkb -o - $DISPLAY | $egrep '^xkb_symbols.*beop' > /dev/null; then
            action=azerty
        else
            action=beop
        fi
    elif [ "$TERM" = "linux" ]; then
        if dumpkeys | $egrep '^[[:space:]]*keycode[[:space:]]+19[[:space:]]*=[[:space:]]*\+p' > /dev/null; then
            action=azerty
        else
            action=beop
        fi
    fi
fi

# Si l’action consiste à changer de disposition, on vérifie qu’on est sous X.org
# ou sous une console Linux.
if { [ "$action" = "azerty" ] || [ "$action" = "beop" ]; } && [ -z "$DISPLAY" ] && [ "$TERM" != "linux" ]; then
    usage "$version" "$variante" "$altgr_sur_win" "$large" "$couleurs"
    echo; echo "ERREUR : Ce script ne prend en charge que X.org et la console texte Linux."; echo
    exit 255
fi

# On analyse le système
analyse_systeme

# On effectue l’action retenue.
case "$action" in
    azerty)
        if [ "$TERM" = "linux" ]; then
            console_azerty
        fi
        # Éviter la construction [ "$DISPLAY " ] && ... permet d’éviter que la
        # valeur de la condition n’affecte la valeur de retour.
        if [ -n "$DISPLAY" ]; then
            azerty
        fi
        ;;
    beop)
        if [ "$TERM" = "linux" ]; then
            console_beop "$variante" "$altgr_sur_win"
        fi
        if [ -n "$DISPLAY" ]; then
            beop "$version" "$variante" "$altgr_sur_win" "$guillemets_avec_espaces_norm" "$guillemets_avec_espaces_typo"
        fi
        ;;
    *installe)
        if [ "$action" = "desinstalle" ] || [ "$action" = "reinstalle" ]; then
            desinstalle_beop
        fi
        if [ "$action" = "installe" ] || [ "$action" = "reinstalle" ]; then
            installe_beop "$version" "$altgr_sur_win" "$guillemets_avec_espaces_norm" "$guillemets_avec_espaces_typo"
        fi
        ;;
esac
