Related
i'm trying to select a date in a monthcal with the sendmessage cmd from AHK. Unfortunately, this is not working and i don't know where is my mistake or my misunderstanding. Anyone could help ? Here's what i already try.
ConvertNormalDateToSystemTime(YYYYMMDD)
; this return a SystemTime format date from a normal date
{
YYYYMMDD.=000000
YYYYMMDDHHMISS:=YYYYMMDD
VarSetCapacity(SystemTime, 16, 0) ; This struct consists of 8 UShorts (i.e. 8*2=16).
Int := SubStr(YYYYMMDDHHMISS, 1, 4) ; YYYY (year)
NumPut(Int, SystemTime, 0, "UShort")
Int := SubStr(YYYYMMDDHHMISS, 5, 2) ; MM (month of year, 1-12)
NumPut(Int, SystemTime, 2, "UShort")
Int := SubStr(YYYYMMDDHHMISS, 7, 2) ; DD (day of month)
NumPut(Int, SystemTime, 6, "UShort")
Int := SubStr(YYYYMMDDHHMISS, 9, 2) ; HH (hour in 24-hour time)
NumPut(Int, SystemTime, 8, "UShort")
Int := SubStr(YYYYMMDDHHMISS, 11, 2) ; MI (minute)
NumPut(Int, SystemTime, 10, "UShort")
Int := SubStr(YYYYMMDDHHMISS, 13, 2) ; SS (second)
NumPut(Int, SystemTime, 12, "UShort")
return % &SystemTime
}
MCM_FIRST:= 0x1000
MCM_SETCURSEL:= MCM_FIRST + 2
MyDate:= 20211115
WinActivate ahk_class AutoHotkeyGUI, ExempleCalendrier.ahk
dateASelectionnerDansCalendrier := ConvertNormalDateToSystemTime(20211115)
try
{
SendMessage MCM_SETCURSEL , , &dateASelectionnerDansCalendrier, SysMonthCal321, ahk_class AutoHotkeyGUI ; THIRD TRIAL
MsgBox % ErrorLevel
}
catch e
{
MsgBox % ErrorLevel
}
An other strange thing is that i always get the MCM_SETCURSEL message back in MyReturn variable. I already try to compile the script and run it as admin. I know that there is no multiselected option on my monthcal. Someone on Discord suggest me that MCM_SETCURSEL lparam was pointing to a systemtime. So how could i send my date to my monthcal ? Should i convert my actual date into a systemTime in an other way ? (speaking as a noob)
Thanks for any help !
I know how to capture mouse movement in general, relative to the screen, but what about in games where mouse movement is being used independently from the mouse's position on the screen?
For example, in a game your cursor is hidden but you can keep moving your mouse to the left infinitely and turn in circles, far further than there's room for your mouse to move on your screen. The game might lock your invisible mouse into the center, or let it move until it hits the edge of the window, but at that point any attempt to record the mouse's movement relative to the screen is useless.
So how can I capture / send raw mouse input. For example if I want to tell the player to turn 1000 degrees to the left via mouse input and record the mouse input from a player turning 1000 degrees to the left, how can I do both of those things?
My goal is ultimately to record a player's various control including mouse input to create one of those systems which record and play back user input. I've searched all over the ahk docs and Google and found nothing about capturing and sending raw mouse input.
This has been taken care of for you by a fantastic user on the AHK forums named evilC.
It's called mouse delta and tracks changes in raw mouse input.
I've posted one of the few different variants of his mouse delta script. Make sure you follow the link above to see all the different ones he has done.
Again, this is not my work.
; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
Class MouseDelta {
State := 0
__New(callback){
;~ this.TimeoutFn := this.TimeoutFunc.Bind(this)
this.MouseMovedFn := this.MouseMoved.Bind(this)
this.Callback := callback
}
Start(){
static DevSize := 8 + A_PtrSize, RIDEV_INPUTSINK := 0x00000100
; Register mouse for WM_INPUT messages.
VarSetCapacity(RAWINPUTDEVICE, DevSize)
NumPut(1, RAWINPUTDEVICE, 0, "UShort")
NumPut(2, RAWINPUTDEVICE, 2, "UShort")
NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
; It doesn't matter if the GUI is showing, it still exists
Gui +hwndhwnd
NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
this.RAWINPUTDEVICE := RAWINPUTDEVICE
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
OnMessage(0x00FF, this.MouseMovedFn)
this.State := 1
return this ; allow chaining
}
Stop(){
static RIDEV_REMOVE := 0x00000001
static DevSize := 8 + A_PtrSize
OnMessage(0x00FF, this.MouseMovedFn, 0)
RAWINPUTDEVICE := this.RAWINPUTDEVICE
NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
this.State := 0
return this ; allow chaining
}
SetState(state){
if (state && !this.State)
this.Start()
else if (!state && this.State)
this.Stop()
return this ; allow chaining
}
Delete(){
this.Stop()
;~ this.TimeoutFn := ""
this.MouseMovedFn := ""
}
; Called when the mouse moved.
; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
MouseMoved(wParam, lParam){
Critical
; RawInput statics
static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, pcbSize:=8+2*A_PtrSize, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
static axes := {x: 1, y: 2}
; Get hDevice from RAWINPUTHEADER to identify which mouse this data came from
VarSetCapacity(header, pcbSize, 0)
If (!DllCall("GetRawInputData", "UPtr", lParam, "uint", 0x10000005, "UPtr", &header, "Uint*", pcbSize, "Uint", pcbSize) or ErrorLevel)
Return 0
ThisMouse := NumGet(header, 8, "UPtr")
; Find size of rawinput data - only needs to be run the first time.
if (!iSize){
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
VarSetCapacity(uRawInput, iSize)
}
sz := iSize ; param gets overwritten with # of bytes output, so preserve iSize
; Get RawInput data
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
x := 0, y := 0 ; Ensure we always report a number for an axis. Needed?
x := NumGet(&uRawInput, offsets.x, "Int")
y := NumGet(&uRawInput, offsets.y, "Int")
this.Callback.(ThisMouse, x, y)
;~ ; There is no message for "Stopped", so simulate one
;~ fn := this.TimeoutFn
;~ SetTimer, % fn, -50
}
;~ TimeoutFunc(){
;~ this.Callback.("", 0, 0)
;~ }
}
There is a script that makes the effect when I click mouse buttons.
Code of this script.
#NoEnv
CoordMode Mouse, Screen
Setup()
~LButton::ShowRipple(LeftClickRippleColor)
~MButton::ShowRipple(MiddleClickRippleColor)
~RButton::ShowRipple(RightClickRippleColor)
Setup()
{
Global
RippleWinSize := 170
RippleStep := 4
RippleMinSize := 10
RippleMaxSize := RippleWinSize - 20
RippleAlphaMax := 0x4147
RippleAlphaStep := RippleAlphaMax // ((RippleMaxSize - RippleMinSize) / RippleStep)
RippleVisible := False
LeftClickRippleColor := 0xff0000
MiddleClickRippleColor := 0xff00ff
RightClickRippleColor := 0xffa500
DllCall("LoadLibrary", Str, "gdiplus.dll")
VarSetCapacity(buf, 16, 0)
NumPut(1, buf)
DllCall("gdiplus\GdiplusStartup", UIntP, pToken, UInt, &buf, UInt, 0)
Gui Ripple: -Caption +LastFound +AlwaysOnTop +ToolWindow +Owner +E0x80000
Gui Ripple: Show, NA, RippleWin
hRippleWin := WinExist("RippleWin")
hRippleDC := DllCall("GetDC", UInt, 0)
VarSetCapacity(buf, 40, 0)
NumPut(40, buf, 0)
NumPut(RippleWinSize, buf, 4)
NumPut(RippleWinSize, buf, 8)
NumPut(1, buf, 12, "ushort")
NumPut(32, buf, 14, "ushort")
NumPut(0, buf, 16)
hRippleBmp := DllCall("CreateDIBSection", UInt, hRippleDC, UInt, &buf, UInt, 0, UIntP, ppvBits, UInt, 0, UInt, 0)
DllCall("ReleaseDC", UInt, 0, UInt, hRippleDC)
hRippleDC := DllCall("CreateCompatibleDC", UInt, 0)
DllCall("SelectObject", UInt, hRippleDC, UInt, hRippleBmp)
DllCall("gdiplus\GdipCreateFromHDC", UInt, hRippleDC, UIntP, pRippleGraphics)
DllCall("gdiplus\GdipSetSmoothingMode", UInt, pRippleGraphics, Int, 4)
MouseGetPos _lastX, _lastY
SetTimer MouseIdleTimer, 5000
Return
MouseIdleTimer:
MouseGetPos _x, _y
if (_x == _lastX and _y == _lastY)
ShowRipple(MouseIdleRippleColor, _interval:=20)
else
_lastX := _x, _lastY := _y
Return
}
ShowRipple(_color, _interval:=10)
{
Global
if (RippleVisible)
Return
RippleColor := _color
RippleDiameter := RippleMinSize
RippleAlpha := RippleAlphaMax
RippleVisible := True
MouseGetPos _pointerX, _pointerY
SetTimer RippleTimer, % _interval
Return
RippleTimer:
DllCall("gdiplus\GdipGraphicsClear", UInt, pRippleGraphics, Int, 0)
if ((RippleDiameter += RippleStep) < RippleMaxSize) {
DllCall("gdiplus\GdipCreatePen1", Int, ((RippleAlpha -= RippleAlphaStep) << 24) | RippleColor, float, 3, Int, 2, UIntP, pRipplePen)
DllCall("gdiplus\GdipDrawEllipse", UInt, pRippleGraphics, UInt, pRipplePen, float, 1, float, 1, float, RippleDiameter - 1, float, RippleDiameter - 1)
DllCall("gdiplus\GdipDeletePen", UInt, pRipplePen)
}
else {
RippleVisible := False
SetTimer RippleTimer, Off
}
VarSetCapacity(buf, 8)
NumPut(_pointerX - RippleDiameter // 2, buf, 0)
NumPut(_pointerY - RippleDiameter // 2, buf, 4)
DllCall("UpdateLayeredWindow", UInt, hRippleWin, UInt, 0, UInt, &buf, Int64p, (RippleDiameter + 5) | (RippleDiameter + 5) << 32, UInt, hRippleDC, Int64p, 0, UInt, 0, UIntP, 0x1FF0000, UInt, 2)
Return
}
How this script to work:
I often do double click left mouse button. I want to have the same effect on my gif was and when I double click left mouse button.
Could anyone of you tell what needs to be done to effect other color, when I make double click left mouse button?
Thanks.
First variant:
~LButton::
if(A_PriorHotkey = "~LButton" && A_TimeSincePriorHotkey < 200){
RippleVisible := False
ShowRipple(0x2E0854)
} else {
ShowRipple(LeftClickRippleColor)
}
return
When I click left mouse button shows the color set for left mouse button, but double-click to change the color to the color for double-click.
Second variant:
DoubleClickWait := 200
~LButton::
SetTimer, SingleClick, Off
if(A_PriorHotkey = "~LButton" && A_TimeSincePriorHotkey < DoubleClickWait){
ShowRipple(0x2E0854)
} else {
SetTimer, SingleClick, -%DoubleClickWait%
}
return
SingleClick:
ShowRipple(LeftClickRippleColor)
return
Ripple effect are make after DelayTime (200 ms in example). If within 200 ms after the first mouse click will not be second click will show the color for a single click. If 200 ms is committed another click, will show the color for the double-click.
Many thanks Capn Odin AutoHotkey user.
I was wondering if there was a way to change the int value of an auto hot key script to a double, as I am trying to "fine tune" how fast the cursor moves and would like to use a decimal value. The only way I can think of being able to input a decimal value would be to use double, but I can not figure out how to change the int values to double(or if it is even possible).
Here is the code and thank you very much in advance!!
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
; NRA
NRA := 1
; NR
~LButton::
while GetKeyState("LButton") & NRA
{
DllCall("mouse_event", uint, 1, int, 0, int, 1, uint, 0, int, 0)
Sleep, 15
DllCall("mouse_event", uint, 1, int, 0, int, 1, uint, 0, int, 0)
Sleep, 5
}
return
; keys
Insert::ExitApp
delete::suspend
I am trying to change the Y values shown below to be decimal points
DllCall("mouse_event", uint, 1, int, 0, int, Y, uint, 0, int, 0)
Sleep, 15
DllCall("mouse_event", uint, 1, int, 0, int, Y, uint, 0, int, 0)
I know that the higher I change that Y value, the faster it goes, but I was hoping to be able to put a value (like 1.5 or 2.7 as an example) into that Y postion.
In AutoHotkey v1.1, floating-point literals are actually just strings
and they have a default precision of 6 decimals for floating-point output, which can be changed easily by SetFormat, Format(), Round(), SubStr(), Floor() to display them. Source.
If you are planning on doing larger precision Math you are going to need to use a Math library.
I'm really not sure about your code, since you never specified what variable or showed any math where you needed more precision? Did you leave something out?
Double:
NRA := 1
MsgBox % format("{1:0.15f}", NRA) ; Double precision
Based on your edit:
Unfortunately mouse_event only excepts DWORD and will only accept an Integer value in the range 0 through 4,294,967,295.
Your only choice it seems is to increment by 1 for maximum control.
I am writing a function that would loop imagesearch but I am having trouble figuring out how to pass a dynamic variable with the options allowed with Arrays (Such as Array0 which retrieves the total count of records in array, and Array%A_Index% which when used with a Loop displays each name as it goes through the list)
arrowList = C:\AHK\LeftArrow.png|C:\AHK\LeftArrow1.png|C:\AHK\GreenLeftArrow.png
StringSplit, arrowArray, arrowList, |
buildList = C:\AHK\build1.png|C:\AHK\build2.png|C:\AHK\build3.png|C:\AHK\build4.png|C:\AHK\build5.png
StringSplit, buildArray, buildList, |
SearchArray("arrowArray","buildArray")
SearchArray(ByRef x, ByRef y)
{
Loop, %x%
{
x2get := %xA_Index%
ImageSearch, imageX, imageY, 0, 0, A_ScreenWidth, A_ScreenHeight, *25 %x2get%
tooltip, searching for %x2get% , 0, 0
If ErrorLevel = 0
{
Loop, % y%0%
{
y2get := % y%A_Index%
ImageSearch, imageX, imageY, 0, 0, A_ScreenWidth, A_ScreenHeight, *25 %y2get%
tooltip, searching for %y2get% , 0, 0
If ErrorLevel = 0
{
MouseClick, Left, imageX, imageY,
Sleep 1000
}
}
}
}
}
You have some problems with how you're calling the variables. You're not actually using "real" arrays there, you're using what's called "pseudo-arrays". You can read about them in the documentation, here.
They're an old way AHK handled arrays, and I strongly suggest you try to move over to using "real" arrays in AHK. You should also update your version of AHK to the latest if you haven't already - http://ahkscript.org/download/.
I changed how the script called some variables, and it should work now, try this, note I've commented the lines I changed:
arrowList = C:\AHK\LeftArrow.png|C:\AHK\LeftArrow1.png|C:\AHK\GreenLeftArrow.png
StringSplit, arrowArray, arrowList, |
buildList = C:\AHK\build1.png|C:\AHK\build2.png|C:\AHK\build3.png|C:\AHK\build4.png|C:\AHK\build5.png
StringSplit, buildArray, buildList, |
SearchArray("arrowArray", "buildArray")
SearchArray(ByRef x, ByRef y)
{
Loop, % %x%0 ; Changed this line
{
x2get := %x% A_Index ; Changed this line
ImageSearch, imageX, imageY, 0, 0, %A_ScreenWidth%, %A_ScreenHeight%, *25 %x2get% ; Changed this line
tooltip, searching for %x2get% , 0, 0
If ErrorLevel = 0
{
Loop, % %y%0 ; Changed this line
{
y2get := % %y% A_Index ; Changed this line
ImageSearch, imageX, imageY, 0, 0, %A_ScreenWidth%, %A_ScreenHeight%, *25 %y2get% ; Changed this line
tooltip, searching for %y2get% , 0, 0
If ErrorLevel = 0
{
MouseClick, Left, %imageX%, %imageY% ; Changed this line
Sleep 1000
}
}
}
}
}
If you're interested in how a solution using "real" arrays would look, here's an example of that. Just make sure you're running the latest version of AHK before you try it, otherwise it might fail.
arrowList := "C:\AHK\LeftArrow.png|C:\AHK\LeftArrow1.png|C:\AHK\GreenLeftArrow.png"
arrowArray := StrSplit(arrowList, "|")
buildList := "C:\AHK\build1.png|C:\AHK\build2.png|C:\AHK\build3.png|C:\AHK\build4.png|C:\AHK\build5.png"
buildArray := StrSplit(buildList, "|")
SearchArray(arrowArray, buildArray)
SearchArray(firstArray, secondArray) {
; Iterate through the first array
for outerIndex, outerValue in firstArray {
; outerIndex = Index of the current element; 1, 2, etc...
; outerValue = The value of the string at that index
Tooltip, Searching for %outerValue%, 0, 0
ImageSearch, imageX, imageY, 0, 0, %A_ScreenWidth%, %A_ScreenHeight%, *25 %outerValue%
if (ErrorLevel = 0) {
; Iterate through the second array
for innerIndex, innerValue in secondArray {
; innerIndex = Index of the current element; 1, 2, etc...
; innerValue = The value of the string at that index
Tooltip, Searching for %innerValue%, 0, 0
ImageSearch, imageX, imageY, 0, 0, %A_ScreenWidth%, %A_ScreenHeight%, *25 %innerValue%
if (ErrorLevel = 0) {
MouseClick, Left, %imageX%, %imageY%
Sleep, 1000
}
}
}
}
}