Skip to content
Sur cette page

Analyse AHK

Analyse détaillée du script clavier AutoHotkey

Cette page présente une analyse complète du script AutoHotkey d'Optimot.[1]

Vous pourrez retrouver la liste des pilotes disponibles au téléchargement directement sur la page Windows d'Optimot.

1. Informations générales et licence

Le script commence par une déclaration de licence MIT avec une clause d'exception:

  • Licence open-source permettant la modification et distribution
  • Exception concernant la disposition du clavier elle-même, qui doit être licenciée séparément
  • Auteur: Jean-Philippe Molla (Gepeto)

2. Configuration initiale

autohotkey
#NoEnv  ; Recommandé pour les performances et la compatibilité
#SingleInstance, force  ; Force une seule instance du script
SendMode Input  ; Mode d'envoi recommandé pour sa vitesse et fiabilité
SetWorkingDir %A_ScriptDir%  ; Assure un répertoire de travail cohérent

Ces directives configurent l'environnement d'exécution:

  • #NoEnv: Améliore la compatibilité en n'accédant pas aux variables d'environnement
  • #SingleInstance, force: Empêche l'exécution de plusieurs instances du script
  • SendMode Input: Utilise une méthode plus fiable pour envoyer les touches
  • SetWorkingDir: Définit le répertoire de travail pour les chemins relatifs

3. Variables globales

autohotkey
enableNotifications := True  ; Active les notifications
enableAltLeft := False       ; Désactive la modification avec Alt gauche
lockLayer := False           ; Désactive le verrouillage sur modificateur

Ces variables contrôlent le comportement de base du script:

  • enableNotifications: Affiche des info-bulles lors des changements de couche
  • enableAltLeft: Active des caractères spéciaux avec la touche Alt gauche
  • lockLayer: Maintient la couche active après avoir tapé un caractère

4. Système de localisation

Le script définit plusieurs variables pour les textes affichés dans l'interface:

autohotkey
MenuNotifications := "Notifications"
MenuLockModifier := "Verrouillage sur modificateur"
MenuAltLeftModifier := "Geek sur Alt Gauche"
MenuSuspend := "Mettre en pause"
MenuExit := "Quitter"

Cela facilite la traduction de l'interface sans modifier le code principal.

5. Gestion de la configuration

Le script utilise un fichier INI pour sauvegarder et charger les préférences:

autohotkey
baseName := RegExReplace(A_ScriptName, "\.\w{3}$", "")
iniFile := baseName ".ini"

if FileExist(iniFile) {
  ; Lecture des paramètres...
}

Paramètres sauvegardés:

  • ExcludeAppTitles: Applications où le script est désactivé
  • Notifications: État des notifications
  • LockLayer: État du verrouillage de couche
  • AltLeftEnabled: État de la touche Alt gauche
  • ControlLayer: Disposition de base (AZERTY, QWERTY, par défaut)

6. Structure des couches du clavier

6.1. Table d'indexation

autohotkey
rcindex := {0x29: 1, 0x02: 2, 0x03: 3, ...}

Cette table associe les codes de scan des touches (en hexadécimal) à des indices utilisés dans les tableaux de caractères.

6.2. Couches de contrôle

autohotkey
qwerty_control := ["", "1", "2", "3", "4", ...]
azerty_control := ["", "1", "2", "3", "4", ...]
none_control := ["`", "1", "2", "3", "4", ...]

Ces tableaux définissent les caractères de base pour différentes dispositions lorsqu'on utilise la touche Ctrl.

6.3. Couches principales et modificateurs

autohotkey
none := {"default": [...], "shift": [...], "alt": [...], "altshift": [...]}

Structure des couches:

  • Chaque couche est un objet avec quatre états: default, shift, alt, altshift
  • Chaque état contient un tableau de caractères correspondant aux touches du clavier
  • Les caractères sont représentés en Unicode (\u....)

6.4. Couches spéciales

Le script définit plus de 50 couches spéciales comme:

  • _0fd36: Caractères avec accent circonflexe
  • _c763e: Caractères cyrilliques
  • _c1125: Flèches et symboles directionnels
  • _a65b9: Symboles monétaires
  • _97810: Symboles scientifiques
  • _49b23: Caractères grecs

À la fin, toutes ces couches sont regroupées dans un objet layers:

autohotkey
layers := {"none": none, "cir+": _0fd36, "cir-": _d3951, ...}

7. Initialisation et menu système

autohotkey
initMenu()

Cette fonction crée un menu dans la barre d'état système avec:

  • Option pour activer/désactiver les notifications
  • Option pour le verrouillage de couche
  • Option pour activer Alt gauche
  • Sous-menu pour choisir la disposition (AZERTY, QWERTY, défaut)
  • Options pour suspendre/quitter le script

