Change mouse cursor across environment with AutoIt - autoit

I'm hoping this is feasible... I made a program using AutoIt that resides in the system tray. One of the tray items runs a function that waits for the user to click on a window to get the window title (it can be any window, not necessarily one made from AutoIt. This part works flawlessly.
I would like for the function to change the mouse cursor to the cross while waiting for the user's click. I have tried using GUISetCursor(3), but from my understanding this only changes the cursor for an AutoIt GUI window.
How could I go about changing the mouse cursor for the user's environment, not just for an AutoIt window?

You can do it so:
#include <Misc.au3>
#include <WindowsConstants.au3>
GetTitleByClick()
Func GetTitleByClick()
Local $hCursor = GUICreate('', 48, 48, -1, -1, $WS_POPUP, $WS_EX_TOPMOST)
WinSetTrans($hCursor, '', 10)
GUISetCursor(3, 1, $hCursor)
GUISetState(#SW_SHOW, $hCursor)
; get title bar position
Local $pos
Do
$pos = MouseGetPos()
WinMove($hCursor, '', $pos[0]-24, $pos[1]-24)
Sleep(10)
Until _IsPressed('01')
GUIDelete($hCursor)
; block mouse
_MouseTrap($pos[0], $pos[1], $pos[0]+1, $pos[0]+1)
; click position - activates the window
MouseClick('left', $pos[0], $pos[1])
; unblock mouse
_MouseTrap()
; get the title of the active window
Local $sTitle = WinGetTitle('[ACTIVE]')
Return MsgBox(0, 'TITLE', $sTitle)
EndFunc

Thatnks to Richard's comment, and a reply in the AutoIt forums that linked me to AutoIt's _WinAPI_SetSystemCursor function, I was able to get this working.
I copied the cross cursor I wanted from %SystemRoot%\Cursors (specifically, I copied cross_i.cur) to put in my script's source directory.
Then, in the function that executes the brute of the program, I added the following lines:
Func FuncName()
;backs up the user's arrow cursor
Local $hPrev = _WinAPI_CopyCursor(_WinAPI_LoadCursor(0, 32512))
;backs up the user's ibeam cursor
Local $iPrev = _WinAPI_CopyCursor(_WinAPI_LoadCursor(0, 32513))
;changes the user's arrow cursor
_WinAPI_SetSystemCursor(_WinAPI_LoadCursorFromFile(#ScriptDir & "\cross.cur"),32512)
;changes the user's ibeam cursor
_WinAPI_SetSystemCursor(_WinAPI_LoadCursorFromFile(#ScriptDir & "\cross.cur"),32513)
; Do the code you want to execute
;restores the user's default cursor
_WinAPI_SetSystemCursor($hPrev,32512)
;restores the user's ibeam cursor
_WinAPI_SetSystemCursor($iPrev,32513)
EndFunc
This allowed me to accomplish what I needed.

Related

Scilab: How to use cbmenu in xclick()

I do not understand the explanation of the output argument cbmenu in the Scilab documentation of xclick.
It says:
cbmenu: String: callback associated to a menu if xclick returns due to a click on a menu.
I did not find any example in the web so I ask here. I have coded a snippet which lumps together the elements which may be relevant for cbmenu. The snippet does nothing, when I click on CLICK. Could anyone alter/complement/revise the code so that it does something - whatever it is to give me a clue what could be done with cbmenu?
xdel()
x=[-1 +1];
cf=figure(0);
plot(x,x)
m=uimenu(cf,'label','CLICK','callback','two=1+1');
[ibutton,xcoord,yxcoord,iwin,cbmenu]=xclick();
Kind regards
Rosestock
This is a minimal script which explains what the 5th output argument of xclick() can do:
xdel()
x=[-1 +1];
winnum=1; win=string(winnum);
cf=figure(winnum);
plot(x,x)
C=["Green" "Red" "Abort"];//case name strings
addmenu(winnum, C(1)); C1="execstr("+C(1)+"_"+win+"(1))";
addmenu(winnum, C(2)); C2="execstr("+C(2)+"_"+win+"(1))";
addmenu(winnum, C(3)); C3="execstr("+C(3)+"_"+win+"(1))";
while %t
[!,!,!,!,cbmenu]=xclick();
//Get the clicked option by cbmenu
if cbmenu==C1, cf.background=3; end
if cbmenu==C2, cf.background=5; end
if cbmenu==C3, break, end
end
If I get your intentions right, you want to create a custom menu. Here is a small demo, how to bulid custom menu elements, and also how to use locate to get back coordinates (but you don't need xclick to sense menu clicking). This code does not use explicitly cbmenu, but it is not necessary to get it work. If you run the code, first click the "Select range" menu, then click two times on the graph. Then the "Regression" menu is activated, and you can choose "Linear regession". By clicking "Exit program", the execution aborts. Not all nenu functions are implemented, they are there only to demonstrate a multilayer structure. I hope it helps!
//Interactive menu demo
// Scilab 5.5.2
// 2016.12.20. Attila Eredics
//
//Attention!
//Do not close the graphic window with the original x symbol
// while the program is running,
// because the program will run infinitely!
// But you can stop it in the Consol with: Ctrl+C and then typing: abort
clc;
clear;
lines(0);
//artificial data vectors
row = 100;
t=gsort(rand(row,1),'r','i'); //time
c=10*t+8; //concentration
c=c+rand(c); //add some noise
//graphic window
scf(0); clf(0);
w=gcf(); //get current figure
//new menu elements
m3=uimenu(w,"Label","Select range","Callback","m=3");
m4=uimenu(w,"Label","Regression","Enable","off","ForegroundColor","0.5|0.5|0.5");
m41=uimenu(m4,"Label","Linear","Callback","m=41","Enable","on");
m42=uimenu(m4,"Label","Nonlinear","Callback","m=42","Enable","on");
m5=uimenu(w,"Label","Save results","Callback","m=5");
m6=uimenu(w,"Label","Exit program","Callback","abort","ForegroundColor","1|0|0");
plot2d(t,c,style=-5,frameflag=6); //plot the data
xtitle("","time","concentration"); //axis labels
while %T //infinite loop
//-------------wait for user action (click on a menu)-------
m=0;
while m<1
xpause(1e4); //pause 10ms
end
//------------------the menu actions-------------------------
if m==3 then //Select range
mprintf("\nChoose 2 points (click on the graph)!");
coord=locate(2); //locate two clicks
disp(coord); //coord: according to the axes
//Select range in t vector
for i=1:row-1
if coord(1,1)>=t(i) & coord(1,1)<t(i+1) then //t(i) <= 1st click < t(i+1)
i1=i;
end
if coord(1,2)>=t(i) & coord(1,2)<t(i+1) then //t(i) <= 2nd click < t(i+1)
i2=i;
end
end
//selected range
clear tt;
clear cc;
tt=t(i1:i2);
cc=c(i1:i2);
plot2d(tt,cc,style=-5); //plot selected points
h2=gce();
h2.children.mark_foreground=3; //green
m4.Enable="on"; //enable Regression menu
m4.ForegroundColor="0|0|0"
m3.Enable="off"; //Disable selection menu
m3.ForegroundColor="0.5|0.5|0.5"
elseif m==41 then //linear regression of the selected points
mprintf("\nLinear regression");
[a,b,sig]=reglin(tt',cc');
plot2d([tt(1),tt($)],a*[tt(1),tt($)]+b,style=2); //blue line
m41.Enable="off"; //disable Linear regression menu
m41.ForegroundColor="0.5|0.5|0.5"
elseif m==42 then //Nonlinear regression
mprintf("\nNot implemented yet!");
elseif m==5 then //Save
mprintf("\nNot implemented yet!");
end
end

How to expand a tree view using AutoIt

The UI is as following:
The tool "AutoIt Window Info" can only locate the elements in red (red rectangle area), the sub items can not be located.
So how can I expand or operate these items?
Usually Windows controls can be accessed using keystrokes as well.
In the screen-dump the Farmtt element is selected. That would be your starting point.
You may try:
Send("{DOWN}") Move down an element.
Send("{TAB}") Navigate to next control (button, checkbox, etc)
Send("{NumPadMult}") Recursively expands folders in a SysTreeView32.
Send("{ENTER}") ENTER key on the main keyboard
etc.
Reference:
https://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm
There are two things over here:
1) Use the following code snippet:
;Gets the handle for the text
Func readFirstlevelTreeNodes($hWndCtrl)
Local $firstItemHandle = _GUICtrlTreeView_GetFirstItem ($hWndCtrl)
Local $iCount = _GUICtrlTreeView_GetSiblingCount( $hWndCtrl, $firstItemHandle )
Dim $aRet[$iCount]
$aRet[0] = $firstItemHandle
For $index = 1 To $iCount - 1
$aRet[$index] = _GUICtrlTreeView_GetNextSibling ( $hWndCtrl, $firstItemHandle )
$firstItemHandle = $aRet[$index]
Next
getTreeNodeTextList($hWndCtrl,$aRet)
EndFunc
; Gets the text for given sibling node handle lists
Func getTreeNodeTextList($hWndCtrl,$aRet)
ConsoleWrite("Tree Node first level list"&#CRLF)
For $index = 0 To Ubound($aRet) -1
ConsoleWrite(_GUICtrlTreeView_GetText ( $hWndCtrl, $aRet[$index] )&#CRLF)
Next
EndFunc
You may see the output for the first level tree nodes.
2) If you still dont see the output then please verify the control handle values and window handles. If they are correct and it still doesnt show the first level tree nodes then try running your sciTE editor as administrator.
I think this should help.

"Down arrow" moves cursor to end of line - how to turn it off

In IPython Notebook / Jupyter, arrow up/down keystrokes within a cell are handled by CodeMirror (as far as I can tell). I use these actions a lot (re-bound to control-p / control-n) to move between cells; but at the end of every cell, the cursor moves to end of line first before jumping to the next cell. This is counter-intuitive and, to me, rather distracting.
Is there any way to configure CodeMirror to make this move down to be just that - a move down?
Thanks!
The moving-to-next-cell behavior is defined by IPython wrapper code, which probably checks whether the cursor is at the end of the current cell, and overrides the default CodeMirror behavior in that case. You'll have to find that handler and somehow replace it with one that checks whether the cursor is on the last line. (I don't know much about IPython, only about CodeMirror, so I can't point you at the proper way to find and override the relevant code. They might have bound the Down key, or they might have overridden the goLineDown command.)
Knowing that I wasn't alone in wanting to skip the "going to end of line" behavior when going down from the last line of a code cell, I investigated that behavior and found out that:
it's CodeMirror that goes to the end of line when you type down in the last line of a code cell (file: codemirror.js ; "methods": findPosV and moveV)
and it's IPython that decides what to do with the "down" event after it has been handled by CodeMirror (file: cell.js ; class: Cell ; method: handle_codemirror_keyevent) ; looking at the code, I saw that IPython ignores the event when not at the last character of the last line.
This essentially confirms Marijin's answer.
The primary goal being to jump to the next cell, I think there's no need to prevent CodeMirror from going to the end of that line. The point is to force IPython to handle the event anyway.
My solution was to change the code from Cell.prototype.handle_codemirror_keyevent to this:
Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
var shortcuts = this.keyboard_manager.edit_shortcuts;
var cur = editor.getCursor();
if((cur.line !== 0) && event.keyCode === 38){
// going up, but not from the first line
// don't do anything more with the event
event._ipkmIgnore = true;
}
var nLastLine = editor.lastLine();
if ((event.keyCode === 40) &&
((cur.line !== nLastLine))
) {
// going down, but not from the last line
// don't do anything more with the event
event._ipkmIgnore = true;
}
// if this is an edit_shortcuts shortcut, the global keyboard/shortcut
// manager will handle it
if (shortcuts.handles(event)) {
return true;
}
return false;
};
This code provides the desired behavior for the "down-arrow" key (almost: the cursor still goes to the end of the line, except that we don't see it, as we're already in another cell at that point), and also handles the "up-arrow" key similarly.
To modify the handle_codemirror_keyevent prototype, you have two possibilities:
You edit the cell.js file and change the code of the prototype to the code I gave above. The file is in <python>/Lib/site-packages/IPython/html/static/notebook/js or something similar depending on you distro
Much better, after the page is loaded, you change that prototype dynamically by doing this:
IPython.Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
<same code as above>
};
You can do that in your custom.js for example, or create an extension to do it (that's what I did).

Assigning a Hotkey in Autoit

I want to use space bar to "click" a specific button in a window with autoit (without focusing the program?), like a "start" button in a game.
I tried to use ControlClick function but It's doing nothing by the way. I think i'm doing something wrong.
HotKeySet( "{space}", "MyFunction")
Func MyFunction()
ControlClick ( "title", "text", controlID [, button = "left" [, clicks = 1 [, x [, y]]]] )
EndFunc
Is it something like that?
Your way doing it is good. You are missing the title and the controlID of the ControlClick function. The 1st and 3rd parameter should be set to the title of the window and the control ID of the control.
To get those use the AutoIt tool that comes with autoit installation.
Set those properly and the code should work.
U can use it like this.
First start AutoIt info program to get desired coordinates ( place where u want to click ), use finder tool to get coorinates of mouse and edit it in a script.
So when u run ur script it will do nothing untill u press Spacebar, then it will run function MyFunction 1 time.
So it move mouse on given position, make pause of half second then left click on desired position $x and $y 1 time and srcipt stop untill u press space again then he make same procedure.
I added exit function so u can turn it off by just press ESC key.
HotKeySet( "{SPACE}", "MyFunction")
HotKeySet( "{ESC}", "CloseScript")
Global $x = 519 ; x is first value of mouse position
Global $y = 900 ; y is second value of mouse position
While 1
sleep(10)
Wend
Func MyFunction()
MouseMove($x, $y, 2) ; moves the mouse pointer do mouse position with speed 2
Sleep(500) ; wait 500 ms half of second ( delay )
MouseClick("left", $x, $y, 1, 2) ; now click left mouse key on mouse position, 1 click with speed 2
EndFunc
Func CloseScript()
Exit
EndFunc

AutoIt Wait for a Control Element to Appear

I'm attempting to automate an application using AutoIt, and I need to wait for a control to appear within the application before the automation can begin. This control loads shortly after the application starts, but it does not change the window title. How do I wait for the control to appear?
To get a handle to a control on another GUI you need to use the AutoIt Window Info Tool to identify that control. To get the classname of the control go to the tab "Control" and look up the value for "ClassnameNN". Now you can use this value as I did in the example below.
Of course you need to replace "Button1" with the information you got from the AutoIt Info Tool and modify the window titles accordingly.
Global $hCtrl = 0, $Waiting = True
; your GUI loop
While (1)
If $Waiting And WinExists("Title of OtherApp.exe") Then
$hCtrl = ControlGetHandle("Title of OtherApp.exe", "", "Button1")
If $hCtrl Then
; we got the handle, so the button is there
; now do whatever you need to do
GUICtrlCreateLabel("Button is there!", 10, 10)
$Waiting = False
EndIf
EndIf
$iMsg = GUIGetMsg()
Switch $iMsg
Case $GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd

Resources