none
generelle Frage: key events an windows senden RRS feed

  • Frage

  • Hallo, 

    ist es generell möglich von einem Programm aus ans hostsystem (also windows7 zb.) die Message zu senden "es wurde Taste xy auf dem keyboard gedrückt" damit diese von anderen programmen ausgewertet werden kann? Natürlich ohne das die Taste wirklich physikalisch gedrückt wurde. ;)

    Grüße

    ee

    Samstag, 27. Oktober 2012 06:29

Antworten

  • Hallo ee,

    Die Tastatureingabe hat als Ziel immer das aktuell aktive Fenster, unabhängig davon ob man SendKeys.Send() verwendet, oder die SendInput()-API Funktion. In bestimmten Szenarien kann man WM_KEYUP-, WM_CHAR- und WM_KEYDOWN-Nachrichten direkt an die jeweilige Fensterprozedur über SendMessage()-API absetzen, dann funktioniert u.U. die Weitergabe von "Tastaturanschlägen" auch ohne ein aktives Fenster, eine Garantie für die (zeitnahe) Verarbeitung der Nachrichten aber - vor allem unter Windows 7 - gibt es nicht. Und: Viele betrachten es eher als Unsitte, Tastatureingaben mit WM_KEYDOWN zu simulieren. Der klassische .NET-Weg ist also: Fremdanwendung in den Vordergrund bringen und aktivieren (FindWindow/SetForegroundWindow), dann SendKeys.Send() verwenden.

    Details findest Du hier:
    Tasten Simulieren: Enter funktioniert nicht unter Windows 7

    Gruß
    Marcel

    Samstag, 27. Oktober 2012 08:28
    Moderator
  • Leider crasht mein Programm beim versuch die KeyEvents an die anderen Anwendungen zu verschicken.

    Hallo ee,

    Zunächst zum Crash: Es ist generell hilfreich, wenn man zu einem Fehler die genauen Umstände beschreibt, sowie die Fehlermeldung im Wortlaut hier postet (StackTrace erwünscht).

    Ich kann mir aber in diesem Fall ehrlich gesagt schwer vorstellen, dass SendKeys.Send() zu einem Crash führen könnte, da dieses Methode intern einfach ein Keyboard-State setzt und diesen an die SendInput()-Funktion weiterdelegiert. Nichts weltbewegendes hier, wirklich.

    Welche Option Du schlussendlich wählst, hängt von dem ab, was deine Anwendung machen muss. Nachfolgend eine Klasse, die beide Wege (Windows API / SendKeys.Send) implementiert:

        public class SendKeysHelper
        {
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool SetForegroundWindow(IntPtr hWnd);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);
    
            private const int WM_KEYDOWN = 0x100;
            private const int WM_KEYUP = 0x101;
    
            public static void ActivateWindowThenSendKeys(string windowTitle, string keys)
            {
                var windowHandle = GetWindowHandleFromTitle(windowTitle);
    
                if (windowHandle != IntPtr.Zero) {
                    SetForegroundWindow(windowHandle);
                    SendKeys.Send(keys);
                }
            }
    
            public static void DontActivateWindowJustSendKeys(string windowTitle, int keyCode)
            {
                var windowHandle = GetWindowHandleFromTitle(windowTitle);
    
                if (windowHandle != IntPtr.Zero)
                    SendMessage(windowHandle, WM_KEYDOWN, keyCode, IntPtr.Zero);
            }
    
            private static IntPtr GetWindowHandleFromTitle(string windowTitle)
            {
                var windowHandle = FindWindow(null, windowTitle);
                return windowHandle;
            }
        }
    

    Wenn man Tastaturanschläge an Anwendungen schickt, muss man sich natürlich darüber im Klaren sein, dass man nur Herr über die Senderseite ist. Was die Zielanwendung daraus macht (und ob), steht auf einem anderen Blatt.

    Gruß
    Marcel

    Sonntag, 28. Oktober 2012 16:44
    Moderator

