AutoHotkey Community

It is currently May 25th, 2012, 11:33 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: July 16th, 2007, 7:52 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Not quite.

Firstly, there's no point incrementing "i" if you set it to 1 every iteration. ;)

Second, retrieving the value of a dynamically-named variable (i.e. an array item) can only be done with expressions (or Transform,var,DeRef,%var%.) Something like this should work:
Code:
WinGet, winid, list, WinTitle-or-whatever
Loop, %winid%
{
    ; Of course, this has limited usefulness, as it would activate each window
    ; immediately, leaving only the last one active.
    WinActivate, % "ahk_id " . winid%A_Index%
}

The "% " forces the parameter to be interpreted as an expression. ahk_id must be a literal string (so "" are required). A_Index is the current iteration of the loop (starting at "1"), so winid%A_Index% retrieves the value of the variable whose name is "winid1", "winid2", etc.

The "Arrays" page in the help file explains a few things. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 8:12 am 
That's great lexikos!

Please correct me if I'm wrong, but I understood that if winget, variable, list is all that's coded, it will automatically add all open windows to the array?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 8:53 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Ah, you're right. I read:
WinGet - WinTitle wrote:
The title or partial title of the target window (the matching behavior is determined by SetTitleMatchMode). If this and the other 3 parameters are omitted, the Last Found Window will be used.
and didn't see the exception:
WinGet - List wrote:
(to retrieve all windows on the entire system, omit all four title/text parameters).

I imagine "all windows" only includes all visible windows if DetectHiddenWindows is OFF. I'm not sure if this only includes windows that show up in the task bar... I think it would include other visible windows (like the task bar itself!)

Edit: Yep, the list includes the taskbar (ahk_class Shell_TrayWnd) and desktop (ahk_class Progman).


Last edited by Lexikos on July 16th, 2007, 8:57 am, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 8:54 am 
Offline

Joined: June 23rd, 2007, 12:23 pm
Posts: 87
Hi,
sorry for the mistake and the not minimal code! :)
In any case you're right the winget function retrievs the list (if list parameter is specified) of the windows matching your criteria (in this case probably the title). In any case the variable named in this case winid will contain the number of windows and the variables from winid1 to winidn will contain the ids of the windows.

Bye! :shock: :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 8:54 am 
I've managed to scrounge this code together, and though I believe it should work in keeping each window selected randomly only once for each time the macro is run. The code no longer seems to switch between the windows.

I'm suspecting there's something I dont understand about the %Number% value being used?

Code:
F9::
WinGet, winid, list
Options=12345678
  Loop
  {
    Random, Pos, 1, % StrLen(Options)
    Number:=SubStr(Options, Pos, 1)
    WinActivate, % "ahk_id " . winid%Number%
    Send, Text window %Number%
    Sleep, 100
    StringReplace, Options, Options, % Number
    If not StrLen(Options)
      Break
  }
Return


Am I still making sense?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:00 am 
Offline

Joined: June 23rd, 2007, 12:23 pm
Posts: 87
Hi,
Try to put some MsgBox or something that can give you a feedback on the content of the several variables you have.

Bye! :shock: :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:26 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
I don't see any problems. In fact, I tried the script and it seems to work perfectly, although:
  • I disabled the "Send" because I didn't want it to mess with my open windows.
  • I had 9 windows in the list (including the taskbar and desktop), but the Options string only includes 8. To fix that, you'd need to build a list of indices (1 to %winid%). The code gets a bit more complicated once you get >9 windows - because numbers can be > 1 char long, you need a delimiter.
Here's what I came up with (though I think it could be cleaned up a lot):
Code:
F9::
WinGet, winid, list

