Why is HotkeySet() not working with clipboard data? - clipboard

My clipboard controller could have several items copied to the clipboard when using a hotkey (CTRL + SHIFT + Q), instead of only one item, and pastes all at once (CTRL + SHIFT + W), or paste any of the first 10 items directly (CTRL + SHIFT + 1 … 9). Another option is to clear the clipboard (CTRL + SHIFT + -).
It works just for several copy and pastes, but then trying to make a copy operation nothing is added to the buffer. I couldn't find a reason for this.
Code (problem should be in the addToClipboard() or getAll()) :
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <array.au3>
Global $clipBoard[50]=[""]
Global $counter = 0
HotKeySet("^+q","addToClipboard")
HotKeySet("^+-","emptyAll")
HotKeySet("^+w","getAll")
HotKeySet("^+1","get1")
HotKeySet("^+2","get2")
HotKeySet("^+3","get3")
HotKeySet("^+4","get4")
HotKeySet("^+5","get5")
HotKeySet("^+6","get6")
HotKeySet("^+7","get7")
HotKeySet("^+8","get8")
HotKeySet("^+9","get9")
$hGUI = GuiCreate("Clipboard Controller", 100, 100,Default,Default,$WS_SIZEBOX)
GUISetState()
Func addToClipboard()
Send ("^c")
$copied = ClipGet()
$clipBoard[Mod($counter,50)] = $copied
$counter +=1
EndFunc
Func getByIndex($i)
$statement = $clipBoard[$i]
ClipPut($statement)
Send("^v")
EndFunc
Func getAll()
$statement =""
For $i In $clipBoard
If $i <> "" Then
$statement &= $i & #CRLF
EndIf
Next
ClipPut($statement)
Send("^v")
EndFunc
Func emptyAll()
For $i=0 To 49
$clipBoard[$i]=""
Next
ClipPut("")
EndFunc
Func get1()
getByIndex(0)
EndFunc
Func get2()
getByIndex(1)
EndFunc
Func get3()
getByIndex(2)
EndFunc
Func get4()
getByIndex(3)
EndFunc
Func get5()
getByIndex(4)
EndFunc
Func get6()
getByIndex(5)
EndFunc
Func get7()
getByIndex(6)
EndFunc
Func get8()
getByIndex(7)
EndFunc
Func get9()
getByIndex(8)
EndFunc
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd

Problem is an old trap...
It takes a small amount of time to copy to the clip board
especially large items..try a sleep after the Send
Func addToClipboard()
Send ("^c")
sleep(1000) ; try different values
$copied = ClipGet()
$clipBoard[Mod($counter,50)] = $copied
$counter +=1
EndFunc
anyway like your script..idea

The problem is the code for addToClipboard is running while the user still has the keys pressed down. As a result, the Send command designed to send just Ctrl+C is in effect sending Ctrl+Shift+C, so the text is never copied.
The solution is to wait for the user to raise those keys, using the _IsPressed function, then once all keys are released, execute the code. It may also be wise to disable the hotkey when you enter the function (and re-enable when you leave) so that holding the hotkey down for a long time doesn't keep triggering the function.
An alternative would be to send the WM_COPY message directly to the control with focus. This is not guaranteed to work for every control (though I'd be very surprised if it didn't). This would be a far more reliable method.

hope this is the end of the problem , I found another way to set/get data from clipboard , functions : _ClipBoard_SetData () & _ClipBoard_GetData() from library <Clipboard.au3> , after trying them it worked well , after all it seems like the problem was in setting and getting data from the clipboard..
will come later isA to assure whether its finally correct or not

Related

Passing Command Line Argument to SwitchCase in AutoIt

