The function in OnClipboardChange gets executed twice when taking screenshot with ShareX Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
NorInd
Posts: 44
Joined: 03 May 2020, 04:23

The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

11 Nov 2021, 01:16

[Moderator's note: Topic moved from Bug Reports.]

Problem:
The function in OnClipboardChange gets executed twice when taking screenshot with ShareX
(Though, this may not be a bug of AHK, but a bug of ShareX?)

Procedure:
1. execute the following script
2. take a screenshot with ShareX
3. the function AA() will execute twice instead of once

Note:
  • In step 2, If you copy a text instead, it works fine.
  • In step 2, If you use printscreen instead, it works fine.
  • If you test the script with MsgBox, aa , you won't have that bug.
  • No issue in other softwares
Script:

Code: Select all

#NoEnv
#SingleInstance Force 
#Persistent 

OnClipboardChange("AA", 1)

AA() {
  SendInput, aa
  ; If you test with [c] MsgBox, aa [/c], you won't have that bug
}
Log file:

---- C:\Users\XXX\Desktop\AHK scripts\Test\Test.ahk
005: OnClipboardChange("AA", 1)
007: {
011: Exit (6.02)
008: SendInput,aa
010: } (0.01)
008: SendInput,aa
010: } (1.06)

Press [F5] to refresh.
User avatar
boiler
Posts: 17393
Joined: 21 Dec 2014, 02:44

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

11 Nov 2021, 02:08

If the Send command is somehow triggering a clipboard change when used with ShareX, try unregistering it before the Send:

Code: Select all

#NoEnv
#SingleInstance Force 
#Persistent 

OnClipboardChange("AA", 1)

AA() {
  OnClipboardChange("AA", 0)
  SendInput, aa
  OnClipboardChange("AA", 1)
}
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

11 Nov 2021, 05:21

The function is called in response to a WM_CLIPBOARDUPDATE message. If it is called twice, that is because the system sent two messages, which is because the clipboard content changed twice. DllCall("GetClipboardSequenceNumber") will also show that the clipboard content has changed (although that does not mean the new content is different to the old content).

I was curious as to how sending keystrokes could have this effect, so I tested it. I think it was initially as you describe, but after some time, I could not reproduce it: every time ShareX took a screenshot, there were two WM_CLIPBOARDUPDATE messages, regardless of what action the script took or whether I used PrintScreen or the context menu.
NorInd
Posts: 44
Joined: 03 May 2020, 04:23

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

12 Nov 2021, 18:50

boiler wrote:
11 Nov 2021, 02:08
If the Send command is somehow triggering a clipboard change when used with ShareX, try unregistering it before the Send:
This does not fix the issue. Because "the Send command" does not "triggering a clipboard change".

I think the problem is like what lexikos says:
lexikos wrote:
11 Nov 2021, 05:21
every time ShareX took a screenshot, there were two WM_CLIPBOARDUPDATE messages

But I can't think of a solution for this.
User avatar
boiler
Posts: 17393
Joined: 21 Dec 2014, 02:44

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

12 Nov 2021, 19:21

NorInd wrote: I think the problem is like what lexikos says:
lexikos wrote:
11 Nov 2021, 05:21
every time ShareX took a screenshot, there were two WM_CLIPBOARDUPDATE messages

But I can't think of a solution for this.
Try checking the Type parameter that is sent to the function when ShareX changes the clipboard each time. Perhaps one time it is 0 because it first clears it and the next it is 2 because it then loads it with the captured image. It it is different, then you can have the function act only when it receives one of those values.

Reference from OnClipboardChange():
FunctionName(Type)
Type
Contains one of the following numbers:

0 = Clipboard is now empty.
1 = Clipboard contains something that can be expressed as text (this includes files copied from an Explorer window).
2 = Clipboard contains something entirely non-text such as a picture.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX  Topic is solved

13 Nov 2021, 02:15

During my tests, the clipboard contained the exact same set of formats each time.

If you want to work around the function being called twice, there are multiple potential solutions, including:
  • Exclude calls that come too closely together.
  • Save the clipboard content in each call, and compare it to the last call.
  • Be more selective about when you take action (depends on what the goal is).
  • Check which process "owns" the clipboard (see below).
  • Some combination.

Code: Select all

#Persistent
OnClipboardChange("ClipChange")
ClipChange() {
    hwnd := DllCall("GetClipboardOwner", "ptr")
    DetectHiddenWindows On
    WinGet name, ProcessName, ahk_id %hwnd%
    ToolTip Clipboard changed by %name%
}
NorInd
Posts: 44
Joined: 03 May 2020, 04:23

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

15 Nov 2021, 20:44

boiler wrote:
12 Nov 2021, 19:21
Try checking the Type parameter that is sent to the function when ShareX changes the clipboard each time. Perhaps one time it is 0 because it first clears it and the next it is 2 because it then loads it with the captured image.
I don't think it is 0 in the first time.
But check Type can be helpful.
NorInd
Posts: 44
Joined: 03 May 2020, 04:23

Re: The function in OnClipboardChange gets executed twice when taking screenshot with ShareX

15 Nov 2021, 20:54

lexikos wrote:
13 Nov 2021, 02:15

Code: Select all

#Persistent
OnClipboardChange("ClipChange")
ClipChange() {
    hwnd := DllCall("GetClipboardOwner", "ptr")
    DetectHiddenWindows On
    WinGet name, ProcessName, ahk_id %hwnd%
    ToolTip Clipboard changed by %name%
}
Base on lexikos code, here is what I wrote, I test it simply, its working.
(But I may just live with how originally ShareX works, because the code feels a bit cumbersome, may slow down the code execution speed.)
OldCode


Side Notes::
lexikos wrote:
13 Nov 2021, 02:15
If you want to work around the function being called twice, there are multiple potential solutions, including:
  • Exclude calls that come too closely together.
  • Save the clipboard content in each call, and compare it to the last call.
These are also good solutions.
"Exclude calls that come too closely together." Can be implemented with checking the Type.

Thanks to boiler and lexikos.


CodeUpdate (20211117_190)::
Move the position of DetectHiddenWindows Off up.
Changed naming.
CodeUpdate (20211121_025)::
Fix the wrong Type check. (should be 2 not 1)

Code: Select all

#NoEnv
#SingleInstance Force 
#Persistent 

OnClipboardChange("fnA", 1)

; @bugfix
; >> Check if its pure image and if its accesed by ShareX
toggle_ShareXExecutedOnce := 0

fnA(type_Clip) {
  ; @bugfix
  ; >> Check if its pure image and if its accesed by ShareX
  if (type_Clip == 2) {
    hwnd := DllCall("GetClipboardOwner", "ptr")
    DetectHiddenWindows On
    WinGet, nameprocess_ClipOwner, ProcessName, ahk_id %hwnd%
    DetectHiddenWindows Off
    
    if (nameprocess_ClipOwner == "ShareX.exe") {
      global toggle_ShareXExecutedOnce
      if (toggle_ShareXExecutedOnce := !toggle_ShareXExecutedOnce) {
        goto, executeCommand
      } else {
        return
      }
    }
  }
  
  executeCommand:
  SendInput, aa
  
  return
}


Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Chunjee, Descolada, GroggyOtter, Mateusz53, moltenchees and 168 guests