; build a comma-delimited (in case there are >9 windows) list of indices.
Options = ,
Loop, %winid%
    Options .= A_Index . ","

  Loop
  {
    Random, Pos, 1, %winid% ; (see winid-- near the end of the loop)
   
    ; remove the start/end "," for easier parsing
    temp := SubStr(Options, 2, -1)
   
    ; use a parsing loop to select the right item from the list
    Loop, Parse, temp, `,
        if (A_Index = Pos)
        {
            Number := A_LoopField
            break
        }
   
    WinActivate, % "ahk_id " . winid%Number%
   
    ;Send, Text window %Number%
   
    Sleep, 100
   
    ; Replace ,Number, with , (effectively removing the item)
    StringReplace, Options, Options, `,%Number%`,, `,

    ; Reuse winid to keep track of how many items are left.
    winid--

    If not winid
      Break
  }
Return


Edit: Here's a shorter/cleaner version. How it works:
  1. It loops through all indices (1..%winid%), encodes the index as a single character (using Chr()) and appends it to the Options string.
  2. Instead of pulling the numeric digit from the Options string, it pulls the encoded character and retrieves it's numerical value (using Asc()).
  3. Because "Number" no longer exists in the Options string in literal form, SubStr() is used to remove the encoded character.
Code:
F9::
WinGet, winid, list

if (winid > 255)
    winid = 255 ; max 255 windows (Chr codes are between 1 and 255)
Loop, %winid%
    Options .= Chr(A_Index)

  Loop
  {
    Random, Pos, 1, % StrLen(Options)
   
    ; Use Asc() to retrieve the character code corresponding to this character (between 1 and 255)
    Number := Asc(SubStr(Options, Pos, 1))
   
    WinActivate, % "ahk_id " . winid%Number%
    ;Send, Text window %Number%
    Sleep, 100
   
    ; Remove the character at %Pos%.
    Options := SubStr(Options, 1, Pos-1) . SubStr(Options, Pos+1)
   
    If not StrLen(Options)
      Break
  }
Return

Note that because each character is a single byte (1..255), a maximum of 255 windows is imposed. :lol: On the other hand, it beats the limit of 9 windows, while removing the requirement for a delimiter (like ","), which makes the code more compact.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:44 am 
Offline

Joined: June 23rd, 2007, 12:23 pm
Posts: 87
Hi,
I think it would be clearer in this two points with
Code:
    temp := SubStr(Options, 2, -1)

Code:
    temp := RegExReplace(Options, "^,?(.*?),?$", "$1")

and this
Code:
     StringReplace, Options, Options, `,%Number%`,, `,

with
Code:
     Options := RegExReplace(Options, ",?" . Number)

If this works correctly you can remove the substitution of the start end commas and do it only once after the construction of the list.
Unfortunately in this moment I cannot test them.

EDIT:
Code:
Number := Asc(SubStr(Options, Pos, 1))
   
    WinActivate, % "ahk_id " . winid%Number%
    ;Send, Text window %Number%
    Sleep, 100
   
    ; Remove the character at %Pos%.
    Options := SubStr(Options, 1, Pos-1) . SubStr(Options, Pos+1)

this with regex can be:
Code:
Tmp := SubStr(Options, Pos, 1)
Number := Asc(Tmp)
   
    WinActivate, % "ahk_id " . winid%Number%
    ;Send, Text window %Number%
    Sleep, 100
   
    ; Remove the character at %Pos%.
    Options := RegExReplace(Options, Tmp)


Bye! :shock: :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 11:02 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Tarch wrote:
Hi,
I think it would be clearer in this two points with
Code:
temp := SubStr(Options, 2, -1)
Code:
temp := RegExReplace(Options, "^,?(.*?),?$", "$1")

I disagree. Using SubStr() is shorter, clearer and more efficient. We know there will always be start and end commas in "Options", so there is no need to use regular expressions (or the "?" quantifier.)
Quote:
and this
Code:
StringReplace, Options, Options, `,%Number%`,, `,
with
Code:
Options := RegExReplace(Options, ",?" . Number)
The point of having commas on both sides of every number is to remove ambiguity when, for example, one number is a subset of another. For example: ",?1" would match the "1" in ",210" (because the comma is optional)... However, I realise now that there should never be ambiguity, because
  • a larger number can't be a subset of a smaller number ("x" can't contain "xy"), and
  • the indices are in ascending order (left->right),
  • so AHK will always find the smaller number first!
