I have a simple AHK script that plays back text into an editor ( see script below ).
I want to be able to Pause / Resume the playback by pressing a sequence of keys.
I reviewed a few solutions here & at various AHK sites w/o success.
The script below should startup when I type Mike XXX ( and then press enter ) and should pause / restart when I use the Ctrl+Alt+P key sequence ...if I uncomment the Pause key sequence the script does not run at all ...any thoughts ?
++++++++++
AHK Script
++++++++++
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; ================ Define PAUSE key sequence ======================
;^!p::Pause ; Press Ctrl+Alt+P to pause. Press it again to resume.
; =================================================================
BAS1 =
(
This is line 1 of some text
)
BAS2 =
(
This is line 2 of some text
)
BAS3 =
(
This is line 3 of some text
)
; ==================================================
; ====================== Start BAS definitions
; ==================================================
::Mike XXX::
send, Mike XXX
send, {enter 2}
SendDelay(BAS1)
send, {enter 2}
SendDelay(BAS2)
send, {enter 2}
SendDelay(BAS3)
send, {enter 2}
return
; ==================================================
; ====================== End BAS definitions
; ==================================================
SendDelay(text) {
Loop, parse, text
{
Random, rdel, 5, 9
Random, rdur, 6, 9
SetKeyDelay, %rdel%, %rdur%
Sendraw % A_LoopField
}
}
; =================================== End Methods
Related
I'm trying to achieve a visual-studio-like chaining of hotkeys for something at work.
Basically, when I hit Ctrl+Alt+F, I want to enter a sort of "Format mode" The next key I press will determine what text is injected. I'd like "Format mode" to cease as soon as one of the inner hotkeys is pressed. However I'd also like the option to have to cancel it manually just in case.
I've tried searching for the chaining of hotkeys, as well as attempted the following, rather naive code:
;
;; Format Mode
;
^+f::
; Bold
b::
Send "<b></b>"
Send {Left 4}
return
; Italics
i::
Send "<i></i>"
Send {Left 4}
return
; Bulleted List
u::
Send "<u></u>"
Send {Left 4}
return
; Numbered List
o::
Send "<o></o>"
Send {Left 4}
return
; List Item
l::
Send "<li></li>"
Send {Left 4}
return
; Line Break
r::
Send "<br/>"
return
return
I was pretty sure this wasn't going to work, but I figured I'd give it a shot so as to not make y'all think I'm just asking to be spoon fed.
I haven't worked with AHK a whole lot, but I've used it enough to be able to accomplish some stuff both at home and at work, but it's suuuuper messy - just as some background as to my experience with AHK.
With the #if command you are able to Switch/Toggle between action1/Enable and action2/Disable with the same Hotkeys.
You can test it out in Notepad. if you then type the key t
type Ctrl+Shift+f keys to toggle between two the same hotkeys.
Note: For your Hotkeys You Can Change the Code a Little Bit! you can Place all your hotkeys into #if Mode1 and then use no hotkeys into #if Mode2
Example1.ahk
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
#SingleInstance force
a := 1
#If mode1 ; All hotkeys below this line will only work if mode1 is TRUE or 1
t::
send 1
; Here you can put your first hotkey code
return
; Here you can Place All your Hotkeys
#If
#If mode2 ; All hotkeys below this line will only work if mode2 is TRUE or 1
t::
send 2
; And here you can put your second hotkey code
return
#If
; toggle between [t::1] and [t::2]
;a = 1 => t::1
;a = 2 => t::2
;type Ctrl+Shift+f keys to toggle between two the same hotkeys
;you can test it out in notepad - if you then type the key t
^+f::
if (a=1)
{
mode1 = 1
mode2 = 0
a := 2
}else{
mode1 = 0
mode2 = 1
a := 1
}
return
esc::exitapp
Using #If is a good choice, as stevecody showed. Below is another solution that may work for you. It uses your ^+f hotkey to activate the specialty hotkeys. The specialty hotkeys will also deactivate themselves upon use. f1 is your option to cancel it manually.
^+f::
Hotkey , b , l_Bold , On
Hotkey , i , l_Italics , On
Hotkey , l , l_ListItem , On
Return
f1::
Hotkey , b , l_Bold , Off
Hotkey , i , l_Italics , Off
Hotkey , l , l_ListItem , Off
Return
l_Bold:
Hotkey , b , l_Bold , Off
Send , <b></b>{left 4}
Return
l_Italics:
Hotkey , i , l_Italics , Off
Send , <i></i>{left 4}
Return
l_Italics:
Hotkey , l , l_ListItem , Off
Send , <li></li>{left 5}
Return
Something else I was looking at, but it doesn't quite work right, is below. The problem is that it will still send the specialty key and you end up with something like <i>i</i> instead of <i></i>.
f1::
KeyBdHook := DllCall( "SetWindowsHookEx" , "int" , 13 , "uint" , RegisterCallback( "KeyBdProc" ) , "uint" , 0 , "uint" , 0 )
input
Return
KeyBdProc( nCode , wParam , lParam )
{
global KeyBdHook
Critical
If ( wParam = 0x100 )
{
DllCall( "UnhookWindowsHookEx" , "ptr" , KeyBdHook )
sKey := GetKeyName( Format( "vk{:x}" , NumGet( lParam + 0 , 0 , "int" ) ) )
If ( sKey = "i" )
Send , <i></i>{left 4}
Else
MsgBox , You pressed %sKey%
}
}
I have the following autohotkey script. I would like that (1) when I press and release the RShift, the script suspends for the next keystroke (i.e., for just one keypress) and (2) when I press and hold the RShift the script suspends until I release RShift.
Unfortunately the following code only performs (2) not (1). I am looking for a correct code to perform both (1) and (2).
AppsKey::RButton
RShift::Suspend, On
RShift Up::Suspend, Off
RShift::
KeyWait, RShift, T0.3
; Release RShift in less than 0,3 seconds after pressing it
; to suspend the script for the next keystroke
If (!ErrorLevel)
{
Suspend On
; BlockInput On
SetTimer OneKeyPressed, 200
}
else
{
; Hold RShift pressed for more than 0,3 seconds
; to suspend until you release RShift
while GetKeyState("RShift", "P")
Suspend On
KeyWait, RShift, L
Suspend, Off
}
return
#If A_IsSuspended
RShift Up:: Suspend, Off
#If
OneKeyPressed:
If (A_TimeIdlePhysical < 100)
{
SetTimer OneKeyPressed, off
; BlockInput Off
Suspend Off
}
return
I wrote an AHK script designed to copy a text from Adobe Acrobat when I press F9. It then changes it according to a regex and shows the copied text in tooltip. Additionally, I added code to automatically close an annoying window that Acrobat sometimes shows when coping a text, an infamous There was an error while copying to Clipboard. An internal error occurred. When this window doesn't show up, the script keeps showing a tooltip, which is designed to close after a specified amount of time. I've been banging my head against the wall but I don't know how to correct this.
;#NoTrayIcon
#Persistent
#SingleInstance
F9::
#If WinActive("ahk_exe Acrobat.exe")
{
Clipboard:=""
send,^c
ClipWait, 1
Clipboard := RegExReplace(Clipboard, "\r\n", " ")
SetTimer,CheckForMsgBox,100
CheckForMsgBox:
IfWinExist, Adobe Acrobat
{
Send {Enter}
SetTimer,CheckForMsgBox,Off
}
;Return
If (StrLen(Clipboard) < 120)
ToolTip % Clipboard
Else
ToolTip Copied
SetTimer, ToolTipOff, -1000
return
}
#If
ToolTipOff:
ToolTip
return
;#NoTrayIcon
; #Persistent ; (1)
#SingleInstance
SetTimer,CheckForMsgBox,100 ; (2)
return
#If WinActive("ahk_exe Acrobat.exe") ; (3)
F9::
clipboard:=""
send,^c
ClipWait, 1
Clipboard := RegExReplace(Clipboard, "\r\n", " ")
If (StrLen(Clipboard) < 120)
ToolTip %Clipboard%
Else
ToolTip Copied
SetTimer, ToolTipOff, -1000
return
#If ; turn off context sensitivity
ToolTipOff:
ToolTip
return
CheckForMsgBox:
; ControlSend, Control, Keys, WinTitle, WinText, ExcludeTitle, ExcludeText
ControlSend, , {Enter}, Adobe Acrobat ; Close this unwanted window whenever it appears
return
(1) Scripts containing hotkeys, hotstrings, or any use of OnMessage() or Gui are automatically persistent.
(2) SetTimer causes a subroutine (Label) to be launched automatically and repeatedly at a specified time interval.
https://autohotkey.com/docs/commands/SetTimer.htm
(3) Like the #IfWin directives, #If is positional: it affects all hotkeys and hotstrings physically beneath it in the script.
https://autohotkey.com/docs/commands/_If.htm
!c::
file_name = footnote.ini
restore_original_clipBoard := clipboard
clipboard =
KeyWait, Alt
KeyWait, c ;small c
BlockInput, on
SendEvent, ^{ins} ;^c doesn't work
ClipWait, 2 ; Wait for the clipboard to contain text.
if ErrorLevel
{
MsgBox Failed to save the selection: %clipboard%
exit
}
BlockInput, off
save_selection := clipboard
Problem: Despite a selection being made, Sendevent ^{ins} does not save it to the clipboard. Sometimes I have to repeat my hotkey, alt + c several times before the selection is being copied to the clipboard. The KeyWait should ensure me that only ^{ins} is being processed without any additional keys. What am I doing wrong here?
UPDATE
One of the ways I tried to force copy a selection to the clipboard was by using a while loop. I got it to work through the post: Looping clipboard and errorlevel evaluation not working as expected
PROBLEM
When I make a selection and press alt + c it sometimes gets stuck in the infinite loop that I implemented. But as you can see from that code:
clipboard := ""
while( StrLen(clipboard) < 1 )
{
Send, ^{ins}
Sleep, 50
}
MsgBox % ClipBoard
The infinite loop incorporates within itself a continues resending of ^{ins}. For some reason, my selection is not being recognized as a selection. Whilst it is in that infinite loop, I try to reselect the text. It then recognizes it instantly and copies my selection to the clipboard. But alas! The selection is incomplete because it goes so quick.
This problem is not always like that. Sometimes it recognizes the selection first spot on! So sometimes it copies my selection to my clipboard sometimes not. When it does not, then a resending of a ^{ins} does not seem to work. I do not want to the user to reselect his selection. Is that possible to do?
Send {Ctrl Down}{c}{Ctrl Up}
That presses Ctrl+C, you must do it instantly as one command apposed to pressing Ctrl waiting then pressing C.
Never seen Insert key used for copying text.
Also found this sends Ctrl+C as well.
Send, ^c
To send insert key use
{Insert}
This way works for me:
!vk43:: ; alt+c
clipContent:=ClipboardAll
Clipboard:=""
SendEvent, ^{Ins}
ClipWait, .75
MsgBox, % 262 . (ErrorLevel ? 160:208)
, % ErrorLevel ? "Period expired:":"Result:"
, % ErrorLevel ? "Failed to save the selection.":Clipboard
, % (ErrorLevel ? 0:2) . .5
Clipboard:=clipContent
KeyWait, vk43
Return
!vk43:: ; alt+c
clipContent:=ClipboardAll ; backup clipboard content (if needed)
Clipboard:="" ; no comment :)
Loop
{
SendEvent, ^{Ins}
ClipWait, .75 ; means 750ms, same if write 0.75
; assign value of "ErrorLevel" an variable for further usage
errLvl:=ErrorLevel
; monitoring current action (for debugging purpose only)
TrayTip, % "attempt: #"A_Index
, % """ErrorLevel"" of ""ClipWait"" command is: "errLvl
}
; here you can set the condition of ending the cycle: either...
; ...variable errLvl has not a true value,...
; ...or the number of attempts is equal 5
Until, Not errLvl Or A_Index=5
; value of each field of the command "MsgBox"...
; ...are set depending on the value of errLvl variable...
; ...using a ternary expression
; means if errLvl is a true, "options" field is 262160
MsgBox, % 262 . (errLvl ? 160:208)
; means that "title" has a couple variants
, % errLvl ? "Period expired:":"Result:"
; means that "text" has a couple variants
, % errLvl ? "Failed to save the selection.":Clipboard
; means if errLvl is a true, "timeout" field is 0.5 (500ms)
, % (errLvl ? 0:2) . .5
/* same that and above:
IfEqual, errLvl, % True, MsgBox, 262160
, % "Period expired:"
, % "Failed to save the selection."
, 0.5
Else MsgBox, 262208, % "Result:", % Clipboard, 2.5
*/
TrayTip ; remove "TrayTip" (for debugging purpose only)
; save an positive result (if needed)
IfEqual, errLvl, 0, Sleep, -1, someVar:=Clipboard
; return a temporarily saved data into clipboard (if needed)
Clipboard:=clipContent
KeyWait, % "vk43"
Return
From my experience whenever keystrokes are not recognized reliably it's due to either the system or the targeted program not keeping up with the speed at which those keys are sent.
For SendEvent you could try something like SetKeyDelay, 1000, 1000 and see if this improves things. The other option would be to send explicit down and up keys with intermittent sleep calls as outlined in this answer.
I have this simply script in Autohotkey:
:*:teams::
(
milan
juventus
inter
roma
lazio
napoli
mantova
)
When i type teams on Notepad my output is the list of teams (milan, juventus..)
if i use a physical keyboard to type teams this script work for me
, but if use a virtual keyboard to type teams i have no list on Notepad:
and if i run the script to type teams automatically
WinWait, *new 2 - Notepad++,
IfWinNotActive, *new 2 - Notepad++, , WinActivate, *new 2 - Notepad++,
WinWaitActive, *new 2 - Notepad++,
MouseClick, left, 133, 117
Sleep, 100
Send, squadre
the script doesn't replace teams with the list of teams
Why the script works only if i type with a physical keyboard?
is there a solution to replace words, sentences with my scripts without using physical keyboard?
Sorry if i am noob
You can use the Input command.
loop {
While !RegexMatch(strCapture, "teams$") {
Input, strUserInput, V L1, {BackSpace} ; V: visible, L1: Character length 1
If ErrorLevel = Endkey:BackSpace
strCapture := SubStr(strCapture, 1, StrLen(strUserInput) - 1)
else
strCapture .= strUserInput
; tooltip % ErrorLevel "`n" strUserInput "`n" strCapture "`n" ; enable this to see what actually happens
}
SendInput,
(Ltrim
{Backspace 5}
milan
juventus
inter
roma
lazio
napoli
mantova
)
strCapture := ""
}