How can I set random choice for button 'click' or 'don't click'?
In this example I need let iMacros make random action between like action and do nothing.
TAG POS=1 TYPE=BUTTON ATTR=TXT:Like
As one of the ways to do what you need:
SET butTxt "Like"
SET butTxt EVAL("(Math.floor(2*Math.random()) == 0) ? 'No such button!' : '{{butTxt}}';")
SET !ERRORIGNORE YES
SET !TIMEOUT_STEP 0
TAG POS=1 TYPE=BUTTON ATTR=TXT:{{butTxt}}
SET !ERRORIGNORE NO
SET !TIMEOUT_STEP 6
var macro;
macro = "CODE:";
macro += "SET !TIMEOUT_STEP 1" + "\n";
macro += "TAG POS=1 TYPE=BUTTON ATTR=TXT:Like" + "\n";
while (true) {
var random = getRandomInt(1, 10);
if (random < 5) {
iimPlay(macro)
}
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Try this simple .js solution. I made it so if the random number is less then 5 to click the button. Else do nothing.
You can change it the way you want it. You have to save the JS code as .js . Nothing other that that will work.
Related
i wanna click a random button 50 times from a list unless it is 1 only click it once, its always going to the else even if key is 1
!F2::
breakvar = 1
return
!F1::
loop
{
Random, var, 1,7
keyList = {1},{2},{3},{w},{a},{s},{d}
StringSplit, KeyAry, KeyList, `,,%A_Space%
key := KeyAry%var%
loop 50
{
; i've tryied:
;(%key% = "1")
;(key = 1)
;(key = {1})
; but with out success
if (key = "1")
{
Send, %key%
break
}
else
{
Send, %key%
Sleep, 100
}
}
if breakvar = 1
break
}
breakvar = 0
return
also is there a better way to achieve what i am trying to do?
thx
Your main mistake was that you indeed didn't manage to get the if statement corrent. The right one would've been if (key = "{1}").
But really, I don't know why you even had the { }, it's a common mistake I see from nearly every beginner, I wonder where it comes from.
You're only supposed to use { } for escaping or if the special notation is needed for something such as {space}. Read more from the documentation.
Here's a cleaned up script with all other weirdness removed as well:
KeyList := StrSplit("1,2,3,{space},+1,w,🐈", ",") ; +1 is shift + 1 (whatever key that will produce in your keyboard layout)
!F2::BreakVar := true
!F1::
loop
{
Random, index, 1, 7
key := KeyList[index]
loop 2
{
SendInput, % key
if (key = "1")
break
Sleep, 100
}
if (BreakVar)
break
}
BreakVar := false
return
To be totally correct, I should say that you shouldn't loop under hotkeys and should use a timer instead, but I wont add that in to confuse you. This should be fine as well, if you have problems with hotkeys after this, you can look into a timer approach yourself or ask help here.
I need a script that will left mouse click at a specific time of day. I found the following (see link) which is working but was wondering if there is now simpler code (this code is old ) that will do the same? I will be at the computer and can position the mouse so I won't need x, y coordinates. Any help will be greatly appreciated.
I copied the code from here:
https://autohotkey.com/board/topic/485-need-to-program-a-left-mouse-click-to-run-at-a-certain-time/
Code:
#persistent
TargetTime = 1800
StringLeft, TargetDateTime, A_Now, 8 ; Put just YYYYMMDD into the
variable.
TargetDateTime = %TargetDateTime%%TargetTime%
TimeUntilTarget = %TargetDateTime%
TimeUntilTarget -= %A_Now%, seconds
if TimeUntilTarget < 0
{
MsgBox The target time is already past!
return
}
TimeUntilTarget *= 1000 ; Convert to milliseconds.
TimeUntilTarget -= 1000
SetTimer, ClickTimer, %TimeUntilTarget%
return
ClickTimer:
SetTimer, ClickTimer, off ; i.e. do only one click
MouseClick, left
I've got two userforms - "PhaseHome" and "ModifyPhases".
I must go through the "PhaseHome" form in order to get to the "ModifyPhases" form. Once on the "ModifyPhases" form, I utilize a combo-box and button for the user to create a new & custom named userform that has a few controls. The code looks like this:
Please Note:
"Phasename" is the custom name the user entered in the earlier combo-box.
Sub New_form()
Dim Newphase As VBComponent
Dim ItemBox As MSForms.ComboBox
Dim AddItem As MSForms.CommandButton
Sheet1.Activate
'Creating the new form
Set Newphase = ActiveWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
With Newphase
.Properties("Height") = 250
.Properties("Width") = 350
.Properties("Caption") = Phasename
.Name = Phasename
End With
'Inserting the combobox into the dynamically created form
Set ItemBox = Newphase.Designer.Controls.Add("Forms.ComboBox.1")
With ItemBox
.Name = Phasename & "Box"
.Top = 60
.Left = 12
.Width = 140
.Height = 80
.Font.Size = 8
.Font.Name = "Tahoma"
.BorderStyle = fmBorderStyleOpaque
.SpecialEffect = fmSpecialEffectSunken
End With
'Inserting buttons into the dynamically created form
Set AddItem = Newphase.Designer.Controls.Add("Forms.commandbutton.1")
With AddItem
.Name = "cmd_1"
.Caption = "Add Line Item"
.Top = 5
.Left = 200
.Width = 110
.Height = 35
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
With that done and the userform created; I now want to add a button to the "PhaseHome" form that allows the user to get to the form we just created.
Sheet1.Select
Range("D5").Value = Range("D5").Value + 45
'Add button to Phase Home Form
Dim homeform_button As MSForms.CommandButton
Dim ufObj As UserForm
Set ufObj = ActiveWorkbook.VBProject.VBComponents("Phasehome").Designer
With ufObj
Set homeform_button = .Controls.Add("Forms.CommandButton.1")
With homeform_button
.Name = "cmd" + Phasename
.Caption = Phasename
.Top = Range("D5").Value
.Left = 45
.Width = 78
.Height = 36
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
End With
'Making sure we don't overwrite previously existing code when we insert this into PhaseHome
Dim linestart As Integer
linestart = Range("D8").Value
ThisWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Private Sub cmd" & Phasename & "_Click()"
linestart = linestart + 1
ThisWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Unload Me"
linestart = linestart + 1
ThisWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Sheet2.Activate"
linestart = linestart + 1
ThisWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "" & Phasename & ".Show"
linestart = linestart + 1
ThisWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "End Sub"
linestart = linestart + 1
Range("D8").Value = linestart
Now the good news is that this code works!.... As long as I run it from the "ModifyPhases" form directly. Once, for the very first time in a session, that I open and close the "PhaseHome" form I start receiving an error 91 (Object variable or With block Variable not set) that points to the
Set homeform_button = .Controls.Add("Forms.CommandButton.1")
line everytime I attempt to run the macro again.
Things I've tried:
I've made sure that the "PhaseHome" form is unloaded. The button that goes between the userforms always includes an Unload Me, i've also tried unloading "PhaseHome" directly within the macro itself, and also used variables tied to "PhaseHome"'s terminate and Initialize functions to ensure it is unloaded without referencing it directly.
After noticing that refreshing the workbook fixed the issue, I discovered some code online (From a source I regretfully forget) that closes and reopens the workbook each time the "ModifyPhases" form is launched which fixes the issue.
Sub CloseMe()
Application.OnTime Now + TimeValue("00:00:02"), "OpenMe"
ThisWorkbook.Close True
End Sub
Sub OpenMe()
ModifyPhases.Show
End Sub
I don't know why the code tags aren't working right here.
This works but... causes corruption in the workbook and also seems rather unnecessary. Do you fellows have any theories on why this could be occurring? Thank you!
-Mano
Make no mistake about it: Modifying controls at run-time, and especially adding forms at run-time, is a high-level VBA exercise, and I think that it simply is beyond what you're currently capable of. (Please don't take this the wrong way, I don't mean to condescend)
I need a new custom button for each custom form added to "PhaseHome".
I'm gathering that this is the hang-up, and also source of error. So...
Is there an easier way??
Let's ditch that idea altogether!
Use a different control type that is more amenable to modifications at run-time. Buttons are tricky because they require each their own _Click event handler. Instead of adding buttons for each phase, just add a new item to a ComboBox control, and leverage its _Change (or some other) event as a method of user-input.
IOW, instead of expecting the user to press a button that displays a form, just let them select the form from a ComboBox!
Then, invoking that ComboBox's _Change event, refer back to the dict/collection of properties, and display the "Phaseform" object where you can modify it's controls at runtime, as needed.
Now you have a relatively generic form that will be used for any possible phase.
The List property of the Combobox is itself dynamic, and has a _Change event handler which you can use!
Private Sub cbox_PhaseNames_Change()
MsgBox Me.Value 'Show the value which is selected, for debugging
'Modify the Newphase userform. There is only one form, and its properties
' will be modified based on the selection from the cBox_Phasenames control
Newphase.Caption = Me.Value
'If you need to change other controls, you can probably do that here, too
End Sub
Example
I created some crude example (download from Google Drive if you'd like), using only two user forms. Phasehome implements described above, and the Phaseform can be modified (e.g., it's Caption) based on the selection in the ComboBox on PhaseHome.
NOTE: You're using 3 forms at least, please make note that I'm only using 2, what my example does for Pagehome really is probably more applicable to your ModifyPhases form, so take note of that and modify accordingly.
This would be how I set up the code for Phasehome:
Option Explicit
Private Sub cbox_Phasenames_Change()
Dim val$, bFound As Boolean
Dim i As Long
'crude validation:
val = Me.cbox_Phasenames.Value
For i = 0 To Me.cbox_Phasenames.ListCount - 1
If val = Me.cbox_Phasenames.List(i) Then
bFound = True
Exit For
End If
Next
If Not bFound Then Exit Sub 'Avoid errors
'Modify the PhaseForm:
With phaseForm
.Caption = val
.Show
End With
End Sub
Private Sub CommandButton1_Click()
'Very simple example, allows duplicates, which you probably want to avoid
Me.cbox_Phasenames.AddItem Me.TextBox1.Value
End Sub
And here is the code for Phaseform, I've commented a few items, but using the Initialize event to assign the properties you've set up:
Option Explicit
Private Sub UserForm_Initialize()
Me.Height = 250
Me.Width = 350
'Me.Caption = "" '## This is set in the calling procedure
With Me.ComboBox1
.Top = 60
.Left = 12
.Width = 140
.Height = 80
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
With Me.CommandButton1
'### There is no need to assign a dynamic Name property to this control
'.Name = "cmd" + Phasename
.Caption = ""
.Top = Range("D5").Value
.Left = 45
.Width = 78
.Height = 36
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
End Sub
Private Sub ComboBox1_Change()
MsgBox "Does something..."
End Sub
Note: If there are additional properties that you need to persist during runtime can be done via Static variables and using possibly Collection or Dictionary object to assist with organizing what's needed. Keep the "list" of phases in an Array, and keep their relevant properties in a dict/collection, etc. If absolutely necessary you can store some things in a hidden worksheet, or in a Name in the workbook, or in CustomXMLPart, etc. -- there's lots of ways you can conceivably persist metadata beyond the user session, so that the changes will be available tomorrow, next week, etc.
So I discovered the issue with my macro. Once my code had finished building my custom userforms at Design time - it was not exiting from design mode on the custom form when I attempted to switch it over to the design mode on the "PhaseHome" userform to edit my buttons resulting in the Error 91. I found that by manually entering design mode (Using code I found here from Mr. Peter Thornton) and then manually exiting design mode using a time delay macro (Shown below) right before my code began placing my button onto the "Phasehome" form worked every time without error.
I used the time delay macro because entering design mode ends macro execution.
I discovered this by using the .hasopendesigner property (here) to test my custom form variable right before I tried to enter design mode for my "Phasehome" userform to add my button and found that it was still open. Just manually exiting design mode did not seem to change this - which is the part I suspect is a bug. This is why I manually entered then manually exited design mode.
I'm not certain but i'm leaning towards this being a bug within VBA Userforms as it has aggressively resisted any other form of troubleshooting besides a workbook reload as described previously.
Here is my code after I have completed the design of my custom userform (Please note selections are done because I wanted to control what the user saw during this process and are mostly unnecessary):
Sheet1.Select
Dim linestart As Integer 'Making sure we don't overwrite our code when we insert it into PhaseHome
linestart = Range("D8").Value
ActiveWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Private Sub cmd" & Phasename & "_Click()"
linestart = linestart + 1
ActiveWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Unload Me"
linestart = linestart + 1
ActiveWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "Sheet2.Activate"
linestart = linestart + 1
ActiveWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "" & Phasename & ".Show"
linestart = linestart + 1
ActiveWorkbook.VBProject.VBComponents("PhaseHome").CodeModule.InsertLines linestart, "End Sub"
linestart = linestart + 1
Range("D8").Value = linestart
Range("D5").Value = Range("D5").Value + 45
Range("D10").Value = Phasename
Sheet2.Select
Range("A1").Select
Call Design_mode_on
End Sub
TIME DELAY MACRO:
Sub Design_mode_on()
Application.OnTime Now + TimeValue("00:00:01"), "Design_mode_off"
EnterExitDesignMode True 'Enter Design Mode
End Sub
Sub Design_mode_off()
EnterExitDesignMode False 'Exit Design Mode
Call second_newphase
End Sub
Sub EnterExitDesignMode(bEnter As Boolean)
Dim cbrs As CommandBars
Const sMsoName As String = "DesignMode"
Set cbrs = Application.CommandBars
If Not cbrs Is Nothing Then
If cbrs.GetEnabledMso(sMsoName) Then
If bEnter <> cbrs.GetPressedMso(sMsoName) Then
cbrs.ExecuteMso sMsoName
Stop
End If
End If
End If
End Sub
\TIME DELAY MACRO:
Sub second_newphase() 'Divided this module in 2 due to some weird form interactions
Sheet1.Select
Phasename = Range("D10").Value
Range("D10").Clear
Dim homeform_button As MSForms.CommandButton
Dim ufObj As UserForm
EnterExitDesignMode False 'Exit again just for good measure hehe
Set ufObj = ActiveWorkbook.VBProject.VBComponents("Phasehome").Designer
With ufObj
Set homeform_button = .Controls.Add("Forms.CommandButton.1")
With homeform_button
.Name = "cmd" + Phasename
.Caption = Phasename
.Top = Range("D5").Value
.Left = 45
.Width = 78
.Height = 36
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
End With
Sheet2.Select
Range("A1").Select
End Sub
I want to press a hotkey, "x", to trigger mouse clicks that alternate between two positions
If I press "x", the mouse should click at position A
If I press "x" again, the mouse should click at position B
If I press "x" again, the mouse should click at position A
and so on
Here is my pseudocode
global variable "i"
i = 0
x::
if (i % 2 = 0) {
Click position A
} else {
Click position B
}
i = i + 1
}
return
I don't know how to do this in Autohotkey, please help
here is an example
x::
if (toggle := !toggle)
MsgBox A
else
MsgBox B
return
I have this code working...
myScroller.scrollTo(0, -654, 200);
I also have this working....
myScroller.scrollToElement("#p4", "1s");
Is there a way to add offset to the #id, like scrollToElement("#p4" + 100, "1s")?
No you can't.
myScroller.scrollToElement("#p4", "1s");
Because first parameter should be the CSS selector of a DOM element. Therefore can you use "#p4" + 100 for applying CSS rules? If your answer is YES then YOU CAN else YOU CANNOT.
If you wanted to scroll to next element after particular time what you can do is try with nth-child() CSS property with a appropriate timeout and incremental flag. Something like this (Assume your elements are inside a parent DIV element which have id myDiv)
var incre = 0;
function customScrollToElement(){
myScroller.scrollToElement("#myDiv:nth-child(" + incre + ")", 10);
incre ++;
}
setTimeout(function(){
customScrollToElement();
},100);
You can do it with some calculation by first using jQuery to get the element's position relative to their parent.
var left = -1 * ( $('#p4').position().left + 100 ),
top = -1 * ( $('#p4').position().top );
myScroller.scrollTo(left, top, 1000);
That will scroll 100 pixels right of the element