8. Intercepteurs de touches

autohotkey
$*SC29::ScanCodeProcess()
$*SC02::ScanCodeProcess()
...
$*SC39::ScanCodeProcess()

Fonctionnement:

  • $: Empêche le script de se déclencher lui-même
  • *: Fonctionne même si des modificateurs sont enfoncés
  • SC##: Code de scan de la touche
  • Toutes les touches redirigent vers la même fonction de traitement

9. Le modèle de machine à états du script

La fonction ScanCodeProcess() est conçue selon le principe d'une machine à états finie, ce qui constitue une approche particulièrement élégante pour gérer la complexité des entrées clavier tout en évitant les problèmes de récursivité.

9.1. Principes de la machine à états

Une machine à états finie comporte:

  • Des états (ici: couches du clavier, combinaisons de modificateurs)
  • Des entrées (ici: touches pressées)
  • Des transitions (ici: changements de couche)
  • Des actions (ici: envoi de caractères)

ScanCodeProcess() implémente ce modèle en:

  1. Capturant l'état actuel (touches enfoncées, modificateurs actifs, couche courante)
  2. Déterminant l'état suivant (changement de couche ou envoi de caractère)
  3. Effectuant la transition appropriée
  4. Revenant à l'état initial si nécessaire

9.2. Mécanismes anti-récursivité

autohotkey
$*SC02::ScanCodeProcess()  ; Le préfixe $ empêche la récursivité

Le préfixe $ est fondamental: il indique à AutoHotkey de ne pas déclencher ce raccourci lorsque la touche est envoyée programmatiquement par Send. Sans cela, le script entrerait dans une boucle infinie:

  1. L'utilisateur appuie sur "A"
  2. Le script intercepte cette touche et envoie "B"
  3. Sans le préfixe $, l'envoi de "B" déclencherait à nouveau le script
  4. Le script enverrait un autre caractère
  5. Et ainsi de suite...

De plus, l'utilisation de SendLevel dans certaines fonctions permet de contrôler davantage le niveau d'interception, offrant une couche supplémentaire de protection contre la récursivité.

9.3. Structure de contrôle non-linéaire

