Wie auf Tastendruck Event reagieren bzw. warten?



  • Hallo, ich habe eine Konsolenanwendung in C# geschrieben, die im Autostart mit Windows startet. Nun möchte ich die STRG Taste drücken, die soll nun von meinem Konsolenprogramm abgefangen und verarbeitet werden, habt ihr eine Idee wie man sowas realisiert?

    Welche Möglichkeiten gäbe es? Threads, KeyListener usw????



  • Servus,

    mir fällt auf anhieb KeyHook ein. Einfach einen KeyHook für die STRG Taste Schreiben.

    Ich hatte vor 1-2 Jahren mal eine Basis KeyHook Klasse geschrieben (Teilweise zusammengesucht, Referenzlinks habe ich aber nicht mehr...):

    public class KeyboardHook 
    {
        #region Constants
    
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x100;
        private const int WM_KEYUP = 0x101;
        private const int WM_SYSKEYDOWN = 0x104;
        private const int WM_SYSKEYUP = 0x105;
    
        #endregion // Constants
    
        #region Structs
    
        public struct KeyboardHookStruct 
        {
            public int VKCode;
            public int ScanCode;
            public int Flags;
            public int Time;
            public int ExtraInfo;
        }
    
        #endregion // Structs
    
        #region Fields
    
        public delegate int KeyboardHookEventHandler(int code, int wParam, ref KeyboardHookStruct lParam);
        private KeyboardHookEventHandler KeyboardHookEvent;
        private ArrayList hookedKeys;
        private IntPtr hhook;
    
        #endregion // Fields
    
        #region Constructors / Dispose
    
        public KeyboardHook() 
        {
            this.hookedKeys = new ArrayList();
            this.hhook = IntPtr.Zero;
            this.KeyboardHookEvent = new KeyboardHookEventHandler( this.HookProcedure );
    
            this.Hook();
        }
    
        ~KeyboardHook() 
        {
            this.Unhook();
        }
    
        #endregion // Constructors / Dispose
    
        #region Native Methods
    
        /// <summary>
        /// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null
        /// </summary>
        /// <param name="idHook">The id of the event you want to hook</param>
        /// <param name="callback">The callback.</param>
        /// <param name="hInstance">The handle you want to attach the event to, can be null</param>
        /// <param name="threadId">The thread you want to attach the event to, can be null</param>
        /// <returns>a handle to the desired hook</returns>
        [DllImport("user32.dll")]
        internal static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHookEventHandler callback, IntPtr hInstance, uint threadId);
    
        /// <summary>
        /// Unhooks the windows hook.
        /// </summary>
        /// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param>
        /// <returns>True if successful, false otherwise</returns>
        [DllImport("user32.dll")]
        internal static extern bool UnhookWindowsHookEx(IntPtr hInstance);
    
        /// <summary>
        /// Calls the next hook.
        /// </summary>
        /// <param name="idHook">The hook id</param>
        /// <param name="nCode">The hook code</param>
        /// <param name="wParam">The wparam.</param>
        /// <param name="lParam">The lparam.</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        internal static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref KeyboardHookStruct lParam);
    
        /// <summary>
        /// Loads the library.
        /// </summary>
        /// <param name="lpFileName">Name of the library</param>
        /// <returns>A handle to the library</returns>
        [DllImport("kernel32.dll")]
        internal static extern IntPtr LoadLibrary(string lpFileName);
    
        #endregion
    
        #region Events
    
        public event KeyEventHandler KeyDown;
        public event KeyEventHandler KeyUp;
    
        #endregion
    
        #region Methods
    
        /// <summary>
        /// Installs the global hook
        /// </summary>
        public void Hook() 
        {
            IntPtr hInstance = LoadLibrary("User32");
    
            this.hhook = SetWindowsHookEx(WH_KEYBOARD_LL, this.KeyboardHookEvent, hInstance, 0);
        }
    
        /// <summary>
        /// Uninstalls the global hook
        /// </summary>
        public void Unhook() 
        {
            UnhookWindowsHookEx(this.hhook);
        }
    
        /// <summary>
        /// The callback for the keyboard hook
        /// </summary>
        /// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param>
        /// <param name="wParam">The event type</param>
        /// <param name="lParam">The keyhook event information</param>
        /// <returns></returns>
        public int HookProcedure(int code, int wParam, ref KeyboardHookStruct lParam) 
        {
            if ( code >= 0 ) 
            {
                Keys key = (Keys)lParam.VKCode;
                if ( this.hookedKeys.Contains(key) ) 
                {
                    KeyEventArgs kea = new KeyEventArgs(key);
                    if ( (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null) ) 
                    {
                        this.KeyDown(this, kea) ;
                    } 
                    else if ( (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null) ) 
                    {
                        this.KeyUp(this, kea);
                    }
    
                    if ( kea.Handled )
                        return 1;
                }
            }
    
            return CallNextHookEx(hhook, code, wParam, ref lParam);
        }
    
        #endregion // Methods
    
        #region Properties
    
        public ArrayList HookedKeys
        {
            get
            {
                return this.hookedKeys;
            }
            set
            {
                this.hookedKeys = value;
            }
        }
    
        #endregion // Properties
    }
    

    Einbindung des Ganzen:

    KeyboardHook keyboardHook = new KeyboardHook();
    
    keyboardHook.KeyDown += new KeyEventHandler(OnKeyboardHookKeyDown);
    keyboardHook.KeyUp += new KeyEventHandler(OnKeyboardHookKeyUp);
    
    // Hier deine STRG Taste
    keyboardHook.HookedKeys.Add(Keys.ControlKey);
    
    private void OnKeyboardHookKeyDown(object sender, KeyEventArgs e)
    {
        e.Handled = true; // Taste generell blocken
    }
    
    private void OnKeyboardHookKeyUp(object sender, KeyEventArgs e)
    {
        e.Handled = true; // Taste generell blocken
    }
    

    Das KeyUp und das KeyDown Event wirst du nun für alle Tasten die in HookedKeys sind mitbekommen.

    gruß
    Hellsgore



  • Hi, vielen Dank 🙂

    Hab mich ein wenig umgeschaut und raus gefunden das man auch die API-Funktion RegisterHotKey verwenden kann, hier ein Beispiel:

    http://www.pinvoke.net/default.aspx/user32.RegisterHotKey



  • Ich muss euch nochmal stören, kriege es nicht hin in der Konsole das Beispiel von hier auszuführen: http://www.pinvoke.net/default.aspx/user32.RegisterHotKey

    Ich habe die Klasse GlobalHotkeys in mein Projekt aufgenommen, in meiner Programm Klasse habe ich nun folgendes gemacht:

    class Program : Form
        {
            private GlobalHotkeys hotkey;
    
            public Program()
            {            
                hotkey = new GlobalHotkeys();
                hotkey.RegisterGlobalHotKey((int)Keys.ControlKey, GlobalHotkeys.MOD_CONTROL);
                hotkey.UnregisterGlobalHotKey();
            }
    
            protected override void WndProc(ref Message m)
            {
                const int WM_HOTKEY = 0x0312;
    
                switch (m.Msg)
                {
                    case WM_HOTKEY:
                        if ((short)m.WParam == hotkey.HotkeyID)
                        {
                            MessageBox.Show("TEST");
                            // do your thing
                        }
                        break;
                    default:
                        base.WndProc(ref m);
                        break;
                }            
            }
    
            [STAThread]
            static void Main(string[] args)
            {
                Application.Run(new Program());            
            }
        }
    

    Darf man Konsolenanwendungen von Form ableiten wie ich das gemacht habe??
    wieso passier nix wenn ich STRG drücke??



  • Servus,

    wusste garnicht das es sowas gibt... lustig...

    hotkey.RegisterGlobalHotKey((int)Keys.ControlKey, GlobalHotkeys.MOD_CONTROL);
    hotkey.UnregisterGlobalHotKey();
    

    Es passiert nichts, weil du nach dem Register wieder ein "Un"register aufrufst...
    Macht nicht viel Sinn 😉

    gruß
    Hellsgore



  • Wie kann ich nun auf deinen Code reagieren wenn die STRG Taste gedrückt wird, will zum Test ein String in der Konsole ausgeben und muss ich noch eine Schleife einbauen die ständig wartet?

    public class Programm
        {
            static void OnKeyboardHookKeyDown(object sender, KeyEventArgs e)
            {
                e.Handled = true; // Taste generell blocken
            }
    
            public static int Main(String[]args)
            {
                KeyboardHook keyboardHook = new KeyboardHook();
    
                keyboardHook.KeyDown += new KeyEventHandler(OnKeyboardHookKeyDown);            
    
                // Hier deine STRG Taste
                keyboardHook.HookedKeys.Add(Keys.Control);
    
                return 0;
            }        
        }
    


  • Servus,

    du reagierst schon auf den Tastendruck. Allerdings springst du nach dem Initialisiern des Hooks direkt mit "return 0" aus deiner Main wieder heraus. Wird die STRG Taste gedrückt, wird das Event KeyDown gefeuert. Entweder baust du die Klasse um, dass du auf eine Taste in einer Endlosschleife wartest oder du lässt dein Programm nach der Hook Initialisierung solange laufen, bis das Event gefeuert wird.

    gruß
    Hellsgore



  • Hi, hab letztens wieder das Programm rausgesucht, nun habe ich in der Main mit der Applicatio.Run() die Nachrichtenschleife eingeleitet, nun wenn ich mit dem Debugger durch den Code gehe bin ich ständig in der HookProcedure() Funktion, aber er springt nicht hier rein:

    if (this.hookedKeys.Contains(key))
    ...
    

    Ich komme garnicht dazu in der Konsole auf eine Taste zu drücken da ständig der Debugger die Funktion durchläuft. Für WinForms gibt es etliche Beispiele doch für die Konsole hab ich kein brauchbares gefunden, hoffe du kannst mir noch einmal weiterhelfen, möchte es gerne hinbekommen.

    MfG



  • Servus,

    beim Debuggen beisst sich die Katze in den Schwanz... Du landes im Debugger und drückst wahrscheinlich auf "F5" und was passiert? Genau, ein Key Event wird gefeuert und er landet wieder darin 😉

    Sowas mache ich eigentlich nicht, da ich dir schon dein fertiges Programm fast geschrieben habe aber Ausnahmen bestätigen die Regel...

    Hier hast du dein Tool...

    class Program
    {
        private static void OnKeyboardHookKeyDown(object sender, KeyEventArgs e)
        {
            Console.WriteLine("Uhh, its so amazing... KeyDown event fired!!!");
            e.Handled = true; // Taste generell blocken
            Console.WriteLine(string.Format("{0} blocked...", e.KeyCode));
        }
    
        private static void OnKeyboardHookKeyUp(object sender, KeyEventArgs e)
        {
            Console.WriteLine("Uhh, its so amazing... KeyUp event fired!!!");
            e.Handled = true; // Taste generell blocken
            Console.WriteLine(string.Format("{0} blocked...", e.KeyCode));
        } 
    
        private static void Main(string[] args)
        {
            KeyboardHook keyboardHook = new KeyboardHook();
    
            keyboardHook.KeyDown += new KeyEventHandler(OnKeyboardHookKeyDown);
            keyboardHook.KeyUp += new KeyEventHandler(OnKeyboardHookKeyUp);
    
            // Hier deine linke STRG Taste
            keyboardHook.HookedKeys.Add(Keys.LControlKey);
    
            // Hier deine rechte STRG Taste
            keyboardHook.HookedKeys.Add(Keys.RControlKey);
    
            Application.Run();
        }
    }
    

    gruß
    Hellsgore



  • Vielen Dank 🙂

    Ich habe nun in der OnKeyboardHookKeyDown() Funktion eine eigene MessageBox mit einem OK Button erstellt, also wenn die STRG gedrückt wird, poppt dieses Fenster aus. Wie kann man weitere Fenster blockieren wenn jemand wieder die STRG drückt, welche Möglichkeiten gibt es??

    private static void OnKeyboardHookKeyDown(object sender, KeyEventArgs e)
            {
                e.Handled = true; // Taste generell blocken
    
                using (AbortMessage f = AbortMessage.getInstance())
                {
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        //Close current Thread
                        _isExit = true;
    
                        //Close Application Message Loop
                        Application.Exit();
                    }
                }
            }
    


  • Servus,

    jetzt solltest du aber mal ganz gut nachdenken. Das ist sehr simpel und einfach. Stichwort Variable / Feld vom Typ boolean.

    gruß
    Hellsgore



  • Schon erledigt, habs mit Singleton Pattern erstellt, welcher die Instanz der Klasse übergibt.

    Was mir aufgefallen ist, dass die Reaktion der Fenster sehr träge ist. Wenn das Fenster erstellt wird und ich gleich mit der Maus auf den OK Button klicken will, dauert es ungefähr 4 Sekunden bis das Fenster darauf reagiert, liegt es am hook??



  • Ich möchte gern das Programm erweitern, es soll diesmal auf 3 Tasten gewartet werden wie z.B. STRG+SHIFT+1. Die Tasten habe ich registriert, nun muss in der HookProcedure() auf drei Tasten gewartet werden, wie bevor das Event gefeuert wird. Ich bin mir nicht sicher, aber ich glaube folgender Teil müsste geändert werden:

    Keys key = (Keys)lParam.VKCode;
    if (this.hookedKeys.Contains(key))
    { ..
    

    Es soll nicht auf eine sondern 3 registrierte Tasten gewartet werden. Wie sollte man das lösen?


Anmelden zum Antworten