Alle Antworten

  • Hallo ee,

    Die Tastatureingabe hat als Ziel immer das aktuell aktive Fenster, unabhängig davon ob man SendKeys.Send() verwendet, oder die SendInput()-API Funktion. In bestimmten Szenarien kann man WM_KEYUP-, WM_CHAR- und WM_KEYDOWN-Nachrichten direkt an die jeweilige Fensterprozedur über SendMessage()-API absetzen, dann funktioniert u.U. die Weitergabe von "Tastaturanschlägen" auch ohne ein aktives Fenster, eine Garantie für die (zeitnahe) Verarbeitung der Nachrichten aber - vor allem unter Windows 7 - gibt es nicht. Und: Viele betrachten es eher als Unsitte, Tastatureingaben mit WM_KEYDOWN zu simulieren. Der klassische .NET-Weg ist also: Fremdanwendung in den Vordergrund bringen und aktivieren (FindWindow/SetForegroundWindow), dann SendKeys.Send() verwenden.

    Details findest Du hier:
    Tasten Simulieren: Enter funktioniert nicht unter Windows 7

    Gruß
    Marcel

    Samstag, 27. Oktober 2012 08:28
    Moderator
  • Riesen Dank an Dich Marcel.

    Samstag, 27. Oktober 2012 19:42
  • Der klassische .NET-Weg ist also: Fremdanwendung in den Vordergrund bringen und aktivieren (FindWindow/SetForegroundWindow), dann SendKeys.Send() verwenden.

    Hallo nochmal, 

    Meine  Lösung sieht jetzt wie folgt aus, aber leider crasht mein Programm beim versuch die KeyEvents an die anderen Anwendungen zu verschicken. Lohnt es sich es weiter mit SendKeys zu versuchen oder sollte ich es lieber mit keydb_event() weiter versuchen?

    private void remote()
    {
        string processname = "";
        foreach (Process p in Process.GetProcesses())
        {
            //if (p.MainWindowHandle != null && p.MainWindowTitle.Contains("Google Chrome") == true)
            if (p.MainWindowHandle != null && p.MainWindowTitle.Contains("Mozilla Firefox") == true)
            {
                // Prozesss mit Name und handle anzeigen
                //System.Windows.MessageBox.Show(p.MainWindowTitle + " -> " + p.MainWindowHandle.ToString());
                processname = p.MainWindowTitle;
                break;
            }
        }
    
        IntPtr mybrowser = FindWindow(null, processname);
    
        if (mybrowser.ToInt32() == 0) System.Windows.MessageBox.Show(OutputErr(1));
        else
        {
            SetForegroundWindow(mybrowser);
            SendKeys.Send("{DOWN}");
        }
    }
    

    Danke und Grüße

    ee

    Sonntag, 28. Oktober 2012 08:24
  • Leider crasht mein Programm beim versuch die KeyEvents an die anderen Anwendungen zu verschicken.

    Hallo ee,

    Zunächst zum Crash: Es ist generell hilfreich, wenn man zu einem Fehler die genauen Umstände beschreibt, sowie die Fehlermeldung im Wortlaut hier postet (StackTrace erwünscht).

    Ich kann mir aber in diesem Fall ehrlich gesagt schwer vorstellen, dass SendKeys.Send() zu einem Crash führen könnte, da dieses Methode intern einfach ein Keyboard-State setzt und diesen an die SendInput()-Funktion weiterdelegiert. Nichts weltbewegendes hier, wirklich.

    Welche Option Du schlussendlich wählst, hängt von dem ab, was deine Anwendung machen muss. Nachfolgend eine Klasse, die beide Wege (Windows API / SendKeys.Send) implementiert:

        public class SendKeysHelper
        {
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool SetForegroundWindow(IntPtr hWnd);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, IntPtr lParam);
    
            private const int WM_KEYDOWN = 0x100;
            private const int WM_KEYUP = 0x101;
    
            public static void ActivateWindowThenSendKeys(string windowTitle, string keys)
            {
                var windowHandle = GetWindowHandleFromTitle(windowTitle);
    
                if (windowHandle != IntPtr.Zero) {
                    SetForegroundWindow(windowHandle);
                    SendKeys.Send(keys);
                }
            }
    
            public static void DontActivateWindowJustSendKeys(string windowTitle, int keyCode)
            {
                var windowHandle = GetWindowHandleFromTitle(windowTitle);
    
                if (windowHandle != IntPtr.Zero)
                    SendMessage(windowHandle, WM_KEYDOWN, keyCode, IntPtr.Zero);
            }
    
            private static IntPtr GetWindowHandleFromTitle(string windowTitle)
            {
                var windowHandle = FindWindow(null, windowTitle);
                return windowHandle;
            }
        }
    

    Wenn man Tastaturanschläge an Anwendungen schickt, muss man sich natürlich darüber im Klaren sein, dass man nur Herr über die Senderseite ist. Was die Zielanwendung daraus macht (und ob), steht auf einem anderen Blatt.

    Gruß
    Marcel

    Sonntag, 28. Oktober 2012 16:44
    Moderator
  • Hallo externalerror,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Montag, 5. November 2012 15:59
    Moderator