AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

ControlGetFocus disables Doubleclick
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Bug Reports
View previous topic :: View next topic  
Author Message
Tekl



Joined: 24 Sep 2004
Posts: 813
Location: Germany

PostPosted: Thu Oct 07, 2004 3:06 pm    Post subject: ControlGetFocus disables Doubleclick Reply with quote

Hello,

I've made a script which shows me a tooltip if a entered Filename in a file-dialog-box is longer than 31 chars.

If this script is running and press Ctrl+O for example in the Notepad, than there it is not possible to open a folder with a double-click.

If I increase the timer to 400 then it works If I klick inbetween this time.

Well, if I replace

ControlGetFocus, control, ahk_id %active_id%

with

control=Edit1

it works, so the doubleclick-stealer seems to be this Command.

Code:

#persistent
SetTimer, Warner, 100
return

Warner:
; 31-Zeichen-Warner
   WinGet, active_id, ID, A
   WinGetClass, f_class, ahk_id %active_id%
   If f_class = #32770
   {
      WinGetActiveTitle, wintitle
      WinGetText, wintext, ahk_id %active_id%
      if wintext contains Dateiname,Filename,Folder,Verzeichnis,Ordner,Öffnen,Speichern
      {
         ControlGetFocus, control, ahk_id %active_id%
         if control = Edit1
         {
            ControlGetText, edittext, Edit1, ahk_id %active_id%
            SplitPath,edittext,fname
            StringLen,editlen,fname
            if editlen <> %Tip31%
            {
               if editlen > 31
               {
                  X = %A_CaretX%
                  X += 7
                  Y = %A_CaretY%
                  Y += 13
                  ToolTip, Dateiname länger als 31 Zeichen (%editlen%),%X%,%Y%,3
                  Tip31=%editlen%
                  SetTimer, Tip31, 1600
                  return
               }
                  else
               {
                  if editlen = 31
                  {
                     X = %A_CaretX%
                     X += 7
                     Y = %A_CaretY%
                     Y += 13
                     ToolTip, OK,%X%,%Y%,3
                     Tip31=%editlen%
                     SetTimer, Tip31, 600
                     return
                  }
                     else
                  {
                     Gosub, Tip31
                  }
               }
            }
         }
      }
      else
      {
         Gosub, Tip31
      }
   }
   else
   {
      Gosub, Tip31
   }
return
Tip31:
   ToolTip,,,,3
   SetTimer,Tip31,off
return


Tekl
Back to top
View user's profile Send private message Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Thu Oct 07, 2004 7:36 pm    Post subject: Reply with quote

Thanks. Unfortunately, I don't see any way to fix it. Incidentally, it also happens under AutoIt3.

I've updated the help file with the following:
Quote:
If ControlFocus is executed repeatedly at a high frequency (i.e. every 500 ms or faster), it will probably disrupt the user's ability to double-click. There is no known workaround.
Back to top
View user's profile Send private message Send e-mail
Tekl



Joined: 24 Sep 2004
Posts: 813
Location: Germany

PostPosted: Wed Dec 22, 2004 11:22 am    Post subject: Reply with quote

Hi Chris,

is there another way to get the active controlname?

Tekl
Back to top
View user's profile Send private message Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Wed Dec 22, 2004 1:46 pm    Post subject: Reply with quote

Since the OS does not allow an application to discover the focused control in another application, I can't think of a way (other than a system wide hook, which is currently outside the scope of the project) to do it without internally calling AttachThreadInput(), which is believe is the thing that disrupts double-clicks. Depending on what you want to do, you could use MouseGetPos to find out the control under the mouse cursor.

Assuming that isn't sufficient, you could limit your calls to ControlGetFocus to only when a keystroke or mouseclick occurs. A keystroke event can be detected with the Input command. A mouseclick can be detected by making all mouse buttons into pass-through hotkeys:

~LButton::
~RButton::
~MButton::
; For LButton in particular, give time for a double click to occur beforehand:
Sleep, 500
ControlGetFocus, FocusedControl, A
return
Back to top
View user's profile Send private message Send e-mail
Tekl



Joined: 24 Sep 2004
Posts: 813
Location: Germany

PostPosted: Wed Dec 22, 2004 6:53 pm    Post subject: Reply with quote

Hi Chris,

well, I only want to know, if the cursor is in an edit1-Control. Maybe I'll try to check the window before I check the focus. Or is there a way to check, if the caret is waiting for input?

Tekl
Back to top
View user's profile Send private message Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Wed Dec 22, 2004 7:35 pm    Post subject: Reply with quote

Tekl wrote:
is there a way to check, if the caret is waiting for input?
I don't think so. I though of suggesting A_CaretX and Y to find out where the caret is, but unfortunately, that calls AttachThreadInput(). So it will probably disrupt double-clicks too (if you find out that it doesn't please let me know).

Don't know if this would help, but you could periodically retrieve the text from the Edit1 and see if it's changed from the previous check.
Back to top
View user's profile Send private message Send e-mail
David Andersen



Joined: 15 Jul 2005
Posts: 85
Location: Denmark

PostPosted: Thu Nov 09, 2006 12:21 pm    Post subject: Any progress Reply with quote

Hi,

Has there been any progress on this issue. I really need to see which control has focus with a high frequency. I have tried paying around with Chris' solution, but it does not work in my script for several reasons, the main reason being that it sometimes hinders the user from double clicking, which is very irritating. Mad

