Jump to content

_WinAPI_SetKeyboardState error


Recommended Posts

I just got a new mouse that has macro functionality, and i wanted to make something simmilar for my keyboard. Thing is, _WinAPI_SetKeyboardState gives me an error i cannot seem to fix.

Please ask me if you have any questions, also here is the code:

#include <WinAPISys.au3>
#include <Array.au3>
#include <File.au3>
#include <GUIConstantsEx.au3>


HotKeySet('{ESC}', 'Close')

Global $bRecording = False
Global $bStop = False

Func Close()
    $bStop = True
EndFunc   ;==>Close

$hGUI = GUICreate('Input recorder', 500, 200)
$idStartRecording = GUICtrlCreateButton('Start recording', 80, 100)
$idStopRecording = GUICtrlCreateButton('Run macro', 320, 100)
GUISetState()


Global $aArray[11][2]

$hTimer = TimerInit()
While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $idStartRecording
            $bStop = False
            GUICtrlSetData($idStartRecording, 'Running...')
            $hFile = FileOpen(@ScriptDir & '\Macro' & @YEAR & '.' & @MON & '.' & @MDAY & '-' & @HOUR & '.' & @MIN & '.' & @SEC & '.macro', 1)
            While $bStop = False
                ;$hTimer = TimerInit()
                For $i = 0 To 10
                    If $i <> 0 Then
                        Do
                            Sleep(10)
                            $a = _WinAPI_GetKeyboardStateMod()
                        Until _ArrayToString($a, '') <> $aArray[$i - 1][0] or $bStop = True
                        ;ConsoleWrite(_ArrayToString($a, '') & '       ' & $aArray[$i - 1][0])
                    Else
                        $a = _WinAPI_GetKeyboardStateMod()
                    EndIf

                    $aArray[$i][0] = _ArrayToString($a, '')
                    $aArray[$i][1] = Round(TimerDiff($hTimer), 1)
                    $hTimer = TimerInit()
                Next
                _FileWriteFromArray($hFile, $aArray, Default, Default, @CRLF)
                for $iO = 0 to 10
                    $aArray[$iO][0] = ''
                    $aArray[$iO][1] = ''
                Next
                ;ConsoleWrite(@error)
            WEnd
            _FileWriteFromArray($hFile, $aArray, Default, Default, @CRLF)
            GUICtrlSetData($idStartRecording, 'Start recording')

        Case $idStopRecording
            $bStop = False
            $hFile = FileOpen(FileOpenDialog('Select macro file', @ScriptDir, 'Macro files (*.macro)', 1 + 2))
            GUICtrlSetData($idStopRecording, 'Running...')
            $sFileContent = FileRead($hFile)
            ;ConsoleWrite($sFileContent&@CRLF&@CRLF&@CRLF)
            $aWholeFile = StringSplit($sFileContent, @LF)
            ;_ArrayDisplay($aWholeFile)
            For $i = 1 To $aWholeFile[0] - 1
                ;ConsoleWrite(Mod($i,2))
                if $bStop = True Then ExitLoop
                If $aWholeFile[$i] <> @CR Then
                    If Mod($i,2) = 1 Then
                        ConsoleWrite('Array ' & $aWholeFile[$i])
                        $aCharPresses = StringSplit($aWholeFile[$i], '')
                        _WinAPI_SetKeyboardState($aCharPresses)
                    Else
                        ConsoleWrite('Sleep ' & $aWholeFile[$i])
                        Sleep(Int($aWholeFile[$i]))
                    EndIf
                EndIf
            Next
            GUICtrlSetData($idStopRecording, 'Run macro')
    EndSwitch
WEnd

Func _WinAPI_GetKeyboardStateMod()
    Local $aDllRet, $lpKeyState = DllStructCreate("byte[256]")
    $aDllRet = DllCall("User32.dll", "int", "GetKeyboardState", "ptr", DllStructGetPtr($lpKeyState))
    Local $aReturn[256]
    For $i = 1 To 256
        $aReturn[$i - 1] = DllStructGetData($lpKeyState, 1, $i)
    Next
    Return $aReturn