So, you could...
Code:
; replace:
Options = ,
; with:
Options =  ; no starting comma needed
; replace these two lines:
temp := SubStr(Options, 2, -1)
Loop, Parse, temp, `,
; with:
Loop, Parse, Options, `,  ; no need to remove anything - no need for temp
; and this:
StringReplace, Options, Options, `,%Number%`,, `,
; with
StringReplace, Options, Options, %Number%`,  ; remove N, (no starting comma required)

At any rate, I much prefer the second method I posted (using Asc() and Chr()). It's more compact, more efficient, and cleverer. :P
Quote:
Code:
...
Options := SubStr(Options, 1, Pos-1) . SubStr(Options, Pos+1)
this with regex can be:
Code:
...
Options := RegExReplace(Options, Tmp)
*sigh*. Why are you using RegExReplace? Tmp can potentially be any character. Because you haven't escaped it (e.g. "\Q" . Tmp . "\E"), if Tmp is a regex-reserved character, the script could crash. Granted, that isn't likely (there'd have to be a lot of windows), but it's possible. More to the point, you haven't specified a regular expression, so you should be using StringReplace, not RegExReplace.

There are two reasons I believe SubStr() . SubStr() is (marginally) more efficient:
  1. *Replace needs to first search for the character, whereas we already know the position.
  2. The *Replace method requires the use of a Tmp variable.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 11:24 am 
Offline

Joined: June 23rd, 2007, 12:23 pm
Posts: 87
Hi,
lexikos wrote:
Tmp can potentially be any character. Because you haven't escaped it (e.g. "\Q" . Tmp . "\E"), if Tmp is a regex-reserved character, the script could crash.

yes, you're right, mine error. I just trying to be helpful (unfortunately I haven't the possibility to test things in that moment, and usually I prefer to test is much better)
lexikos wrote:
At any rate, I much prefer the second method I posted (using Asc() and Chr()). It's more compact, more efficient, and cleverer.

Is better for me, too.

Bye! :shock: :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 8:05 pm 
Man, you've all been so helpful!
This is what I've come to using:

Code:
F9::
WinGet, winid, list, ahk_class Notepad

if (winid > 255)
    winid = 255 ; max 255 windows (Chr codes are between 1 and 255)
Loop, %winid%
    Options .= Chr(A_Index)

  Loop
  {
    Random, Pos, 1, % StrLen(Options)
   
    ; Use Asc() to retrieve the character code corresponding to this character (between 1 and 255)
    Number := Asc(SubStr(Options, Pos, 1))
   
    WinActivate, % "ahk_id " . winid%Number%
    Send, Text Window %Number%
    Sleep, 100
   
    ; Remove the character at %Pos%.
    Options := SubStr(Options, 1, Pos-1) . SubStr(Options, Pos+1)
   
    If not StrLen(Options)
      Break
  }
Return


The desktop counting as a window was throwing me off a bit, so I limited it to 'Notepad' and the send function works just fine.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 3:31 am 
TriggerVariable := Mod(WinID%Number%, 3)

Should the above line of code assign 'TriggerVariable' with either 0, 1, 2 with consideration to the variables previously mentioned?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 4:29 am 
Offline
User avatar

Joined: August 30th, 2005, 8:43 pm
Posts: 8647
Location: Salem, MA
yes, but it might not be useful.

_________________
Image
(Common Answers) - New Tutorials Forum - Humongous FAQ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 7:21 am 
Hehe, I just realized, I need to decrement the number of windows by one in order to tab through them.

And

AltTab := %WinID% -1

Doesn't seem to work.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 7:38 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
"Decrement the number of windows" -- why? What's the "AltTab" var? If by "tab through them" you mean activate the window that is second-most recently active, that would be winid2. winid%winid% (the last item) would be the least recently activated window. If you're trying to eliminate the active window from consideration, start at index 2 (winid2). So, for example:
Code:
Loop, % winid-1
    Options .= Chr(A_Index+1)  ; +1 to skip the first one


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


Who is online

Users browsing this forum: BrandonHotkey, just me, Looq, Yahoo [Bot] and 66 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group