Does anyone have any clue on a workaround?
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Thu Nov 09, 2006 5:40 pm    Post subject: Reply with quote

I've added the following example to the documentation. Hopefully it will be enough for what you need:
Code:
; This script retrieves the ahk_id (HWND) of the active window's focused control.
; This script requires Windows 98+ or NT 4.0 SP3+.
GuiThreadInfoSize = 48
VarSetCapacity(GuiThreadInfo, GuiThreadInfoSize)
InsertInteger(GuiThreadInfoSize, GuiThreadInfo, 0)
if not DllCall("GetGUIThreadInfo", uint, 0, str, GuiThreadInfo)
{
   MsgBox GetGUIThreadInfo() indicated a failure.
   return
}
FocusedHWND := ExtractInteger(GuiThreadInfo, 12)  ; Retrieve the hwndFocus field from the struct.
MsgBox % "The focused control's ahk_id (HWND) is " . FocusedHWND
; This ID can be used all control commands.  For example:
; ControlGetText, OutputVar,, ahk_id %FocusedHWND%
Code:

; SUPPORT FUNCTIONS:

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
    Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
        DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
{
    Loop %pSize%  ; Build the integer by adding up its bytes.
        result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
    if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
        return result  ; Signed vs. unsigned doesn't matter in these cases.
    return -(0xFFFFFFFF - result + 1)
}

MSDN docs: GetGUIThreadInfo()
Back to top
View user's profile Send private message Send e-mail
David Andersen



Joined: 15 Jul 2005
Posts: 85
Location: Denmark

PostPosted: Fri Nov 10, 2006 12:52 pm    Post subject: Reply with quote

Thanks a lot Chris! This really helps me one step on the way.

My problem now is to retreve the name of the control (like "Edit1") from the HWND. This should be fairly trivial, but I cannot use any of the standard functions like ControlGet etc. A search on the forum got me to an article of how to get the HWND from the control name, but not the other way around.
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Fri Nov 10, 2006 1:40 pm    Post subject: Reply with quote

I don't see why you need it. As stated in my post above, this ahk_id number (HWND) can be used all control commands. For example:
ControlGetText, OutputVar,, ahk_id %FocusedHWND%
Back to top
View user's profile Send private message Send e-mail
David Andersen



Joined: 15 Jul 2005
Posts: 85
Location: Denmark

PostPosted: Fri Nov 10, 2006 2:46 pm    Post subject: Reply with quote

The reason is that I want to record macros that are reusable even after the user has closed the given window. As far as I could see the HWND id of a control is different each time one opens the given application.
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10467

PostPosted: Fri Nov 10, 2006 10:54 pm    Post subject: Reply with quote

I don't think there's an easy way to do it, so you might have to design the script to dynamically fetch the ahk_id (HWND) every time. If that isn't feasible, you could try the following, though I'm not proficient in it so it might not work (and might require more research):

ControlID := DllCall("GetDlgCtrlID", uint, ControlHWND) ; Given the ahk_id (HWND), this retrieves a unique identifier of the control that might be persistent across sessions.

ControlHWND := DllCall("GetDlgItem", uint, ParentHWND, int, ControlID) ; This goes the opposite direction: given the parent window's ahk_id and the control's controlID, it gets the ControlHWND, which can then be used via ahk_id in all the control commands.
Back to top
View user's profile Send private message Send e-mail
David Andersen



Joined: 15 Jul 2005
Posts: 85
Location: Denmark

PostPosted: Sat Nov 11, 2006 4:34 pm    Post subject: Reply with quote

Thanks again Chris! The identifier gotten from ControlID := DllCall("GetDlgCtrlID", uint, ControlHWND) is not always unique across sessions. I noticed this by focusing on the "font" control inside Microsoft Word which was different when I had two windows of Word open. The URL edit control in Firefox also has the number 0.

After further researching, I came across the following article:
http://msdn2.microsoft.com/en-us/library/ms996405.aspx

In the section "Recommended Solution for Windows Forms", which should be an article of general interest. It describes using WM_GETCONTROLNAME to get the name given the HWND. I attempted to use WM_GETCONTROLNAME in a send message call, but I cannot find the hex (like 0x111) number for WM_GETCONTROLNAME, and a general search on google did not get me further. Any clues?
Back to top
View user's profile Send private message Send e-mail Visit poster's website
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Sun Nov 12, 2006 9:41 am    Post subject: Reply with quote

First site I looked at when searching WM_GETCONTROLNAME in Google: http://www.pcreview.co.uk/forums/thread-1229324.php
It seems this message can be used only internally. Not even sure it works outside Windows Forms (a .NET technology I believe).
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
David Andersen



Joined: 15 Jul 2005
Posts: 85
Location: Denmark

PostPosted: Sun Nov 26, 2006 12:51 pm    Post subject: Reply with quote

I have now spent an awful lot of time on this without getting any further. If someone can solve this problem, I will pay them a symbolic 50$ over PayPal.

What I need is this:
The ControlGetFocus to work without hindering the double click, and without taking up unreasonable amounts of resources like CPU and memory. I suggest first retreving the HWND of the control and, somehow retreving the identifier of the control (just like ControlGetFocus) from there.

I hope you can help me out.

Regards,

David
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Bug Reports All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group