EndFunc   ;==>_WinAPI_GetKeyboardStateMod
Link to comment
Share on other sites

Just found that i was using an old version of _WinAPI_GetKeyboardState, the new version uses structs. Is there any way to save a $tStruct to a file? I had no luck with _WinAPI_StructToArray, as it would usually give an error and when it didnt it would have random characters in it anyway.

Link to comment
Share on other sites

Write the struct to a file in write binary mode. The result from the function is an array of 256 bytes without any ASCII meaning, so binary mode is mandatory.

Example:

Local $t = _WinAPI_GetKeyboardState()
$h = FileOpen("kbst.bin", 18)
FileWrite($h, DllStructGetData($t, 1))
FileClose($h)

 

Edited by jchd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Thank you, the code works as expected. However I cant find how to read the file (kbst.bin) and set a variable to the value that was saved in the file.

Basically i want to do something like this:

  1. Assign the value returned from _WinAPI_GetKeyboardState() to a variable $t
  2. Save the value of $t to a file that can be accesed after the main program is closed
  3. Read the file and assign the data to a variable $t
  4. Use _WinAPI_SetKeyboardState($t) to simulate the presses recorded previously by _WinAPI_GetKeyboardState()

And i guess i already did 1. and 2. with your help, here is my code

Local $t = _WinAPI_GetKeyboardState()
$h = FileOpen("kbst.bin", 18)
FileWrite($h, DllStructGetData($t, 1))
FileClose($h)

$hFile = FileOpen("kbst.bin")
$tStruct = FileRead($hFile)
_WinAPI_SetKeyboardState($tStruct)

_WinAPI_SetKeyboardState() returns 0, with no @extended flag. I guess this has to do with the data being altered with before it was written to a file, but i could not find a fitting function to fix my issue

Link to comment
Share on other sites

I found out what i did wrong, here is the final code:

Local $t = _WinAPI_GetKeyboardState()
$h = FileOpen("kbst.bin", 18)
FileWrite($h, DllStructGetData($t, 1))
FileClose($h)

$hFile = FileOpen("kbst.bin")
$sFileData = FileRead($hFile)
FileClose($hFile)
$aStructData = StringSplit($sFileData, '')
$tStruct = DllStructCreate('STRUCT')

For $i = 1 To 256
    DllStructSetData($tStruct, $i, $aStructData[$i])
Next

_WinAPI_SetKeyboardState($tStruct)

Thanks for helping me

Link to comment
Share on other sites

It's better to assign the whole binary chunk all at once:

; get data and store it
Local $tStruct = _WinAPI_GetKeyboardState()
Local $hFile = FileOpen("kbst.bin", $FO_BINARY + $FO_OVERWRITE)
FileWrite($hFile, DllStructGetData($tStruct, 1))
FileClose($hFile)

; read back data and load it
$hFile = FileOpen("kbst.bin", $FO_BINARY)
Local $bFileData = FileRead($hFile)
FileClose($hFile)
$tStruct = DllStructCreate('byte[256]')     ; or DllStructCreate('byte[' & BinaryLen($bFileData) & ']')
DllStructSetData($tStruct, 1, $bFileData)
_WinAPI_SetKeyboardState($tStruct)

 

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Thanks man!

I don't know how to @ you, but i was wondering if you know what _WinAPI_SetKeyboardState() actually does?

I want it to simulate those buttonpresses that were recorded with _WinAPI_GetKeyboardState(), but when i run the code it does nothing. I have checked for errors and any wierd characters in my .macro file i created but still it does nothing. I could not find anything useful online, maybe its not used that often, and i thought i might be using it wrong or making the wrong assumptions about its usage. Please tell me if i can use it to simulate keystrokes :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...