Pricehacker Posted April 24, 2019 Posted April 24, 2019 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: expandcollapse popup#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
Pricehacker Posted April 24, 2019 Author Posted April 24, 2019 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.
jchd Posted April 24, 2019 Posted April 24, 2019 (edited) 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 April 25, 2019 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 hereRegExp tutorial: enough to get startedPCRE 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)
Pricehacker Posted April 25, 2019 Author Posted April 25, 2019 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: Assign the value returned from _WinAPI_GetKeyboardState() to a variable $t Save the value of $t to a file that can be accesed after the main program is closed Read the file and assign the data to a variable $t 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
Pricehacker Posted April 25, 2019 Author Posted April 25, 2019 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
jchd Posted April 25, 2019 Posted April 25, 2019 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 hereRegExp tutorial: enough to get startedPCRE 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)
Pricehacker Posted April 26, 2019 Author Posted April 26, 2019 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now