autohotkey
ScanCodeProcess() {
  ; Détermination de l'état
  if altl && none_altl && enableAltLeft {
    ; Traitement Alt gauche
    return
  } else if altgr {
    state := "alt"
  } else if ctrl {
    ; Traitement Ctrl
    return
  }
  
  ; Sélection du caractère basée sur l'état actuel
  map := layers[lockedLayer]
  rcvalues := map[state]
  render := rcvalues[index]
  
  ; Transition d'état ou action
  isSubLayer := RegExMatch(render, "„([a-z]+)"", layer)
  if isSubLayer {
    SwitchLayer(layer1)  ; Transition vers un nouvel état
  } else {
    SendValue(render)    ; Action (envoi du caractère)
    if !(lockLayer and capsLock) {
      SwitchLayer()      ; Retour à l'état initial
    }
  }
}

Ce code illustre les principes de la machine à états:

  • Détermination de l'état: Analyse des modificateurs actifs
  • Sélection basée sur l'état: Choix du caractère selon la couche et l'état
  • Transitions conditionnelles: Changement de couche si nécessaire
  • Actions: Envoi du caractère approprié
  • Retour à l'état initial: Réinitialisation de la couche sauf si verrouillée

9.4. Avantages de cette architecture pour un pilote clavier

  1. Évitement des boucles infinies: Le modèle de machine à états prévient naturellement la récursivité.

  2. Gestion élégante de la complexité: Des combinaisons potentiellement infinies de touches et modificateurs sont réduites à un nombre fini d'états.

  3. Modularité: Chaque couche peut être définie indépendamment, facilitant l'extension du script.

  4. Performance: Les décisions sont prises à travers une structure conditionnelle claire plutôt que par des appels récursifs coûteux.

  5. Prévisibilité: Le comportement du script est déterministe, ce qui facilite le débogage.

9.5. Applications de ce modèle à d'autres types de pilotes

Cette approche par machine à états peut être transposée à d'autres contextes:

  • Systèmes de saisie complexes: Méthodes d'entrée asiatiques (IME) où plusieurs frappes produisent un caractère
  • Interfaces gestuelles: Traduction de séquences de mouvements en actions
  • Périphériques adaptés: Interfaces d'accessibilité pour personnes en situation de handicap
  • Émulation matérielle: Conversion entre différents protocoles ou formats d'entrée

Dans tous ces cas, la machine à états offre un cadre conceptuel robuste pour gérer des interactions complexes tout en évitant les effets secondaires indésirables comme la récursivité ou les états incohérents.

10. Fonctions principales

10.1. GetValue et SendValue

autohotkey
GetValue(value) {
  isUnicode := RegExMatch(value, "^\\u([a-zA-Z0-9]+)$", hex)
  if isUnicode {
    value := "U+" hex1
    if hex1 = 0008 {
      SendLevel, 1
      Send, {Backspace}
      value :=
    } 
  }
  Return, value
}

SendValue(value) {
  foundUnicode := InStr(value, "\u")
  if foundUnicode {
    values := StrSplit(value, "\u")
    for k, v in values {
      if (v != "") {
        if v = 0008 {
          SendLevel, 1
          Send, {Backspace}
        } else {
          v := "U+" v
          Send, {%v%}
        }
      }
    }
  } else {
    Send, {%value%}
  }
}

Ces fonctions:

  • Convertissent les codes Unicode (\u....) en format utilisable par AutoHotkey
  • Gèrent les cas spéciaux comme la touche Retour arrière
  • Envoient les caractères au système

10.2. SwitchLayer

autohotkey
SwitchLayer(layer = "") {
  global layers, lockedLayer
  if !layer or !layers.HasKey(layer) {
    lockedLayer := "none"
  } else {
    lockedLayer := layer
    ShowTrayTip(layer)
  }
}

Cette fonction:

  • Change la couche active du clavier
  • Réinitialise à la couche par défaut si aucune couche n'est spécifiée
  • Affiche une notification du changement de couche

10.3. ScanCodeProcess

C'est la fonction principale qui traite les touches pressées:

autohotkey
ScanCodeProcess() {
  ; Détermine quelle touche a été pressée
  ; Vérifie les modificateurs actifs (Shift, Alt, Ctrl)
  ; Sélectionne la couche et l'état appropriés
  ; Envoie le caractère correspondant ou change de couche
}

Étapes de traitement:

  1. Identifie la touche pressée et les modificateurs actifs
  2. Gère les cas spéciaux (touche Windows, Ctrl)
  3. Détermine l'état (default, shift, alt, altshift)
  4. Consulte la couche active pour trouver le caractère correspondant
  5. Vérifie si le caractère est un changement de couche
  6. Envoie le caractère ou change de couche
  7. Réinitialise la couche si nécessaire

11. Gestion des touches spéciales

autohotkey
$Esc::        ; SC01
$End::        ; SC4f
$Home::       ; SC47
$Delete::     ; SC53
$Backspace::  ; SC0e
  key := SubStr(A_ThisHotkey, 2) ; removing $
  if (key != "Delete" and key != "Backspace") {
    SwitchLayer()
  }
  SendLevel, 1
  Send, {%key%}
return

Ces touches ont un comportement spécial:

  • Échap, Fin, Début: Réinitialisent la couche active puis effectuent leur action normale
  • Suppr, Retour arrière: Effectuent uniquement leur action normale sans réinitialiser la couche

12. Workflow complet

  1. Initialisation:

    • Chargement de la configuration depuis le fichier INI
    • Définition des couches et des correspondances de touches
    • Création du menu système
  2. Surveillance des touches:

    • Toutes les touches sont interceptées et redirigées vers ScanCodeProcess()
  3. Traitement d'une touche:

    • Identification de la touche et des modificateurs
    • Détermination de la couche et de l'état
    • Récupération du caractère correspondant
    • Envoi du caractère ou changement de couche
  4. Gestion des options:

    • Le menu système permet de modifier le comportement
    • Les options sont sauvegardées dans le fichier INI

13. Points forts et cas d'utilisation

13.1. Fonctionnalités avancées

  • Système multi-couches: Accès à des milliers de caractères spéciaux
  • Couches contextuelles: Changement temporaire ou permanent de couche
  • Support multiple: Compatible avec QWERTY, AZERTY et autres dispositions
  • Notifications visuelles: Info-bulles lors des changements de couche
  • Exclusion d'applications: Désactivation automatique dans certains programmes

13.2. Cas d'utilisation

Ce script est particulièrement utile pour:

  • Scientifiques: Accès à de nombreux symboles mathématiques et scientifiques
  • Linguistes: Saisie de caractères phonétiques et diacritiques
  • Traducteurs: Utilisation de plusieurs alphabets (latin, grec, cyrillique)
  • Développeurs: Saisie rapide de symboles spéciaux pour la programmation
  • Typographes: Utilisation de symboles typographiques avancés

14. Extensibilité

Le script est conçu pour être facilement extensible:

  • Ajout de nouvelles couches en définissant de nouveaux tableaux
  • Modification des correspondances de touches
  • Personnalisation des options et du comportement

Cette analyse couvre les aspects essentiels du script AutoHotkey pour l'émulation d'une disposition de clavier personnalisée, expliquant sa structure, son fonctionnement et ses cas d'utilisation.


  1. À part quelques corrections ou précisions mineures, cette analyse a été réalisée par Claude.ai ↩︎