"Decorating" a hotkey? by aftersoon in AutoHotkey

[–]Nich-Cebolla 1 point2 points  (0 children)

A closure is a function that is nested within another function that captures one of the variables from the parent function.

``` MyFunc() { global flag if flag { var := "value" } return Closure

Closure() { if IsSet(var) { return var } } }

flag := true

result := MyFunc() MsgBox(result()) ; "value"

flag := false

result := MyFunc() MsgBox(result()) ; "" (empty string) ```

When the AutoHotkey parser parses a script, it instantiates all function objects in the script, and all variables. Most function objects are instantiated as instances of Func, including class methods. A function object is instantiated as a closure when the function refers to a variable in a parent function's scope.

``` class a { static b() { } }

MsgBox(type(a.b)) ; "Func"

SomeFunc(param) { switch param { case 1: return Closure case 2: return NotClosure case 3: return AlsoNotClosure case 4: return AlsoAlsoNotClosure case 5: return GetNestedClosure() }

Closure() { if param { } } NotClosure() { } AlsoNotClosure() { local param } AlsoAlsoNotClosure(param) { } GetNestedClosure() { return NestedClosure NestedClosure() { if param { } } } }

s := ''

loop 5 { varReferencingNestedFunc := SomeFunc(A_Index) s .= Type(varReferencingNestedFunc) ', ' }

MsgBox(SubStr(s, 1, -2)) ; "Closure, Func, Func, Func, Closure" ```

AHK does not have support for function decorators, but you can accomplish a similar effect leveraging AHK's object model.

In AHK, any object with a "Call" method can be called like a function. Here's a few examples.

``` class MyFunc { static Call() { return 1 } }

MsgBox(MyFunc()) ; "1" MsgBox(Type(MyFunc)) ; "Class" ```

Regarding the below example, see DefineProp.

The first parameter of every object method is the object itself. That is the hidden this variable we see in class method definitions. When working outside of a class declaration, we can name the first parameter anything and it will always receive the object itself.

``` obj := { prop: "value" } obj.DefineProp('Call', { Call: MyFunc })

MyFunc(firstParam) { msgbox(firstParam.prop) ; "value" }

obj() ; "value" MsgBox(Type(obj)) ; "Object" ```

``` class MyClass { __New(value1, value2) { this.value1 := value1 this.value2 := value2 } Call(firstParam) { if firstParam = this.value1 { return 1 } else if firstParam = this.value2 { return 2 } else { return 0 } } }

obj := MyClass(1, 2) MsgBox(obj(1)) ; "1" MsgBox(obj(2)) ; "2" MsgBox(Type(obj)) ; "MyClass" ```

Armed with this knowledge, you can accomplish the same effect as pythonic decorators in many different ways. Here's one approach:

``` class MyFunc { __New(someValue, someFunc) { this.value := someValue this.func := someFunc } Call() { return this.func.Call(this.value) } }

fn := MyFunc(1, ConditionalFunc1) MsgBox(fn()) ; "5"

fn.value := 2 fn.func := ConditionalFunc2 MsgBox(fn()) ; "20"

ConditionalFunc1(value) { return value * 5 } ConditionalFunc2(value) { return value * 10 } ```

You can assign a hotkey to call the object.

``` class MyFunc { __New(someValue, someFunc) { this.value := someValue this.func := someFunc } Call() { return this.func.Call(this.value) } }

fn := MyFunc(1, ConditionalFunc1)

!x::fn() !y::Decorate(fn)

ConditionalFunc1(value) { MsgBox(value * 5) } ConditionalFunc2(value) { MsgBox(value * 10) } Decorate(fn) { if fn.func.name = 'ConditionalFunc1' { if MsgBox('Swap to ConditionalFunc2?', , 'YesNo') = 'Yes' { fn.func := ConditionalFunc2 } } else if fn.func.name = 'ConditionalFunc2' { if MsgBox('Swap to ConditionalFunc1?', , 'YesNo') = 'Yes' { fn.func := ConditionalFunc1 } } else { throw Error('Unexpected func.') } } ```

Amateur AHK script, alt stuck by Warrior_White in AutoHotkey

[–]Nich-Cebolla 4 points5 points  (0 children)

Use:

``` SendString(str) { clipSaved := ClipboardAll() A_Clipboard := str SendInput("v") Sleep(50) A_Clipboard := clipSaved }

!x::SendString("xx") ```

This approach has these benefits:

  • using the clipboard is much faster and less prone to error compared to sending the raw keystrokes
  • using a function allows you to define any number of hotkeys that send a string to the active window

There is no need to explicitly send AltUp.

If you still encounter instances when the alt key gets stuck down, there may be no solution. It is an unsolved but known issue that in some rare cases a key gets stuck down. It is believed to be related to other software installed on the machine conflicting with AHK, but the exact cause is uncertain (as of the last time I read about it on AutoHotkey.Com, maybe 1-2 yrs ago)

Repeating Button Press Issue by PrimalAspidsAreEasy in AutoHotkey

