web-dev-qa-db-fra.com

C # Comment traduire un keycode virtuel en char?

J'essaie de mapper un keycode virtuel à un char.

Mon code utilise ProcessCmdKey pour écouter WM_KEYDOWN qui me donne accès à la touche enfoncée. Par exemple, lorsque j'appuie sur un guillemet simple, j'obtiens une clé de 222 que je veux faire mapper au clavier 39 qui représente ... vous l'avez deviné ... guillemet simple.

Mon contexte de développement est: - .net Framework 2.0 - UserControl placé dans beaucoup d'endroits

Connaissez-vous la réponse à la question?

23
Horas

N'est-ce pas à cela que sert la classe System.Windows.Form.KeysConverter ?

KeysConverter kc = new KeysConverter();
string keyChar = kc.ConvertToString(keyData);
41
Powerlord

Oui, j'ai utilisé la méthode MapVirtualKey. Mais je m'attendais à plus de détails sur la façon de l'utiliser: quelle directive DllImport utiliser, quelle enum est spécifique pour le mappage sur des caractères, etc.

Je n'aime pas ces réponses où vous google pendant 5 secondes, puis suggérez une solution: le vrai défi est de rassembler toutes les pièces et de ne pas perdre votre temps avec des tonnes de pages MSDN sans échantillon ou d'autres forums de codage afin d'obtenir votre réponse. Pas de socle offensif, mais votre réponse (même bonne) était sans souci puisque j'avais cette réponse avant même de poster ma question sur le forum!

Alors voilà, je vais publier ce que je cherchais - une solution C # prête à l'emploi:

1- Placez cette directive dans votre classe:

[DllImport("user32.dll")]
static extern int MapVirtualKey(uint uCode, uint uMapType);

2- Récupérez votre personnage comme ceci:

  protected override bool ProcessCmdKey(ref Message msg, Keys keyData)      
  {
     const int WM_KEYDOWN = 0x100;

     if (msg.Msg == WM_KEYDOWN)
     {            
        // 2 is used to translate into an unshifted character value 
        int nonVirtualKey = MapVirtualKey((uint)keyData, 2);

        char mappedChar = Convert.ToChar(nonVirtualKey);
     }

     return base.ProcessCmdKey(ref msg, keyData);
  }

Merci de votre attention ... et profitez-en!

25
Horas

Je cherchais quelque chose de similaire, mais j'avais besoin que le caractère soit mappé à la disposition de clavier actuelle. Puisqu'aucune des réponses ci-dessus ne répondait à mes exigences, voici ce que j'ai trouvé.


        public string KeyCodeToUnicode(Keys key)
        {
            byte[] keyboardState = new byte[255];
            bool keyboardStateStatus = GetKeyboardState(keyboardState);

            if (!keyboardStateStatus)
            {
                return "";
            }

            uint virtualKeyCode = (uint)key;
            uint scanCode = MapVirtualKey(virtualKeyCode, 0);
            IntPtr inputLocaleIdentifier = GetKeyboardLayout(0);

            StringBuilder result = new StringBuilder();
            ToUnicodeEx(virtualKeyCode, scanCode, keyboardState, result, (int)5, (uint)0, inputLocaleIdentifier);

            return result.ToString();
        }

        [DllImport("user32.dll")]
        static extern bool GetKeyboardState(byte[] lpKeyState);

        [DllImport("user32.dll")]
        static extern uint MapVirtualKey(uint uCode, uint uMapType);

        [DllImport("user32.dll")]
        static extern IntPtr GetKeyboardLayout(uint idThread);

        [DllImport("user32.dll")]
        static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);

10
Ivan Petrov

Après avoir lu et testé certaines des réponses fournies, j'ai pensé suggérer une alternative.

Comme mentionné par MM , System.Windows.KeysConverter ne fournit pas une représentation de caractère de la clé mais plutôt le nom de l'énumération, par ex. "Entrez" au lieu de '\ n'.

La méthode MapVirtualKey suggérée par Horas , en réponse à sa propre question, est un bon point de départ, mais ne prend toujours pas en charge ni le verrouillage des majuscules, ni les caractères saisis avec la touche Maj, par ex. '!', '$' et '>'.

Une alternative à la méthode MapVirtualKey, que j'utilise, est une méthode d'extension pour la classe Keys:

public static char ToChar(this Keys key)
{
    char c = '\0';
    if((key >= Keys.A) && (key <= Keys.Z))
    {
        c = (char)((int)'a' + (int)(key - Keys.A));
    }

    else if((key >= Keys.D0) && (key <= Keys.D9))
    {
        c = (char)((int)'0' + (int)(key - Keys.D0));
    }

    return c;
}

La méthode illustrée ci-dessus prend en charge les caractères alphanumériques. La prise en charge de caractères supplémentaires peut être implémentée avec une instruction switch ou une table de recherche.

7
SongWithoutWords

Je viens d'écrire une amélioration de réponse Ivan Petrov pour afficher une représentation sous forme de chaîne des combinaisons de touches enfoncées dans WPF, voir mon code ci-dessous:

public static string GetKeyString(Key key, ModifierKeys modifiers)
{
    string result = "";
    if (key != Key.None)
    {
        // Setup modifiers
        if (modifiers.HasFlag(ModifierKeys.Control))
            result += "Ctrl + ";
        if (modifiers.HasFlag(ModifierKeys.Alt))
            result += "Alt + ";
        if (modifiers.HasFlag(ModifierKeys.Shift))
            result += "Shift + ";
        // Get string representation
        string keyStr = key.ToString();
        int keyInt = (int)key;
        // Numeric keys are returned without the 'D'
        if (key >= Key.D0 && key <= Key.D9)
            keyStr = char.ToString((char)(key - Key.D0 + '0'));
        // Char keys are returned directly
        else if (key >= Key.A && key <= Key.Z)
            keyStr = char.ToString((char)(key - Key.A + 'A'));
        // If the key is a keypad operation (Add, Multiply, ...) or an 'Oem' key, P/Invoke
        else if ((keyInt >= 84 && keyInt <= 89) || keyInt >= 140)
            keyStr = KeyCodeToUnicode(key);
        result += keyStr;
    }
    return result;
}

private static string KeyCodeToUnicode(Key key)
{
    byte[] keyboardState = new byte[255];
    bool keyboardStateStatus = GetKeyboardState(keyboardState);

    if (!keyboardStateStatus)
    {
        return "";
    }

    uint virtualKeyCode = (uint)KeyInterop.VirtualKeyFromKey(key);
    uint scanCode = MapVirtualKey(virtualKeyCode, 0);
    IntPtr inputLocaleIdentifier = GetKeyboardLayout(0);

    StringBuilder result = new StringBuilder();
    ToUnicodeEx(virtualKeyCode, scanCode, new byte[255], result, (int)5, (uint)0, inputLocaleIdentifier);

    return result.ToString();
}

[DllImport("user32.dll")]
static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);

[DllImport("user32.dll")]
static extern IntPtr GetKeyboardLayout(uint idThread);

[DllImport("user32.dll")]
static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);
2
edupeux

KeysConverter obtient le nom de la clé et non les clés "text" ex: "Num2" au lieu de "2" MapVirtualKey fonctionnera pour l'anglais mais pour les états de documentation des caractères non anglais utilisant MapVirtualKeyEx mais qui nécessite un identificateur de paramètres régionaux qui est chargé par LoadKeyBoardLayout qui nécessite un identifiant de culture constant, mais après avoir trouvé les valeurs id correctes, cela n'a pas fonctionné comme je l'ai essayé, donc finalement j'ai vidé le tout

1
mm.