Eigenen Tastatur Treiber programmieren

Hardware- und Elektronikbasteleien, Ansteuerung von Schnittstellen und Peripherie.
Fragen zu "Consumer"-Problemen kommen in Offtopic.
¯\_(ツ)_/¯
Beiträge: 141
Registriert: 18.08.2017 09:35

Re: Eigenen Tastatur Treiber programmieren

Beitrag von ¯\_(ツ)_/¯ »

Achso ok aber ich verstehe nur Bahnhof bzw ich kriegs nicht hin. Kannst du mir helfen? Das ist so komlex ich steig nicht durch.
Bild
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Eigenen Tastatur Treiber programmieren

Beitrag von RSBasic »

Hier der funktionierende Code:

DLL-Datei:

Code: Alles auswählen

EnableExplicit

ProcedureDLL KeyboardProc(code, wParam, lParam)
  #WM_GETKEY = #WM_USER + 1024
  Global WindowID
  
  If code < 0
    ProcedureReturn CallNextHookEx_(@KeyboardProc(), code, wParam, lParam)
  EndIf
  
  If WindowID = 0
    WindowID = FindWindow_(0, "MultiKBHook")
  EndIf
  
  If WindowID
    If SendMessage_(WindowID, #WM_GETKEY, wParam, lParam) = #True
      ProcedureReturn -1
    EndIf
  EndIf
  
  ProcedureReturn CallNextHookEx_(@KeyboardProc(), code, wParam, lParam)
EndProcedure 
EXE-Datei:

Code: Alles auswählen

EnableExplicit

#RID_HEADER = $10000005
#RID_INPUT = $10000003
#RIM_TYPEMOUSE = 0
#RIM_TYPEKEYBOARD = 1
#RIM_TYPEHID = 2
#RIDEV_REMOVE = $00000001
#RIDEV_EXCLUDE = $00000010
#RIDEV_PAGEONLY = $00000020
#RIDEV_NOLEGACY = $00000030
#RIDEV_INPUTSINK = $00000100
#RIDEV_CAPTUREMOUSE = $00000200
#RIDEV_NOHOTKEYS = $00000200
#RIDEV_APPKEYS = $00000400
#RIDEV_EXINPUTSINK = $00001000
#RIDEV_DEVNOTIFY = $00002000
#RIDI_PREPARSEDDATA = $20000005
#RIDI_DEVICENAME = $20000007
#RIDI_DEVICEINFO = $2000000b
#WM_GETKEY = #WM_USER + 1024

Prototype GetRawInputData(hRawInput, uiCommand, *pData.RAWINPUT, *pcbSize, cbSizeHeader)
Prototype RegisterRawInputDevices(*pRawInputDevices.RAWINPUTDEVICE, *uiNumDevices, cbSize)
Prototype GetRawInputDeviceList(*pRawInputDeviceList.RAWINPUTDEVICELIST, *uiNumDevices, cbSize)
Prototype GetRawInputDeviceInfo(hDevice, uiCommand, *pData, *pcbSize)

Global user32 = OpenLibrary(#PB_Any, "user32.dll")
If IsLibrary(user32)
  Global RegisterRawInputDevices.RegisterRawInputDevices = GetFunction(user32, "RegisterRawInputDevices")
  Global GetRawInputData.GetRawInputData  = GetFunction(user32, "GetRawInputData")
  Global GetRawInputDeviceList.GetRawInputDeviceList = GetFunction(user32, "GetRawInputDeviceList")
  Global GetRawInputDeviceInfo.GetRawInputDeviceInfo = GetFunction(user32, "GetRawInputDeviceInfoW")
EndIf

Import "kernel32.lib"
  GetProcAddress(hModule, lpProcName.p-ascii)
EndImport

Global HookID
Global MultiKBHook
Global LasthDevice

Procedure WindowCallback(WindowID, Message, wParam, lParam)
  Protected result = #PB_ProcessPureBasicEvents
  Protected Key
  Protected VirtualCode
  Protected RepeatCount
  Protected ScanCode
  Protected SpecialKey
  Protected AltState
  Protected PreviousState
  Protected KeyUp
  
  Select Message       
    Case #WM_GETKEY
      Key=lParam
      
      VirtualCode=wParam
      RepeatCount=Key&$FFFF
      ScanCode=(Key>>16)&$FF
      SpecialKey=(Key>>24)&1
      AltState=(Key>>29)&1
      PreviousState=(Key>>30)&1
      KeyUp=Key>>31&1
      
      result = #False
      
      If LasthDevice = 99354541;Handle der Tastatur
        If ScanCode = 30;Buchstabe A
          result = #True
          Debug "funktioniert"
        Else
          result = #False
        EndIf
      EndIf
      
    Case #WM_INPUT
      Protected pcbSize.l
      Protected *pRawData.RAWINPUT
      
      If GetRawInputData(lParam, #RID_INPUT, #Null, @pcbSize, SizeOf(RAWINPUTHEADER)) = 0
        *pRawData = AllocateMemory(pcbSize)
        If *pRawData
          GetRawInputData(lParam, #RID_INPUT, *pRawData, @pcbSize, SizeOf(RAWINPUTHEADER))
          Select *pRawData\header\dwType
            Case #RIM_TYPEKEYBOARD
              LasthDevice = *pRawData\header\hDevice;lieber danach GetRawInputDeviceInfo() benutzen
          EndSelect
          
          FreeMemory(*pRawData)
        EndIf
        
      EndIf
  EndSelect
  
  ProcedureReturn result
EndProcedure

If OpenWindow(0, 0, 0, 500, 400, "MultiKBHook", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  SetWindowCallback(@WindowCallback())
  
  Dim Rid.RAWINPUTDEVICE(0)
  Rid(0)\usUsagePage = 1
  Rid(0)\usUsage = 0
  Rid(0)\hwndTarget = WindowID(0)
  Rid(0)\dwFlags = #RIDEV_INPUTSINK | #RIDEV_PAGEONLY
  
  RegisterRawInputDevices(@Rid(), ArraySize(Rid()) + 1, SizeOf(RAWINPUTDEVICE))
  
  MultiKBHook = OpenLibrary(0, "MultiKBHook.dll")
  If MultiKBHook
    HookID = SetWindowsHookEx_(#WH_KEYBOARD, GetProcAddress(MultiKBHook, "KeyboardProc"), MultiKBHook, 0)
    If HookID = 0
      Debug "Hook konnte nicht erstellt werden."
    EndIf
  Else
    Debug "Die DLL-Datei konnte nicht gefunden werden."
  EndIf
  
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        UnhookWindowsHookEx_(HookID)
        CloseLibrary(0)
        CloseLibrary(user32)
        End
    EndSelect
  ForEver
EndIf
Was passiert genau?
  1. Das Programm lädt die DLL-Datei und ruft die DLL-Funktion "KeyboardProc" für die Erstellung des globalen Keyboard-Hooks auf.
  2. Bei beliebiger Eingabe wird an das Fenster des Hauptprogramms eine benutzerdefinierte Windows-Message mit den Parametern gesendet und wartet auf den Rückgabewert und bei #true gibt er anschließend -1 für das Blocken der Weitergabe der Taste zurück.
  3. Im Hauptprogramm wird gleichzeitig im Hintergrund die Tastatur-Quelle ermittelt und die Handle-Nummer der Tastatur in die Variable LasthDevice geschrieben. Da ist es zukünftig besser, wenn du zusätzlich GetRawInputDeviceInfo() aufrufst um die Tastatur-Hardware-Informationen auszulesen, um deine Tastaturen besser zu unterschieden. Zum Testen habe ich hier nur einen Handle-Vergleich gemacht.
  4. Im Windows-Callback des Hauptprogramms kam nun die von der DLL-Datei gesendete Windows-Message an und wird auf Tastatur-Quelle und auf den gedrückten Tastenwert überprüft. Bei "A" soll beispielhaft geblockt werden. Also soll der Rückgabewert = #true sein.
  5. DLL-Datei blockt nun mit Hilfe des Hooks die Weitergabe der Taste.
Ich hoffe, das war verständlich genug. Jetzt endlich ins Bett. :D
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Eigenen Tastatur Treiber programmieren

Beitrag von ccode_new »

Hallo!

Das hier:

Code: Alles auswählen

Global ende.b = #False, i.i
Repeat
For i = 0 To 255
  If GetAsyncKeyState_(i) >= 255
    ;Debug i
    MessageRequester("Keyboard-Test", "VK: "+Str(i)+" gedrückt.",#MB_SYSTEMMODAL)
    If i = 13 Or i = 27 ;Enter oder ESC führen zum Abbruch
      ende = #True
      Break
    EndIf
  EndIf
Next i
Until ende = #True
funktioniert auch "GLOBAL".
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
¯\_(ツ)_/¯
Beiträge: 141
Registriert: 18.08.2017 09:35

Re: Eigenen Tastatur Treiber programmieren

Beitrag von ¯\_(ツ)_/¯ »

@rsbasic
:shock: :o Danke dass du extra für mich umgesetzt hast. Ich habe die Tastatur Nummer ID vorher ausgegeben und dann in der IF eingetragen und es funktioniert. :o Danke du hast mir extrem geholfen!!

@ccode_new
Danke für den Code und ich dachte zuerst es ginge mit deinem Code deutlich kürzer aber wie kann ich mit deinem Code sagen dass er eine bestimmte Taste nicht ausführen soll? Dh ich drücke die Taste A und ich fange die Taste ab und sage Nein und unterdrücke es so dass der Buchstabe A nicht in einem anderen Programm wie Notepad erscheint. Klappt es mit deinem Code irgendwie? Das wäre super!
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Eigenen Tastatur Treiber programmieren

Beitrag von ccode_new »

(ツ)_/(Hallo!)
|__|
| |
¯\_(ツ)_/¯ hat geschrieben:@ccode_new
Danke für den Code und ich dachte zuerst es ginge mit deinem Code deutlich kürzer aber wie kann ich mit deinem Code sagen dass er eine bestimmte Taste nicht ausführen soll? Dh ich drücke die Taste A und ich fange die Taste ab und sage Nein und unterdrücke es so dass der Buchstabe A nicht in einem anderen Programm wie Notepad erscheint. Klappt es mit deinem Code irgendwie? Das wäre super!
Da hast du recht!

Richte dich da lieber an den Windows-Api-Meister (RSBasic).

Ich hätte da nur einen unschönen Trick:

Code: Alles auswählen

EnableExplicit

Global ende.b = #False, z.i

; SendInput-Anpassungsfunktion von Hier->(https://www.purebasic.fr/english/viewtopic.php?p=289971) geklaut. ;)

Global Dim SendInputData.INPUT(0) ;Structure INPUT ist vordefiniert!

Procedure SendPrepare(n,VK,Char,UpDown,*Resize=#Null)
   SendInputData(n)\Type=#INPUT_KEYBOARD
   SendInputData(n)\ki\wVk=VK
   SendInputData(n)\ki\time=0
   SendInputData(n)\ki\dwExtraInfo=0
   SendInputData(n)\ki\wScan=Char
   SendInputData(n)\ki\dwFlags=UpDown
   If *Resize
      n=PeekL(*Resize)+1
      PokeL(*Resize,n)
      ReDim SendInputData(n)
   EndIf
EndProcedure

Procedure SendInput(Text.s)

   #KEYEVENTF_UNICODE = 4

   Protected i.l;   Pointer to Character in the Text
   Protected j.l;   Counter for SendInput
   Protected k.l;   Total Size for SendInput

   Protected Char.l
   Protected NewChar.l
   Protected KeyDown.l

   k=Len(Text)*2 ;*2 wegen Unicode!

   If k
      ReDim SendInputData(k)

      While j < k
         PokeS(@NewChar,Chr(PeekB(@Text+i)),#PB_Unicode)

         If (newchar=char) And KeyDown
            KeyDown=#False
            SendPrepare(j,0,Char,#KEYEVENTF_UNICODE|#KEYEVENTF_KEYUP,@k)
         Else
            char=newchar
            KeyDown=#True
            If char=13
               SendPrepare(j,#VK_MENU,0,#KEYEVENTF_EXTENDEDKEY,@k)
               SendPrepare(j,#VK_RETURN,0,#KEYEVENTF_EXTENDEDKEY)
               SendPrepare(j,#VK_MENU,0,#KEYEVENTF_KEYUP,@k)
            Else
               SendPrepare(j,0,Char,#KEYEVENTF_UNICODE)
            EndIf
            i+1
         EndIf

         j+1
      Wend

      SendInput_(k,SendInputData(0),SizeOf(INPUT))
      Delay(500) ;Wir warten! (Sonst werden zu viele Tastschläge simuliert)
      
   EndIf

EndProcedure

Repeat
  For z = 0 To 255
    If GetAsyncKeyState_(z) >= 255
      ;Debug i
      ;MessageRequester("Keyboard-Test", "VK: "+Str(i)+" gedrückt.", #MB_SYSTEMMODAL)
      If z = 65 ;A - Taste gedrückt
        SendInput(Chr(8)) ;Backspace !!!
        ;Die Nachricht der Taste 'A' wird nicht blockiert und nicht umbelegt. (Machbar entweder aber über Einschubmethode (HOOK), oder Registry)
        SendInput("Das ist unsinniger Mist, aber trotzdem toll!")  
        Continue
        ;...
      EndIf
      If z = 27 ;ESC führt zum Abbruch
        MessageRequester("Keyboard-Test", "Keyboard-Test beendet", #MB_SYSTEMMODAL)
        ende = #True
        Break
      EndIf
    EndIf 
  Next z
Until ende = #True
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Antworten