VB 5/6-Tipp 0589: Tasten miteinander tauschen
von Stefan Bergmann
Beschreibung
Manchmal müssen Sonderzeichen auf die Tastatur genutzt werden, die es nicht gibt. Oder es wäre nützlich, wenn auf dem Ziffernblock statt dem deutschen Komma ein englischer Punkt stehen würde. Letzteres wird in diesem Tipp mittels Subclassing demonstriert.
Schwierigkeitsgrad: | Verwendete API-Aufrufe: AttachThreadInput, CallNextHookEx, RtlMoveMemory (CopyMemory), GetClassNameA (GetClassName), GetFocus, GetForegroundWindow, GetWindowThreadProcessId, PostMessageA (PostMessage), SendMessageA (SendMessage), SetWindowsHookExA (SetWindowsHookEx), UnhookWindowsHookEx | Download: |
'Dieser Quellcode stammt von http://www.activevb.de 'und kann frei verwendet werden. Für eventuelle Schäden 'wird nicht gehaftet. 'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. 'Ansonsten viel Spaß und Erfolg mit diesem Source! '------------ Anfang Projektdatei KeyChange.vbp ------------ ' Die Komponente 'Microsoft Windows Common Controls 6.0 (SP6) (mscomctl.ocx)' wird benötigt. '--- Anfang Formular "frmKeyChange" alias frmKeyChange.frm --- ' Steuerelement: Schaltfläche "Command3" ' Steuerelement: Schaltfläche "Command2" ' Steuerelement: Schaltfläche "Command1" '========================================================================= ' Programm: KeyChange ' Funktion: Komma auf dem Ziffernblock durch Punkt ersetzen ' Author: Stefan Bergmann ' email: silberfische@gmx.de '========================================================================= '!!! Achtung niemals über Stop-Button in der IDE beenden, 'da sonst der Hook nicht beendet wird!!! 'Überarbeitet von Jochen Wierum (JoWi@ActiveVB.de) Option Explicit Private Sub Command1_Click() If kbHookRet = 0 Then kbHookRet = SetWindowsHookEx(WH_KEYBOARD_LL, _ AddressOf LowLevelKeyboardProc, App.hInstance, 0&) End If End Sub Private Sub Command2_Click() If kbHookRet <> 0 Then Call UnhookWindowsHookEx(kbHookRet) End Sub Private Sub Command3_Click() Unload Me End Sub ' Programmstart Private Sub Form_Load() ' Tastaturhook einschalten kbHookRet = SetWindowsHookEx(WH_KEYBOARD_LL, _ AddressOf LowLevelKeyboardProc, App.hInstance, 0&) End Sub 'Programm beenden Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) 'Hook ausschalten If kbHookRet <> 0 Then Call UnhookWindowsHookEx(kbHookRet) End Sub '--- Ende Formular "frmKeyChange" alias frmKeyChange.frm --- '------- Anfang Modul "allgemein" alias allgemein.bas ------- '========================================== ' Funktion: Hook + API + Konstanten,... ' Author: Stefan Bergmann ' email: silberfische@gmx.de '========================================== Option Explicit '============================ ' Konstanten Tastaturereignis '============================ Private Const WM_KEYDOWN = &H100 Private Const WM_KEYUP = &H101 Private Const WM_SYSKEYDOWN = &H104 Private Const WM_SYSKEYUP = &H105 '---------------------- ' gesendeter tastencode '---------------------- Private Const VK_OEM_PERIOD = &HBE ' hier: "." '-------------------- ' weitere Tastencodes '-------------------- 'Virtual key constants Private Const VK_TAB = &H9 Private Const VK_CONTROL = &H11 Private Const VK_ESCAPE = &H1B Private Const VK_space = &H20 '==================== ' Konstanten für Hook '==================== Public Const HC_ACTION = 0& 'Konstante für Keyboardhook Public Const WH_KEYBOARD_LL = 13& '===================== 'udt für Tastaturwerte '===================== Private Type KBDLLHOOKSTRUCT vkCode As Long scanCode As Long flags As Long time As Long dwExtraInfo As Long End Type '============================= ' Funktionen für Tastatur-Hook '============================= ' Hook für Tastaturüberwachung ' (filter-type = wh_keyboard_ll) einschalten Declare Function SetWindowsHookEx _ Lib "user32" _ Alias "SetWindowsHookExA" ( _ ByVal nFilterType As Long, _ ByVal hkPrc As Long, _ ByVal hMod As Long, _ ByVal dwThreadId As Long) As Long ' Hook für Tastaturüberwachung wieder ausschalten Declare Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Long) As Long ' Informationen an nächsten Hook weitergeben Declare Function CallNextHookEx Lib "user32" _ (ByVal hHook As Long, _ ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long ' Rückgabe der Tastatur auf kbddlhs-Variable kopieren Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (pDest As Any, pSource As Any, ByVal cb As Long) '================================== ' Funktionen um das Objekt, welches ' den Fokus hat, zu ermitteln '================================== Private Declare Function GetClassName _ Lib "user32" Alias "GetClassNameA" ( _ ByVal hwnd As Long, _ ByVal lpClassName _ As String, _ ByVal nMaxCount As Long) As Long Private Declare Function GetForegroundWindow Lib "user32" () As Long Private Declare Function GetWindowThreadProcessId Lib "user32" _ (ByVal hwnd As Long, lpdwProcessId As Long) As Long Private Declare Function AttachThreadInput Lib "user32" (ByVal _ idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach _ As Long) As Long Private Declare Function GetFocus Lib "user32" () As Long '===================== ' Nachrichten schicken '===================== Private Declare Function SendMessage Lib "user32" Alias _ "SendMessageA" (ByVal hwnd As Long, ByVal wMsg _ As Long, ByVal wParam As Long, lParam As Long) _ As Long Private Declare Function PostMessage Lib "user32" Alias _ "PostMessageA" (ByVal hwnd As Long, ByVal wMsg _ As Long, ByVal wParam As Long, ByVal lParam As _ Long) As Long '===================== ' Variablendeklaration '===================== ' Rückgabe des Hooks Public kbHookRet As Long ' Tastatureingabe auswerten Public Function LowLevelKeyboardProc(ByVal nCode As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Static kbDllhs As KBDLLHOOKSTRUCT Dim blnKeyBlocked As Boolean Dim test As Long If nCode = HC_ACTION Then Call CopyMemory(kbDllhs, ByVal lParam, Len(kbDllhs)) blnKeyBlocked = False ' key down If kbDllhs.flags = 0 Then ' virtueller Tastencode = 110 (Komma) If kbDllhs.vkCode = 110 Then ' Nachricht an aktives Fenster schicken ' (Tastatureingabe, keydown) hat auch mit ' Senkeys funktioniert (ist aber meiner ' Meinung nach nicht so toll) PostMessage GetControl, WM_KEYDOWN, ByVal VK_OEM_PERIOD, 0& 'ursprüngliche Tastatureingabe nicht weitergeben LowLevelKeyboardProc = 1 Else 'ursprüngliche Tastatureingabe weitergeben LowLevelKeyboardProc = CallNextHookEx(kbHookRet, nCode, wParam, lParam) End If End If ' key up If kbDllhs.flags = 128 Then ' virtueller Tastencode = 110 (komma) If kbDllhs.vkCode = 110 Then ' Nachricht an aktives Fenster schicken ' (Tastatureingabe, keyup) hat auch mit ' Senkeys funktioniert (ist aber meiner ' Meinung nach nicht so toll) 'Anmerkung von Jochen Wierum (JoWi@ActiveVB.de): ' Ich habe die Zeile deaktiviert, da sonst bei einem ' Tastendruck immer 2 Punkte erzeugt wurden. Falls es ' in dieser Konfiguration Probleme geben sollte, bitte ' den Kommentar vor der folgenden Zeile entfernen: 'PostMessage GetControl, WM_KEYUP, ByVal VK_OEM_PERIOD, 0& 'ursprüngliche Tastatureingabe nicht weitergeben LowLevelKeyboardProc = 1 Else 'ursprüngliche Tastatureingabe weitergeben LowLevelKeyboardProc = CallNextHookEx(kbHookRet, nCode, wParam, lParam) End If End If End If End Function '------------------------------------------------------- ' Objekt (Textfeld,....) welches den Fokus hat ermitteln Private Function GetControl() As Long Dim OtherThreadID As Long Dim Thread1 As Long Dim Thread2 As Long Dim bMerker As Boolean Dim GetCurrentThreadID As Long Thread1 = GetWindowThreadProcessId(frmKeyChange.hwnd, GetCurrentThreadID) Thread2 = GetWindowThreadProcessId(GetForegroundWindow, OtherThreadID) If Thread1 <> Thread2 Then bMerker = AttachThreadInput(Thread2, Thread1, True) GetControl = GetFocus() End Function '-------- Ende Modul "allgemein" alias allgemein.bas -------- '------------- Ende Projektdatei KeyChange.vbp -------------
Tipp-Kompatibilität:
Windows/VB-Version | Win32s | Win95 | Win98 | WinME | WinNT4 | Win2000 | WinXP |
VB4 | |||||||
VB5 | |||||||
VB6 |
Ihre Meinung
Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.
Archivierte Nutzerkommentare
Klicken Sie diesen Text an, wenn Sie die 8 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.
Kommentar von Timo am 06.08.2007 um 23:51
danke
Kommentar von Philipp Stephani am 18.02.2007 um 18:38
Schöner Tipp, aber das Belegen von Tasten mit Zeichen sollte per Tastaturlayout geschehen. Das ist der dafür vorgesehene, viel einfachere Weg.
Kommentar von js am 30.12.2006 um 01:02
hmmmm...
Wie wär's mit [ALT GR v] [7 v] [7 ^] [ALT GR ^]
oder?
Kommentar von Puri am 18.01.2005 um 06:35
Und so ists richtig:
Laut http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/KeyboardInput/KeyboardInputReference/KeyboardInputMessages/WM_KEYUP.asp
muß das erste, das 31. und das 32. Bit bei KeyUp 1 sein.
Das richtige KeyUp-Event wird also so ausgelöst:
PostMessage GetControl, WM_KEYUP, ByVal VK_OEM_PERIOD, -1073741823
-1073741823 ist in Zweierkomplementdarstellung eben "11000000000000000000000000000001".
Schöner Gruß
Puri
Kommentar von Philipp Weber am 27.08.2004 um 16:15
KORREKTURVORSCHLAG
Bei mir (win2000, vb6) hat der tipp nicht funktioniert, da der virtuelle tastencode des komma's (nur bei mir?) nicht 110 entspricht, sondern 188 (dezimal) (-> hex: BC).
Als ich bei beiden if's (keydown, keyup) die 110 durch 188 ersetzt habe hat es soweit funktioniert bis auf das keyup-event des betroffenen controls, weil kein keyup ausgelöst wird (im tipp auskommentiert).
Ändert man die zeile:
PostMessage GetControl, WM_KEYUP, ByVal VK_OEM_PERIOD, 0&
beim keyup, in:
PostMessage GetControl, WM_KEYUP, 0, 0&
wird der punkt nur einmal erzeugt und das keyupevent ausgelöst.
Getestet hab ichs auf in einer textbox auf der form und im notepad, funktioniert bei mir einwandfrei.
Grüße
Philipp
Kommentar von Sascha Bürger am 05.06.2004 um 20:16
Man bist du gut.
Kommentar von Armin Grust am 09.01.2004 um 04:32
Windows-Version: Windows XP Home
VB-Version: VB6
Das Einschalten des Punktes funktioniert nur, wenn das Programm aufgerufen wird. Das Umschalten auf Komma per Command-Button funktioniert nicht. Erst wenn das Programm wieder beendet wird, hat die Komma-Taste die ursprüngliche Funktion.
Ich habe es mit Notepad getestet und die Eingaben probiert.
Viele Grüße
Armin Grust
Kommentar von Christoph Fuest am 23.11.2003 um 18:33
Hallo!
Kann ich statt dem Punkt auch eine "{" senden? Ein virtual-Key dafür existiert ja wohl nicht, oder?