none
[WinForms] Intercepter une touche RRS feed

  • Question

  • Bonjour tout le monde,

    Dans mon application, Form1 n'est visible que par le truchement de sa Notifyicon.

    La touche Ctrl F11 doit déclencher un traitement, avec réinitialisation d'un timer, mais bêtement j'achoppe là-dessus.

    Form1_KeyDown et Form1_KeyPress ne voient rien passer (d'ailleurs le formulaire étant invisible ce n'est pas si étonnant).

    Sur la NotifyIcon, à part BaloonTip je ne vois que des événements de souris.

    La documentation me parle bien de Control.ProcessDialogKey, mais j'ai beau ajouter ceci en tête de module, même avec un point d'arrêt dessus, il ne se passe rien :

    protected override bool ProcessDialogKey(System.Windows.Forms.Keys keyData)

    { return ProcessDialogKey(keyData); }

    Y a-t-il un moyen sans rendre visible le formulaire juste pour ça ?

    mardi 3 décembre 2019 20:57

Réponses

  • Il semblerait bien que j'aie trouvé un moyen, en intégrant les références PresentationCore et WindowsBase (mon premier pas dans WPF à ce que je comprends) :

    private void timer2_Tick(object sender, EventArgs e)
    {
    	if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.F11))
    	{
    		MessageBox.Show("F11");
    	}
    }

    Il reste à intégrer le traitement de la touche Ctrl, mais quand il n'y a plus que ça ...

    J'attends un peu avant de marquer ma réponse, car je suppose qu'on utilisait le clavier avant l'existence de WPF.

    • Modifié Gloops mercredi 4 décembre 2019 04:55
    • Marqué comme réponse Gloops vendredi 6 décembre 2019 09:06
    mercredi 4 décembre 2019 04:55
  • Une des méthodes est avec RegisterHotKey

    Par exemple, test Beep() sur Ctrl + F11 =>

            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern short GlobalAddAtom(string atomName);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    
            public const int MOD_ALT = 0x1;
            public const int MOD_CONTROL = 0x2;
            public const int MOD_SHIFT = 0x4;
            public const int MOD_WIN = 0x8;
            public const int MOD_NOREPEAT = 0x4000;
    
            public const int WM_HOTKEY = 0x312;

            private short nAtom;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                nAtom = GlobalAddAtom("HotKey");
                RegisterHotKey(Handle, nAtom, MOD_CONTROL, (int)Keys.F11);
            }
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_HOTKEY)
                {
                    if (m.WParam == (IntPtr)nAtom)
                    {
                        Console.Beep(5000, 100);
                    }
                }
                else
                    base.WndProc(ref m);
            }
    
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                UnregisterHotKey(Handle, nAtom);
            }

    • Marqué comme réponse Gloops vendredi 6 décembre 2019 09:06
    mercredi 4 décembre 2019 09:35

Toutes les réponses

  • Il semblerait bien que j'aie trouvé un moyen, en intégrant les références PresentationCore et WindowsBase (mon premier pas dans WPF à ce que je comprends) :

    private void timer2_Tick(object sender, EventArgs e)
    {
    	if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.F11))
    	{
    		MessageBox.Show("F11");
    	}
    }

    Il reste à intégrer le traitement de la touche Ctrl, mais quand il n'y a plus que ça ...

    J'attends un peu avant de marquer ma réponse, car je suppose qu'on utilisait le clavier avant l'existence de WPF.

    • Modifié Gloops mercredi 4 décembre 2019 04:55
    • Marqué comme réponse Gloops vendredi 6 décembre 2019 09:06
    mercredi 4 décembre 2019 04:55
  • Une des méthodes est avec RegisterHotKey

    Par exemple, test Beep() sur Ctrl + F11 =>

            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern short GlobalAddAtom(string atomName);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    
            public const int MOD_ALT = 0x1;
            public const int MOD_CONTROL = 0x2;
            public const int MOD_SHIFT = 0x4;
            public const int MOD_WIN = 0x8;
            public const int MOD_NOREPEAT = 0x4000;
    
            public const int WM_HOTKEY = 0x312;

            private short nAtom;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                nAtom = GlobalAddAtom("HotKey");
                RegisterHotKey(Handle, nAtom, MOD_CONTROL, (int)Keys.F11);
            }
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_HOTKEY)
                {
                    if (m.WParam == (IntPtr)nAtom)
                    {
                        Console.Beep(5000, 100);
                    }
                }
                else
                    base.WndProc(ref m);
            }
    
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                UnregisterHotKey(Handle, nAtom);
            }

    • Marqué comme réponse Gloops vendredi 6 décembre 2019 09:06
    mercredi 4 décembre 2019 09:35
  • Bonjour,

    Si je résume bien, on a le choix entre l'appel aux API Windows, et l'appel à WPF ?

    L'appel à WPF a été vite fait une fois que j'ai su quelles références appeler, est-ce qu'il pose un problème d'optimisation si WPF n'est pas utilisé pour autre chose ? La taille du programme va beaucoup varier peut-être ?

    Je dois préciser que je vais utiliser des API Windows, via un fichier déjà prêt, pour sélectionner les fenêtres par une partie de l'intitulé. De mémoire je dirais que pour gérer le clavier il faudrait que je fasse un deuxième fichier d'appel.

    jeudi 5 décembre 2019 00:01
  • Même en WPF, la solution standard est avec RegisterHotKey :

    WPF: Implementing Global Hot Keys

    jeudi 5 décembre 2019 07:14
  • Avec IsKeyDown ça marche. J'ai testé ça pendant que je lisais mes mails ou le web. Alors sous Firefox je presse Ctrl F11, parce que F11 tout seul a une autre signification pour Firefox.

    Et tout ce que j'ai fait en amont c'est mettre les références PresentationCore et WindowsBase dans le projet.

    C'est pour ça que je me demandais si ça avait un gros impact sur la taille du programme, ça pourrait être ça l'inconvénient.

    jeudi 5 décembre 2019 08:25
  • Avec IsKeyDown ça marche. 

    Mais c'est dans un timer d'après

    private voidtimer2_Tick(objectsender, EventArgse)

    jeudi 5 décembre 2019 10:22
  • En effet. Je ne me suis pas cassé la tête sur ce coup-là.

    jeudi 5 décembre 2019 10:26
  • En définitive, il se peut que ce qui fasse pencher la balance du côté des API Windows, ne soit pas une histoire de taille du programme, mais de déploiement.

    En mettant PresentationCore.dll et WindowsBase.dll dans le répertoire du programme je me suis débarrassé d'un message qui objectait l'absence de WPF, mais après on me réclame C++.

    Il me semble bien avoir vu un jour un programme d'installation pour le kit d'exécution de C++, mais je n'ai pas dû savoir causer au moteur de recherche, il ne me l'a pas trouvé.

    vendredi 6 décembre 2019 14:13