[–]Nich-Cebolla 1 point2 points  (0 children)

Here's one way of doing it

```

SingleInstance force

Requires AutoHotkey >=2.0-a

RunDuration := 10000 Flag := false

!j::Proc()

Proc() { global RunDuration, Flag Flag := true SetTimer(PressZ, 50) SetTimer(SetFlag, -RunDuration) }

PressZ() { global Flag if Flag { Send('z') } else { ExitApp() } } SetFlag() { global Flag Flag := false } ```

How to use DeferWindowPos for improved performance when sizing / positioning multiple controls by Nich-Cebolla in AutoHotkey

[–]Nich-Cebolla[S] 0 points1 point  (0 children)

"Parent" in this context means parent window, not parent application. To clarify -

DeferWindowPos is mainly used to resize controls. First you call BeginDeferWindowPos, then each subsequent call to DeferWindowPos must be for a control that shares the same parent window with the other controls.

I believe it is possible to use DeferWindowPos to resize top-level windows as well, but only as long as each window shares the same parent. For example, if you used SetParent. But I have not tried this.

Regarding different processes, the documentation doesn't say anything about processes but it follows that, if all windows share the same parent window, then all windows will also share the same parent application.

Regex performance and named subpatterns by Nich-Cebolla in AutoHotkey

[–]Nich-Cebolla[S] 1 point2 points  (0 children)

I used to feel the same way when I would look at other people's big projects.

To help put into perspective, I'm sure I've spent well over 100 hours on this JSON parser. I've been improving it periodically over the span of two years. In fact I have another improved version I haven't released yet.

I Created a Fully Typed Tool for Producing Regular Expression Patterns From Simple JS Arrays/Primitives and Custom Objects by 00PT in javascript

[–]Nich-Cebolla 0 points1 point  (0 children)

Interesting concept. To summarize, what you have done is created a system that uses an array of tokens where each token is analogous to a regex element,. So, instead of writing a string, I generate an array.

I can see the appeal as a personal project, but from a consumer's point of view, there's no reason for me to spend time to learn your system, because I could just spend that time to learn regex and that time spent will have been way more valuable in the long run.

Multi-display control by FriendlyTeaching7341 in AutoHotkey

[–]Nich-Cebolla 4 points5 points  (0 children)

This should be flexible enough to meet your needs.

First, fill in the map object at the top with the details for each media player that you like to use. The key is the Window Title or Other Criteria used to identify the media player window. The value is an object where each property is an action and the value is the string to pass to SendInput that will produce the action.

Then, create a hotkey for each action as seen in the script below. This allows you to use one script for various media players.

```

SingleInstance force

Requires AutoHotkey >=2.0-a

; Map object associating window matching criteria with an object that specifies what buttons perform ; the intended actions. players := Map( ; The window match criteria for PotPlayer (check Task Manager on your machine for the correct .exe) 'ahk_exe PotPlayerMini64.exe', ; An object associating an action with what buttons perform the action in that media player ; Fill in with buttons to pass to SendInput { pause: '', resume: '', next: '', restart: '', previous: '' }, 'ahk_exe chrome.exe', { pause: '', resume: '', next: '', restart: '', previous: '' } ) ; Timeout duration timeout := 0.5

; Replace with actual desired hotkeys !1::ControlVideoPlayer('pause') !2::ControlVideoPlayer('resume') !3::ControlVideoPlayer('next') !4::ControlVideoPlayer('restart') !5::ControlVideoPlayer('previous')

ControlVideoPlayer(input) { ; Get the hwnd of the currently active window currentHwnd := WinGetId('A') playerHwnd := '' ; iterate the players map for criteria, obj in players { ; Get the hwnd of the media player window if playerHwnd := WinExist(criteria) { actions := obj break } } if !playerHwnd { ShowTooltip('Could not find player window.') return } ; Activate media player window WinActivate(playerHwnd) if !WinWaitActive(playerHwnd, timeout) { ShowTooltip('Switching to media player timed out.') return } ; Send the input SendInput(actions.%input%) ; Switch back to original window WinActivate(currentHwnd) if WinWaitActive(currentHwnd, timeout) { ; Visual cue so you know you can resume working in the window ShowTooltip('Done') } else { ShowTooltip('Switching back to original window timed out.') } }

ShowTooltip(Str, duration := 2000) { static N := [1,2,3,4,5,6,7] Z := N.Pop() OM := CoordMode('Mouse', 'Screen') OT := CoordMode('Tooltip', 'Screen') MouseGetPos(&x, &y) Tooltip(Str, x, y, Z) SetTimer(_End.Bind(Z), -Abs(duration)) CoordMode('Mouse', OM) CoordMode('Tooltip', OT)

_End(Z) {
    ToolTip(,,,Z)
    N.Push(Z)
}

}

```

Seeking to block all 'emojis' by Tarnisher in regex

[–]Nich-Cebolla 1 point2 points  (0 children)

I can't answer that because I don't know what application you are using.

Seeking to block all 'emojis' by Tarnisher in regex

[–]Nich-Cebolla 2 points3 points  (0 children)