I have a script that has a GUI and I have been running with a start button using the below code:
Case $StartButton
I would also like to try scheduling this using Windows TaskScheduler to run every morning at 8 AM EST. What would be the best way to add a condition to either start with the start button OR when TaskScheduler runs at 8 AM EST (or any specific time)? I am hesitant to just do 8 AM condition as it may increase processing a lot always looking at the time.
Essentially what I am looking to have happen is for my computer to auto-unlock (login?) using task scheduler and run this AutoIt script which has been compiled to exe.
FilePath is: C:\Users\robert\OneDrive\Desktop\TempFile.exe
Block of relevant code is below:
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Save
SaveOptions()
Case $StartButton
;TAB1 of GUI
If WinExists("[CLASS: QT373947473845]") Then
$oBlah = WinGetHandle("[CLASS: QT373947473845]")
$BSLoc = WinGetPos ("[CLASS: QT373947473845]")
If $BSLoc[0] <> 0 or $BSLoc[1] <> 0 or $BSLoc[2] <> 800 or $BSLoc[3] <> 600 Then
WinSetState ( $oBlah, "", #SW_MINIMIZE )
sleep(500)
WinActivate($oBlah)
WinWaitActive($oBlah)
WinMove($oBlah, "", 0, 0, 800, 600)
sleep(2000)
Else
WinActivate($oBlah)
WinWaitActive($oBlah)
sleep(2000)
EndIf
Endif
EndSwitch
WEnd
I have thousands of lines of other code within the case but I tried to limit it as that portion is irrelevant
The Case $StartButton is the line where I am trying to do an OR if run by TaskManager. I have read you cannot do an OR function within a switch case but if you do 2 cases without a break it is the same thing?
I read some documentation and saw I can add a “/prim1=value” to the end of the command line and it will pass the prim1 argument to $CmdLine[0] but I can’t seem to get it working properly.
Review the documentation.
Particularly this part:
So if you were to use the compiled executable by passing commandline
parameters:
myProg.exe param1 "This is a string parameter" 99
$CmdLine[0] ; this equals 3 (because there are 3 command line parameters)
$CmdLine[1] ; This contains "param1".
$CmdLine[2] ; This contains "This is a string parameter".
$CmdLine[3] ; This contains 99.
So then just modify the code so that it behaves differently if $CmdLine[1] = something.
As for the switch case: that is inside of a message loop for the GUI and the code in the Case $StartButton part of the switch block is run when the start button is pressed and $nMsg is equal to the control ID of the start button ($StartButton).
If you want to run this code at some other time what I would do it just move all of that code into its own function:
Func onStartClick()
; start button code here
Endfunc
And then just call onStartClick() in the switch block:
$nMsg = GUIGetMsg()
Switch $nMsg
Case $StartButton
onStartClick()
Case $someOtherButton
; someOtherButton code...etc
EndSwitch
And then you can also call this function if there is a particular command line param (place this code before the Switch...EndSwitch block, not inside it):
If $CmdLine[0] >= 1 And $CmdLine[1] = "param1" then
; other code to run when started with "program.exe param1"
onStartClick()
EndIf
So the entire thing would look like this:
Func onStartClick()
; start button code here
Endfunc
If $CmdLine[0] >= 1 And $CmdLine[1] = "param1" then
; other code to run when started with "param1"
onStartClick()
EndIf
$nMsg = GUIGetMsg()
Switch $nMsg
Case $StartButton
onStartClick()
Case $someOtherButton
; someOtherButton code...etc
EndSwitch

Optimizing Tab Control With AutoIT

So I wrote this to simulate a program that would have a start and stop feature, and has a tab design. Right now there is a tab that has a RichEdit object intended to be a running log.
As you can see, after we "start" the program I put just some milliseconds of sleep to simulate running instructions. I created a function to check for requests that would be called on a larger scale randomly throughout code to ping the GUI per say.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
GUISetState( #SW_SHOW ) ; initialize the gui
While True
CheckRequests()
WEnd
EndFunc ;==>Example
Func Start()
while true
Sleep(100)
CheckRequests()
WEnd
EndFunc
Func Stop()
EndFunc
Func CheckRequests()
$iMsg = GUIGetMsg()
while $iMsg <> 0
Select
Case $iMsg = $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $iMsg = $h_tabs
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Case $iMsg = $h_startButton
Start()
Case $iMsg = $h_stopButton
Stop()
EndSelect
$iMsg = GUIGetMsg()
WEnd
EndFunc
At about 500ms sleep, the lag when switching tabs is visible.
My question: On a larger scale, is this how we would handle/update things that are specific to a tab while running a larger program? If not, what would be a more efficient way of updating tab specific properties while running a larger overall program.
I have also seen a design recently where all the tabs and related components were their own GUI's but I am not sure the relevance of everything being its own GUI and if it pertains to this question.
Any help or clarification is greatly appreciated, I am new to AutoIT and trying to figure out some do's and dont's as well as efficiency.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
_GUICtrlRichEdit_AppendText($h_logRichEdit, "{\rtf {Showing \b1 Rich Text \b0}")
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
; Register Windows message.
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState( #SW_SHOW ) ; initialize the gui
GuiMessageLoop()
EndFunc
Func GuiMessageLoop()
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $h_startButton
Start()
Case $h_stopButton
Stop()
EndSwitch
WEnd
EndFunc
Func Start()
ConsoleWrite('# Sleep' & #CRLF)
Sleep(5000)
ConsoleWrite('# Awake' & #CRLF)
EndFunc
Func Stop()
EndFunc
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
Local $iLoWord = _WinAPI_LoWord($lParam)
Local $iHiWord = _WinAPI_HiWord($lParam)
ConsoleWrite('- WM_NOTIFY' & ' ' & $iLoWord & ' ' & $iHiWord & #CRLF)
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Try this example. It uses GuiRegisterMessage to capture
WM_NOTIFY Windows messages. WM_NOTIFY is not an ideal
message code for this, though have not found something
more suitable for only changing Tabs.
The code to hide and show the Rich Edit control has been
moved into the WM_NOTIFY function so that each time a
message is received, the Tab hide and show code executes.
ConsoleWrite is used to show what the events of interest
are doing during testing. If your editor has a output
console pane, then you may be able to view the writes to
the console pane.
If an event such as function Start takes a long time,
then multi-processing may help to allow the Gui to
remain responsive with the message loop.
Want a do don't, avoid (cyclic) recursive function
calls and avoid getting trapped in loops.
Additional References:
Windows Message Codes
AutoIt Wiki about Tabs

Invert mousewheel direction for a particular window with AutoIt?

I am using a program that for some reason uses mousewheel+up to zoom out and mousewheel+down to zoom in, I'd like to revert that so it improves my workflow as all the other programs that I use do the inverse. So I need to do that in AutoIt.
What I need it to do is wait for a mousewheel event, then prevent the default and scroll the mousewheel in the opposite correct direction.
My script is as follows (updated), I used the MouseOnEvent.au3 ( https://www.autoitscript.com/forum/topic/64738-mouseonevent-udf/ ) for the events, however it seems like it executes only once because I remove the event with _MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN/UP_EVENT) and try to reattach it, but if I don't do that, then I get some weird huge lag on my machine,
#include <AutoItConstants.au3>
#include <Misc.au3>
#include <MouseOnEvent.au3>
#include <TrayConstants.au3>
_MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT, 'MouseWUp')
_MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, 'MouseWDown')
Func MouseWUp($iEvent)
If WinActive("SAI") Then
Switch $iEvent
Case $MOUSE_WHEELSCROLLUP_EVENT
;TrayTip("", "Mousewheel Up", 2, $TIP_ICONHAND + $TIP_NOSOUND)
_MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT)
MouseWheel($MOUSE_WHEEL_DOWN, 2)
_MouseSetOnEvent($MOUSE_WHEELSCROLLDOWN_EVENT, 'MouseWDown')
EndSwitch
EndIf
EndFunc
Func MouseWDown($iEvent)
If WinActive("SAI") Then
Switch $iEvent
Case $MOUSE_WHEELSCROLLDOWN_EVENT
;TrayTip("", "Mousewheel Up", 2, $TIP_ICONHAND + $TIP_NOSOUND)
_MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT)
MouseWheel($MOUSE_WHEEL_UP, 2)
_MouseSetOnEvent($MOUSE_WHEELSCROLLUP_EVENT, 'MouseWUp')
EndSwitch
EndIf
EndFunc
Func Main()
While 1
Sleep(200)
WEnd
Exit
EndFunc
Call("Main")

How to handle optional windows in Autoit?

I am automating a software installation in Windows7 using AutoIt.
During the installation, in between if a error window appears. I want to click ENTER.
If the error window not appears then I should NOT do anything. Simply its should go to the next section.
I have tried "WinActive and WinWaitActive" But its waiting for the window to appear. If window not appears its not going to the next screen.
Any idea how to handle this situation?
Do a while loop:
$w = 0
While($w = 0)
If(WinActive("ERROR WINDOW"))Then
Send("{ENTER}")
$w = 1
ElseIf(ControlGetText("YOUR WINDOW", "", "[CLASS:Static; INSTANCE:2]") <> "SOME TEXT") Then
$w = 1
;and something else
EndIf
Sleep(1000)
WEnd
AdlibRegister() is the right choice. From the help file:
"... typically to check for unforeseen errors. For example, you could use adlib in a script which causes an error window to pop up unpredictably."
Each 100 ms (may be adjusted) the function is called to check the appearing of your error dialog:
Global $sErrorWindow = 'ErrorDialogName'
Global $iDelayHowOftenDoTheFunctionCall = 100
AdlibRegister('_isErrorWindowDisplayed', $iDelayHowOftenDoTheFunctionCall)
Func _isErrorWindowDisplayed()
If WinActive($sErrorWindow) <> 0 Then
WinActivate($sErrorWindow) ; just to be sure that the ENTER command is on the correct window/dialog
; either do
Send('{ENTER}')
; or
ControlClick('title', 'text', 'controlID')
EndIf
EndFunc
; do your software installation processing here
; ...
; ...
; don't forget to unregister the function at the end
AdlibUnRegister('_isErrorWindowDisplayed')

VIM: Why is this function hanging VIM?

I have added the following fine function to my status bar to show which function is currently being edited in C-derived languages:
set statusline+=%{WhatFunctionAreWeIn()}
fun WhatFunctionAreWeIn()
let strList = ["while", "foreach", "ifelse", "if else", "for", "if", "else", "try", "catch", "case"]
let foundcontrol = 1
let pos=getpos(".") " This saves the cursor position
let view=winsaveview() " This saves the window view
while (foundcontrol)
let foundcontrol = 0
" Go to the character before the last open {
normal [{
call search('\S','bW')
" If the character is a ) then go to the character
" preceding the () section
let tempchar = getline(".")[col(".") - 1]
if (match(tempchar, ")") >=0 )
normal %
call search('\S','bW')
endif
let tempstring = getline(".")
for item in strList
if( match(tempstring,item) >= 0 )
let foundcontrol = 1
break
endif
endfor
if(foundcontrol == 0)
call cursor(pos)
call winrestview(view)
return tempstring
endif
endwhile
call cursor(pos)
call winrestview(view)
return tempstring
endfun
However, after a few minutes VIM hangs. Disabling the function prevents the hang, so I feel confident that this function is to blame. Is there anything in there that might hang VIM? Is there a better way to accomplish the task of showing the currently-edited function in the status bar?
Thanks.
The issue is that your strategy for determining whether to keep moving to surrounding braces is too aggressive:
Suppose your cursor is on the f in a preprocessor directive #endif between two functions.
Since you're between two functions, there is no unmatched { for [{ to jump to, so the cursor doesn't move.
Your match() against strList hits the if in #endif, causing the loop to continue.
The loop never exits.
I suspect a ctags-based approach, like #Gowtham suggests, will work better, even if it requires some customization.

Resources