Benutzer mit den meisten Antworten
Tastatureingaben außerhalb des Formulars erkennen

Frage
-
Hallo,
ich habe ein Problem: Und zwar will ich erreichen, dass mein Programm auch Tastatureingaben außerhalb des Programms, also auch in anderen Anwendungen wahrnehmen kann.Z.B. Wenn man das Programm verkleinert dann verschwindet es ganz aus der Taskleiste und nun soll man es über eine Tastenkombination wieder aufrufen können.Aber sobald man sich in einem anderen Programm befindet, enthält das Formular der eigenen Anwendung natürlich nicht mehr den Fokus.
Gibt es dafür vielleicht eine bestimmte Funktion oder ein Ereignis?
Schonmal danke im voraus.
Antworten
-
Wenn man Tastaturereignisse systemweit abhören möchte, benötigt man einen KeyboardHook, der in einer Standard DLL (zu erstellen z.B. mit C++) untergebracht sein muss. So wie ich Dein Anfrage verstehe, möchtest Du aber nur, dass Deine Anwendung bei einer bestimmten Tastenkombination in den Vordergrund geholt wird. Dafür kannst Du die API Funktion RegisterHotkey verwenden. Anbei eine Beispielimplementierung in VB.NET:
Imports System.Runtime.InteropServices Public Class HotkeyControl Inherits System.ComponentModel.Component Private m_HotkeyWindow As HotkeyWindow Public Event HotkeyPressed As KeyEventHandler Public Sub New() End Sub Protected Overrides Sub Dispose(ByVal disposing As Boolean) If m_HotkeyWindow IsNot Nothing Then m_HotkeyWindow.UnregisterHotkeys() m_HotkeyWindow.DestroyHandle() m_HotkeyWindow = Nothing End If MyBase.Dispose(disposing) End Sub Friend Sub OnHotkey(ByVal hotkey As Keys) Dim lKeyEvent As New KeyEventArgs(hotkey) RaiseEvent HotkeyPressed(Me, lKeyEvent) End Sub Public Function RegisterHotkey(ByVal hotkey As Keys) As Boolean If m_HotkeyWindow IsNot Nothing AndAlso m_HotkeyWindow.Contains(hotkey) Then Throw New ArgumentException("Hotkey is already registered.") End If If m_HotkeyWindow Is Nothing Then m_HotkeyWindow = New HotkeyWindow(Me) End If Return m_HotkeyWindow.RegisterHotkey(hotkey) End Function Public Sub UnregisterHotkey(ByVal hotkey As Keys) If m_HotkeyWindow IsNot Nothing AndAlso Not m_HotkeyWindow.Contains(hotkey) Then Throw New ArgumentException("Hotkey is not registered.") End If If m_HotkeyWindow IsNot Nothing Then m_HotkeyWindow.UnregisterHotkey(hotkey) End If End Sub Private Class HotkeyWindow Inherits NativeWindow Private m_Owner As HotkeyControl Private m_Hotkeys As Dictionary(Of Keys, Integer) Private m_LastID As Integer Public Sub New() m_Hotkeys = New Dictionary(Of Keys, Integer) m_LastID = 0 End Sub Public Sub New(ByVal owner As HotkeyControl) Me.New() m_Owner = owner End Sub Public Function Contains(ByVal hotkey As Keys) As Boolean Return m_Hotkeys.ContainsKey(hotkey) End Function Protected Overridable Sub Create() If Me.Handle = IntPtr.Zero Then Dim lCP As New CreateParams() lCP.Caption = Me.GetType().Name lCP.Style = 0 lCP.ExStyle = 0 lCP.ClassStyle = 0 MyBase.CreateHandle(lCP) End If End Sub Public Overrides Sub DestroyHandle() Me.UnregisterHotkeys() MyBase.DestroyHandle() End Sub Public Function RegisterHotkey(ByVal hotkey As Keys) As Boolean Dim lResult As Integer Dim lID As Integer Dim lModifier As UInteger Dim lVKey As UInteger = CType(hotkey And Not Keys.Modifiers, UInteger) If (hotkey And Keys.Control) = Keys.Control Then lModifier = NativeMethods.MOD_CONTROL End If If (hotkey And Keys.Alt) = Keys.Alt Then lModifier = lModifier Or NativeMethods.MOD_ALT End If If (hotkey And Keys.Shift) = Keys.Shift Then lModifier = lModifier Or NativeMethods.MOD_SHIFT End If lID = m_LastID + 1 If Me.Handle = IntPtr.Zero Then Me.Create() End If lResult = NativeMethods.RegisterHotKey(Me.Handle, lID, lModifier, lVKey) If CBool(lResult) Then m_Hotkeys.Add(hotkey, lID) m_LastID = lID Return True End If End Function Public Sub UnregisterHotkey(ByVal hotkey As Keys) NativeMethods.UnregisterHotKey(Me.Handle, m_Hotkeys(hotkey)) m_Hotkeys.Remove(hotkey) End Sub Public Sub UnregisterHotkeys() For Each item As KeyValuePair(Of Keys, Integer) In m_Hotkeys NativeMethods.UnregisterHotKey(Me.Handle, item.Value) Next m_Hotkeys.Clear() m_LastID = 0 End Sub Public Function LoWord(ByVal value As Integer) As Integer Return value And &HFFFF End Function Public Function HiWord(ByVal value As Integer) As Integer Return (value And &HFFFF0000) \ &H10000 End Function Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) If m.Msg = NativeMethods.WM_HOTKEY Then Dim lHotkey As Keys Dim lModifier As Integer = LoWord(m.LParam.ToInt32) Dim lKey As Integer = HiWord(m.LParam.ToInt32) If (lModifier And NativeMethods.MOD_CONTROL) = NativeMethods.MOD_CONTROL Then lHotkey = Keys.Control End If If (lModifier And NativeMethods.MOD_ALT) = NativeMethods.MOD_ALT Then lHotkey = lHotkey Or Keys.Alt End If If (lModifier And NativeMethods.MOD_SHIFT) = NativeMethods.MOD_SHIFT Then lHotkey = lHotkey Or Keys.Shift End If lHotkey = lHotkey Or CType(lKey, Keys) m_Owner.OnHotkey(lHotkey) Else MyBase.WndProc(m) End If End Sub End Class Friend Class NativeMethods Public Const WM_HOTKEY As Integer = &H312 Public Const MOD_ALT As UInteger = &H1 Public Const MOD_CONTROL As UInteger = &H2 Public Const MOD_SHIFT As UInteger = &H4 Public Const MOD_WIN As UInteger = &H8 <DllImport("user32.dll")> _ Public Shared Function RegisterHotKey(ByVal hWnd As IntPtr, _ ByVal id As Integer, _ ByVal fsModifiers As UInteger, _ ByVal vk As UInteger) As Integer End Function <DllImport("user32.dll")> _ Public Shared Function UnregisterHotKey(ByVal hWnd As IntPtr, _ ByVal id As Integer) As Integer End Function End Class End Class
Diese Komponente kannst Du jetzt entweder über den Designer zu Deinem Formular hinzufügen, oder wie folgt einbinden:
Public Class Form1 Friend WithEvents HotkeyControl1 As HotkeyControl Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load HotkeyControl1 = New HotkeyControl() HotkeyControl1.RegisterHotkey(Keys.M Or Keys.Control Or Keys.Shift) HotkeyControl1.RegisterHotkey(Keys.MediaPlayPause) End Sub Private Sub HotkeyControl1_HotkeyPressed(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyEventArgs _ ) Handles HotkeyControl1.HotkeyPressed MsgBox(String.Format("Modifier: {0} Key: {1}", e.Modifiers.ToString(), e.KeyCode.ToString())) End Sub End Class
Hier wird die Tastenkombination Strg+Umschalt+M, sowie die Start/Pause Taste (bei einigen Multimedia Tastaturen) für Deine Anwendung registriert. Natürlich nur solange, wie keine andere Anwendung schneller war und diese Tasten nicht selber registriert hat.
Thorsten Dörfler
Microsoft MVP Visual Basic- Als Antwort vorgeschlagen Thorsten Dörfler Freitag, 13. November 2009 09:19
- Als Antwort markiert Robert Breitenhofer Montag, 16. November 2009 13:51
-
Hallo Yves,
Dein Code wird bei jedem Tastenanschlag mindestens zweimal ausgeführt: Wenn die Taste gedrückt wird und wenn sie wieder losgelassen wird. Wird sie derweil festgehalten, wird auch das Event permanent wiederholt. Über den Parameter wParam kannst Du abfragen, ob die Taste gedrückt oder losgelassen wurde. Sinnvoll ist hier den Code nur dann auszuführen, wenn die Taste losgelassen wurde:
If nCode = HC_ACTION And wParam = New IntPtr(WM_KEYUP) Then
If lParam.vkCode = Keys.D1 Then abc = abc + "1"
...
Thorsten Dörfler
Microsoft MVP Visual Basic- Als Antwort vorgeschlagen Yves Riedener Sonntag, 14. März 2010 15:07
- Als Antwort markiert Robert Breitenhofer Dienstag, 16. März 2010 08:39
Alle Antworten
-
Wenn man Tastaturereignisse systemweit abhören möchte, benötigt man einen KeyboardHook, der in einer Standard DLL (zu erstellen z.B. mit C++) untergebracht sein muss. So wie ich Dein Anfrage verstehe, möchtest Du aber nur, dass Deine Anwendung bei einer bestimmten Tastenkombination in den Vordergrund geholt wird. Dafür kannst Du die API Funktion RegisterHotkey verwenden. Anbei eine Beispielimplementierung in VB.NET:
Imports System.Runtime.InteropServices Public Class HotkeyControl Inherits System.ComponentModel.Component Private m_HotkeyWindow As HotkeyWindow Public Event HotkeyPressed As KeyEventHandler Public Sub New() End Sub Protected Overrides Sub Dispose(ByVal disposing As Boolean) If m_HotkeyWindow IsNot Nothing Then m_HotkeyWindow.UnregisterHotkeys() m_HotkeyWindow.DestroyHandle() m_HotkeyWindow = Nothing End If MyBase.Dispose(disposing) End Sub Friend Sub OnHotkey(ByVal hotkey As Keys) Dim lKeyEvent As New KeyEventArgs(hotkey) RaiseEvent HotkeyPressed(Me, lKeyEvent) End Sub Public Function RegisterHotkey(ByVal hotkey As Keys) As Boolean If m_HotkeyWindow IsNot Nothing AndAlso m_HotkeyWindow.Contains(hotkey) Then Throw New ArgumentException("Hotkey is already registered.") End If If m_HotkeyWindow Is Nothing Then m_HotkeyWindow = New HotkeyWindow(Me) End If Return m_HotkeyWindow.RegisterHotkey(hotkey) End Function Public Sub UnregisterHotkey(ByVal hotkey As Keys) If m_HotkeyWindow IsNot Nothing AndAlso Not m_HotkeyWindow.Contains(hotkey) Then Throw New ArgumentException("Hotkey is not registered.") End If If m_HotkeyWindow IsNot Nothing Then m_HotkeyWindow.UnregisterHotkey(hotkey) End If End Sub Private Class HotkeyWindow Inherits NativeWindow Private m_Owner As HotkeyControl Private m_Hotkeys As Dictionary(Of Keys, Integer) Private m_LastID As Integer Public Sub New() m_Hotkeys = New Dictionary(Of Keys, Integer) m_LastID = 0 End Sub Public Sub New(ByVal owner As HotkeyControl) Me.New() m_Owner = owner End Sub Public Function Contains(ByVal hotkey As Keys) As Boolean Return m_Hotkeys.ContainsKey(hotkey) End Function Protected Overridable Sub Create() If Me.Handle = IntPtr.Zero Then Dim lCP As New CreateParams() lCP.Caption = Me.GetType().Name lCP.Style = 0 lCP.ExStyle = 0 lCP.ClassStyle = 0 MyBase.CreateHandle(lCP) End If End Sub Public Overrides Sub DestroyHandle() Me.UnregisterHotkeys() MyBase.DestroyHandle() End Sub Public Function RegisterHotkey(ByVal hotkey As Keys) As Boolean Dim lResult As Integer Dim lID As Integer Dim lModifier As UInteger Dim lVKey As UInteger = CType(hotkey And Not Keys.Modifiers, UInteger) If (hotkey And Keys.Control) = Keys.Control Then lModifier = NativeMethods.MOD_CONTROL End If If (hotkey And Keys.Alt) = Keys.Alt Then lModifier = lModifier Or NativeMethods.MOD_ALT End If If (hotkey And Keys.Shift) = Keys.Shift Then lModifier = lModifier Or NativeMethods.MOD_SHIFT End If lID = m_LastID + 1 If Me.Handle = IntPtr.Zero Then Me.Create() End If lResult = NativeMethods.RegisterHotKey(Me.Handle, lID, lModifier, lVKey) If CBool(lResult) Then m_Hotkeys.Add(hotkey, lID) m_LastID = lID Return True End If End Function Public Sub UnregisterHotkey(ByVal hotkey As Keys) NativeMethods.UnregisterHotKey(Me.Handle, m_Hotkeys(hotkey)) m_Hotkeys.Remove(hotkey) End Sub Public Sub UnregisterHotkeys() For Each item As KeyValuePair(Of Keys, Integer) In m_Hotkeys NativeMethods.UnregisterHotKey(Me.Handle, item.Value) Next m_Hotkeys.Clear() m_LastID = 0 End Sub Public Function LoWord(ByVal value As Integer) As Integer Return value And &HFFFF End Function Public Function HiWord(ByVal value As Integer) As Integer Return (value And &HFFFF0000) \ &H10000 End Function Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) If m.Msg = NativeMethods.WM_HOTKEY Then Dim lHotkey As Keys Dim lModifier As Integer = LoWord(m.LParam.ToInt32) Dim lKey As Integer = HiWord(m.LParam.ToInt32) If (lModifier And NativeMethods.MOD_CONTROL) = NativeMethods.MOD_CONTROL Then lHotkey = Keys.Control End If If (lModifier And NativeMethods.MOD_ALT) = NativeMethods.MOD_ALT Then lHotkey = lHotkey Or Keys.Alt End If If (lModifier And NativeMethods.MOD_SHIFT) = NativeMethods.MOD_SHIFT Then lHotkey = lHotkey Or Keys.Shift End If lHotkey = lHotkey Or CType(lKey, Keys) m_Owner.OnHotkey(lHotkey) Else MyBase.WndProc(m) End If End Sub End Class Friend Class NativeMethods Public Const WM_HOTKEY As Integer = &H312 Public Const MOD_ALT As UInteger = &H1 Public Const MOD_CONTROL As UInteger = &H2 Public Const MOD_SHIFT As UInteger = &H4 Public Const MOD_WIN As UInteger = &H8 <DllImport("user32.dll")> _ Public Shared Function RegisterHotKey(ByVal hWnd As IntPtr, _ ByVal id As Integer, _ ByVal fsModifiers As UInteger, _ ByVal vk As UInteger) As Integer End Function <DllImport("user32.dll")> _ Public Shared Function UnregisterHotKey(ByVal hWnd As IntPtr, _ ByVal id As Integer) As Integer End Function End Class End Class
Diese Komponente kannst Du jetzt entweder über den Designer zu Deinem Formular hinzufügen, oder wie folgt einbinden:
Public Class Form1 Friend WithEvents HotkeyControl1 As HotkeyControl Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load HotkeyControl1 = New HotkeyControl() HotkeyControl1.RegisterHotkey(Keys.M Or Keys.Control Or Keys.Shift) HotkeyControl1.RegisterHotkey(Keys.MediaPlayPause) End Sub Private Sub HotkeyControl1_HotkeyPressed(ByVal sender As Object, _ ByVal e As System.Windows.Forms.KeyEventArgs _ ) Handles HotkeyControl1.HotkeyPressed MsgBox(String.Format("Modifier: {0} Key: {1}", e.Modifiers.ToString(), e.KeyCode.ToString())) End Sub End Class
Hier wird die Tastenkombination Strg+Umschalt+M, sowie die Start/Pause Taste (bei einigen Multimedia Tastaturen) für Deine Anwendung registriert. Natürlich nur solange, wie keine andere Anwendung schneller war und diese Tasten nicht selber registriert hat.
Thorsten Dörfler
Microsoft MVP Visual Basic- Als Antwort vorgeschlagen Thorsten Dörfler Freitag, 13. November 2009 09:19
- Als Antwort markiert Robert Breitenhofer Montag, 16. November 2009 13:51
-
wieso schreibt dieser code alles doppelt?
If lParam.vkCode = Keys.D1 Then abc = abc + "1" If lParam.vkCode = Keys.D2 Then abc = abc + "2" If lParam.vkCode = Keys.D3 Then abc = abc + "3" If lParam.vkCode = Keys.D4 Then abc = abc + "4" If lParam.vkCode = Keys.D5 Then abc = abc + "5" If lParam.vkCode = Keys.D6 Then abc = abc + "6" If lParam.vkCode = Keys.D7 Then abc = abc + "7" If lParam.vkCode = Keys.D8 Then abc = abc + "8" If lParam.vkCode = Keys.D9 Then abc = abc + "9" If lParam.vkCode = Keys.D0 Then abc = abc + "0"
LG Yves Riedener -
Hallo Yves,
den Zusammenhang zwischen Deiner Frage zu diesem Thread kann ich so gerade noch erraten.
Aber wieso doppelt?
Es finden 10 Vergleich auf 10 unterschiedliche Werte Keys.D0 - Keys.D9 statt; da ist nichts doppelt.
Man könnte es höchstens etwas eleganter / lesbarer per Select/Case Anweisung lösen.
Olaf Helper ----------- * cogito ergo sum * errare humanum est * quote erat demonstrandum * Wenn ich denke, ist das ein Fehler und das beweise ich täglich http://olafhelper.over-blog.de -
Hallo Yves,
poste bitte ein vollständig reproduzierbares Beispiel und nicht solche zusammenhanglose Codefetzen. Das was Du gepostet hast, gibt genau gar nichts zurück verdoppelt auch nichts und hat auch genau gar nichts mit dem Thema hier zu tun.
@Robert: Kannst Du das Thema bitte aufteilen?
Thorsten Dörfler
Microsoft MVP Visual Basic -
Ok
Imports System.Runtime.InteropServices Imports System.Net.Mail Imports System.Net Public Class Form1 Private Declare Unicode Function GetModuleHandleW Lib "kernel32.dll" (ByVal lpModuleName As IntPtr) As IntPtr Private Delegate Function HOOKPROCDelegate(ByVal nCode As Integer, ByVal wParam As IntPtr, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr Private Declare Unicode Function SetWindowsHookExW Lib "user32.dll" (ByVal idHook As Integer, ByVal lpfn As HOOKPROCDelegate, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr Private HookProc As New HOOKPROCDelegate(AddressOf KeyboardHookProc) Private Declare Unicode Function UnhookWindowsHookEx Lib "user32.dll" (ByVal hhk As IntPtr) As UInteger Private Declare Unicode Function CallNextHookEx Lib "user32.dll" (ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr Private Const WM_KEYDOWN As Int32 = &H100 Private Const WM_KEYUP As Int32 = &H101 Private Const WH_KEYBOARD_LL As Integer = 13 Private Const HC_ACTION As Integer = 0 Private mHandle As IntPtr Public PrevWndProc As Integer Dim abc As String = "" <StructLayout(LayoutKind.Sequential)> Public Structure KBDLLHOOKSTRUCT Public vkCode As Keys Public scanCode, flags, time, dwExtraInfo As UInteger Public Sub New(ByVal key As Keys, ByVal scancod As UInteger, ByVal flagss As _ UInteger, ByVal zeit As UInteger, ByVal extra As UInteger) vkCode = key scanCode = scancod flags = flagss time = zeit dwExtraInfo = extra End Sub End Structure Public Property KeyHookEnable() As Boolean Get Return mHandle <> IntPtr.Zero End Get Set(ByVal value As Boolean) If KeyHookEnable = value Then Return If value Then mHandle = SetWindowsHookExW(WH_KEYBOARD_LL, HookProc, GetModuleHandleW( _ IntPtr.Zero), 0) Else UnhookWindowsHookEx(mHandle) mHandle = IntPtr.Zero End If End Set End Property Private Function KeyboardHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByRef lParam As KBDLLHOOKSTRUCT) As IntPtr Dim fEatKeyStroke As Boolean If nCode = HC_ACTION Then If lParam.vkCode = Keys.D1 Then abc = abc + "1" If lParam.vkCode = Keys.D2 Then abc = abc + "2" If lParam.vkCode = Keys.D3 Then abc = abc + "3" If lParam.vkCode = Keys.D4 Then abc = abc + "4" If lParam.vkCode = Keys.D5 Then abc = abc + "5" If lParam.vkCode = Keys.D6 Then abc = abc + "6" If lParam.vkCode = Keys.D7 Then abc = abc + "7" If lParam.vkCode = Keys.D8 Then abc = abc + "8" If lParam.vkCode = Keys.D9 Then abc = abc + "9" If lParam.vkCode = Keys.D0 Then abc = abc + "0" End If If fEatKeyStroke Then Return New IntPtr(1) Exit Function End If Return CallNextHookEx(mHandle, nCode, wParam, lParam) End Function Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click KeyHookEnable = True Me.Text = "aktiv!" End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click KeyHookEnable = False Me.Text = "nicht aktiv" End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Button2.PerformClick() End Sub Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click MsgBox(abc)
Also das ist mein code:
End Sub
End Class
3x Button
LG Yves Riedener -
Hallo Yves,
Dein Code wird bei jedem Tastenanschlag mindestens zweimal ausgeführt: Wenn die Taste gedrückt wird und wenn sie wieder losgelassen wird. Wird sie derweil festgehalten, wird auch das Event permanent wiederholt. Über den Parameter wParam kannst Du abfragen, ob die Taste gedrückt oder losgelassen wurde. Sinnvoll ist hier den Code nur dann auszuführen, wenn die Taste losgelassen wurde:
If nCode = HC_ACTION And wParam = New IntPtr(WM_KEYUP) Then
If lParam.vkCode = Keys.D1 Then abc = abc + "1"
...
Thorsten Dörfler
Microsoft MVP Visual Basic- Als Antwort vorgeschlagen Yves Riedener Sonntag, 14. März 2010 15:07
- Als Antwort markiert Robert Breitenhofer Dienstag, 16. März 2010 08:39