Die Community zu .NET und Classic VB.
Menü

VB 5/6-Tipp 0589: Tasten miteinander tauschen

 von 

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:

Schwierigkeitsgrad 2

Verwendete API-Aufrufe:

AttachThreadInput, CallNextHookEx, RtlMoveMemory (CopyMemory), GetClassNameA (GetClassName), GetFocus, GetForegroundWindow, GetWindowThreadProcessId, PostMessageA (PostMessage), SendMessageA (SendMessage), SetWindowsHookExA (SetWindowsHookEx), UnhookWindowsHookEx

Download:

Download des Beispielprojektes [5,03 KB]

'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-VersionWin32sWin95Win98WinMEWinNT4Win2000WinXP
VB4
VB5
VB6

Hat dieser Tipp auf Ihrem Betriebsystem und mit Ihrer VB-Version funktioniert?

Ja, funktioniert!

Nein, funktioniert nicht bei mir!

VB-Version:

Windows-Version:

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.

Source funktioniert nicht bei allen Anwendungen - ThomasA 24.02.12 14:25 6 Antworten

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?