Bonjour à tous,

J’ai récemment décidé de passer au clavier bépo (toujours en phase d’apprentissage et d’exercices quotidien).

Avec un collègue on voulait juste générer les drivers nous-mêmes, rapidement et sans que ce soit trop complexe. On est parvenu à une méthode tout en un, mais uniquement pour les bidouilleurs.

Du coup je propose une méthode « simple » de génération depuis MSKLC (Microsoft Keyboard Layout Creator) en faisant sauter la limitation du problème du tiret bas sur la barre d’espace.

Attention : cela fait sauter toutes limitations de la barre d’espace.

1) Téléchargez et installez MSKLC (dernière version en date : 1.4.6000.2)
2) Téléchargez le fichier bepo.klc

Une fois MSKLC installé, faites une copie du binaire principal (msklc.exe) et renommez le (par ex. en msklc2.exe).

Ouvrez la copie du programme (msklc2.exe) et faites une recherche dans un éditeur hexadécimal sur les octets suivants :
• 2D 05 04 2D 02 17 2A 17 0A

Remplacez le 0A par 2A, sauvegardez. Vous pouvez maintenant ouvrir le fichier bepo.klc et générer les drivers avec, directement !

Explication sur la manipulation

Comme indiqué sur le wiki ( bepo.fr/wiki/Pilote_Windows#MSKLC_et_pilote_b.C3.A9po ), lorsqu’on essaye de générer les drivers depuis le fichier bepo.klc avec MSKLC on obtient l’erreur suivante :
ERROR: 'VK_SPACE' in Shift State 'Ctl+Alt' must be made up of white space character(s), but is defined as '_' (U+005f) instead.
Msklc.exe est un programme .NET. On peut donc le décompiler avec des décompileurs spécialisés comme ILSpy (gratuit), dotpeek (gratuit) ou d’autres.

On trouve effectivement le message d’erreur dans les ressources du programme :
  <data name="SpaceKeyNeedsWhiteSpaceCharacters" xml:space="preserve">
    <value>'{0}' in Shift State '{1}' must be made up of white space character(s), but is defined as '{2}' ({3}) instead.</value>
  </data>
On cherche où est référencée l’erreur dans le programme, on trouve une seul occurrence à « SpaceKeyNeedsWhiteSpaceCharacters » :
// Microsoft.Globalization.Tools.KeyboardLayoutCreator.Accept
private bool VerifySpaceBarIntegrity(ShiftState ss, bool fMustBeDefined)
{
    if (ss.Characters == null || (ss.Characters.Length == 0 && !fMustBeDefined))
    {
        return true;
    }
    bool result = true;
    if (ss.Characters.Length == 0)
    {
        this.WriteErrorToLogFile("SpaceKeyCharacterMustBeDefined", new string[]
        {
            "VK_" + Utilities.VkStringOfIvk((int)ss.VK),
            this.m_stStateLabel[(int)ss.State]
        });
        result = false;
    }
    else if (!Utilities.IsSpacing(ss.Characters))
    {
        this.WriteErrorToLogFile("SpaceKeyNeedsWhiteSpaceCharacters", new string[]
        {
            "VK_" + Utilities.VkStringOfIvk((int)ss.VK),
            this.m_stStateLabel[(int)ss.State],
            ss.Characters,
            Utilities.FromCharacterToUPlusForm(ss.Characters)
        });
        result = false;
    }
    return result;
}
Notez que la fonction coupable du message d'erreur se nomme "VerifySpaceBarIntegrity" 🙂

Avec ildasm (disponible avec Visual Studio), on peut désassembler le programme au niveau IL (Intermediate Language) :
  .method private hidebysig instance bool 
          VerifySpaceBarIntegrity(class Microsoft.Globalization.Tools.KeyboardLayoutCreator.ShiftState ss,
                                  bool fMustBeDefined) cil managed
  // SIG: 20 02 02 12 80 90 02
  {
    // Method begins at RVA 0x41cc
    // Code size       203 (0xcb)
    .maxstack  6
    .locals init (bool V_0,
             string[] V_1,
             string[] V_2)
    IL_0000:  /* 03   |                  */ ldarg.1
    IL_0001:  /* 6F   | (06)0001CF       */ callvirt   instance string Microsoft.Globalization.Tools.KeyboardLayoutCreator.ShiftState::get_Characters()
    IL_0006:  /* 2C   | 10               */ brfalse.s  IL_0018

    IL_0008:  /* 03   |                  */ ldarg.1
    IL_0009:  /* 6F   | (06)0001CF       */ callvirt   instance string Microsoft.Globalization.Tools.KeyboardLayoutCreator.ShiftState::get_Characters()
    IL_000e:  /* 6F   | (0A)000025       */ callvirt   instance int32 [mscorlib]System.String::get_Length()
    IL_0013:  /* 2D   | 05               */ brtrue.s   IL_001a

    IL_0015:  /* 04   |                  */ ldarg.2
    IL_0016:  /* 2D   | 02               */ brtrue.s   IL_001a

    IL_0018:  /* 17   |                  */ ldc.i4.1
    IL_0019:  /* 2A   |                  */ ret

    IL_001a:  /* 17   |                  */ ldc.i4.1
    IL_001b:  /* 0A   |                  */ stloc.0
…
Sur la colonne de gauche vous pouvez voir les octets qui constituent le code (et donc les octets recherchés donnés au début de ce message).

Concrètement, remplacer le ‘0x0A’ par ‘0x2A’ remplace une instruction par un ‘return’ direct : le reste du corps de la fonction n’est pas exécuté et donc la vérification sur la barre d’espace aussi. C’est assez « bourrin » et il existe d’autre manières de patcher le code, mais ça fonctionne…

Du coup la fonction ressemble à ça après la modification :
// Microsoft.Globalization.Tools.KeyboardLayoutCreator.Accept
private bool VerifySpaceBarIntegrity(ShiftState ss, bool fMustBeDefined)
{
    return (ss.Characters != null && (ss.Characters.Length != 0 || fMustBeDefined)) || true;
}
La fonction renvoie tout le temps ‘True’ pour le cas qui nous intéresse (il n'y a donc plus aucune vérification sur la barre d'espace, ça peut être problématique dans certains cas j'imagine).

Voilà, je ne sais pas si c'est très utile, mais si jamais ça peut servir à quelqu'un...
Merci pour cette explication, j'avais rencontré le problème il y a peu et avait abandonné la tentative de création d'un layout qui me satisfasse.
J'essayerai ça bientôt.
7 jours plus tard
Testé.
L'erreur n'est effectivement plus visible dans KeyboardVerify.log.
Par contre il est toujours impossible de rajouter un caractère sur la touche espace. Donc si on importe la disposition bépo de base (avec le _ sur la barre espace), ça passe, par contre, si on importe une disposition quelconque et qu'on rajoute le _ sur la barre espace, on a un message d'erreur au moment de cliquer sur « ok ».
Ensuite au moment de générer les dll : 
« CL.EXE returned 1


RC.EXE returned 1


LINK.EXE returned 1 »
Et pas de dll disponible…
Pas encore tout à fait au point donc. Mais je salue l'effort ;-)
5 ans plus tard
Merci énormément, j’ai du mal à croire que ceci ait pu être possible.

J’ai créé ce compte à seul but de vous remercier.

Bien que quatre années plus tard.