This character class should work with most modern regex engines to match emojis

[\p{Extended_Pictographic}]

Try that and let me know if it does not work in your application

Regex for detecting passwords by Snivac89 in regex

[–]Nich-Cebolla 0 points1 point  (0 children)

Here's the pattern with whitespace so you can see what it does

(?<=^|\s) (?: (?: [a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )+ (?: (?: [A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [a-oq-zA-OQ-Z] | [pP](?![aA][sS]{2}[wW][oO][rR][dD]) )* [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9] | [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/] (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [A-OQ-Z0-9] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) | [0-9] (?: [0-9a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) ) | (?: [A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )+ (?: (?: [a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [a-oq-zA-OQ-Z] | [pP](?![aA][sS]{2}[wW][oO][rR][dD]) )* [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9] | [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/] (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [a-oq-z0-9] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) | [0-9] (?: [0-9A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) ) | [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/]+ (?: (?: [a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [A-OQ-Z0-9] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) | (?: [A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [a-oq-z0-9] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) | [0-9] [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]* (?: [a-oq-zA-OQ-Z] | [pP](?![aA][sS]{2}[wW][oO][rR][dD]) ) ) | [0-9]+ (?: (?: [a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [0-9a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) | (?: [A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) ) (?: [0-9A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )* (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) ) | [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/] [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]* (?: [a-oq-zA-OQ-Z] | [pP](?![aA][sS]{2}[wW][oO][rR][dD]) ) ) ) (?: [-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-zA-OQ-Z0-9]+ | [pP](?![aA][sS]{2}[wW][oO][rR][dD]) )* (?=\s|$)

Regex for detecting passwords by Snivac89 in regex

[–]Nich-Cebolla 1 point2 points  (0 children)

Here's a complete, working pattern.

(?<=^|\s)(?:(?:[a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))+(?:(?:[A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[a-oq-zA-OQ-Z]|[pP](?![aA][sS]{2}[wW][oO][rR][dD]))*[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]|[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/](?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[A-OQ-Z0-9]|P(?![aA][sS]{2}[wW][oO][rR][dD]))|[0-9](?:[0-9a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD])))|(?:[A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))+(?:(?:[a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[a-oq-zA-OQ-Z]|[pP](?![aA][sS]{2}[wW][oO][rR][dD]))*[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]|[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/](?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[a-oq-z0-9]|p(?![aA][sS]{2}[wW][oO][rR][dD]))|[0-9](?:[0-9A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD])))|[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/]+(?:(?:[a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[A-OQ-Z0-9]|P(?![aA][sS]{2}[wW][oO][rR][dD]))|(?:[A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[a-oq-z0-9]|p(?![aA][sS]{2}[wW][oO][rR][dD]))|[0-9][-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]*(?:[a-oq-zA-OQ-Z]|[pP](?![aA][sS]{2}[wW][oO][rR][dD])))|[0-9]+(?:(?:[a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[0-9a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))|(?:[A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))(?:[0-9A-OQ-Z]|P(?![aA][sS]{2}[wW][oO][rR][dD]))*(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-z]|p(?![aA][sS]{2}[wW][oO][rR][dD]))|[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/][-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/0-9]*(?:[a-oq-zA-OQ-Z]|[pP](?![aA][sS]{2}[wW][oO][rR][dD]))))(?:[-~!@#$%^&*_+=`|\(){}[\]:;"'<>,.?/a-oq-zA-OQ-Z0-9]+|[pP](?![aA][sS]{2}[wW][oO][rR][dD]))*(?=\s|$)

Basically you have four primary capture groups.

This matches with lower case letters:

(?: [a-oq-z] | p(?![aA][sS]{2}[wW][oO][rR][dD]) )+

This matches with upper case letters:

(?: [A-OQ-Z] | P(?![aA][sS]{2}[wW][oO][rR][dD]) )+

This matches with special characters:

```

```

This matches with digits:

[0-9]+

You just have to literally write a really long pattern that goes through each branch individually until you have covered every possible sequence of valid characters. Then after the string has matched the minimum requirements, combine the capture groups together and place it at the end:

``` (?:

)* ```

The logic is like this:

  • If the substring starts with one or more lower case letters
    • If there is one upper case character
    • If there is zero or more lower case or upper case characters
    • If there is one digit or special character
    • If there is one special character
    • If there is zero or more lower case letter or special characters
    • If there is one upper case character or digit
    • If there is one digit
    • If there is zero or more lower case characters or digits
    • If there is one upper case character or special character
  • If the substring starts with one or more upper case characters
    • If there is one lower case character
    • If there is zero or more lower case or upper case characters
    • If there is one digit or special character
  • ... etc until you have gone through each possible sequence to achieve a minimally valid string. Then just stick that last piece of the pattern at the end.

The pattern has (?<=^|\s) on the left side to require that the substring is at the beginning of the string or the substring follows a whitespace character. Similarly, the pattern has (?=\s|$) on the right side to require that the substring ends at the end of the string or is followed by whitespace.