3
votes

I'm trying to write an AutoHotKey script that will activate my Git Gui window, refresh it, and put the focus in the commit-comment text box. Activating and refreshing are no problem, but I'm not having any success changing focus. AutoHotKey doesn't seem to be correctly detecting the child controls in the Git Gui window.

If I run AutoHotKey's Window Spy utility, switch to the Git Gui window, and put the mouse over the commit-comment text box, Window Spy shows the following output (abbreviated):

>>>>>>>>>>( Window Title & Class )<<<<<<<<<<<
Git Gui (Tyler08) C:/svn/Tyler08
ahk_class TkTopLevel

>>>>>>>>>>>>( Mouse Position )<<<<<<<<<<<<<
On Screen:  808, 727  (less often used)
In Active Window:   816, 735

>>>>>>>>>( Now Under Mouse Cursor )<<<<<<<<
ClassNN:    TkChild18
Text:   
Color:  0xF0F0F0  (Blue=F0 Green=F0 Red=F0)

So it looks like the class name of that edit box is TkChild18, and I would expect to be able to write the following in my AutoHotKey script:

NumpadAdd::
ControlFocus, TkChild18, Git Gui (Tyler08) C:/svn/Tyler08
return

But when I start this script and then press Numpad +, nothing happens. I expected the focus to move to the commit-comment text box, but the focus doesn't change at all.

In trying to troubleshoot this, I built the following script based on the AutoHotKey docs for ControlGetFocus:

NumpadAdd::
ControlGetFocus, OutputVar, Git Gui (Tyler08) C:/svn/Tyler08
if ErrorLevel
    MsgBox, The target window doesn't exist or none of its controls has input focus.
else
    MsgBox, Control with focus = %OutputVar%

Now if I activate the Git Gui window and press Numpad +, AutoHotKey pops up a message box that says: "Control with focus = TkChild1". No matter where the focus is -- whether the focus is in the commit-comment text box, or in the diff pane, or in the "New Commit" or "Amend Last Commit" radio buttons, or in any of the buttons -- AutoHotKey always reports that the focus is TkChild1. This disagrees with Window Spy, which is able to see all the child windows (TkChild18, etc.)

The above script does work with at least some other apps (as long as I change the window title in the second line). It shows its "target window doesn't exist..." failure message if a WPF element has focus (e.g. the Output window in Visual Studio 2010) but it succeeds if a WinForms control has focus (e.g. VS2010's Properties grid). So I know I've got the right syntax for the ControlGetFocus command. I suspect that Git Gui is doing something strange with its child windows (it's built with the Tk framework, which may do something weird that AutoHotKey can't handle).

Anyone have any ideas on how I can get AutoHotKey to successfully change focus within the Git Gui window?

Using AutoHotKey Basic v1.0.48.00 and mSysGit version 1.7.3.1-preview20101002 on 64-bit Vista.

1

1 Answers

6
votes

I suspect that Git Gui is doing something strange with its child windows (it's built with the Tk framework, which may do something weird that AutoHotKey can't handle).

I suspect you're right. Most of Autohotkey's commands are merely wrappers for MSFT Win32 api calls. In this case, ControlFocus probably just wraps SetFocus(). If the TK framework doesn't respond to normal windows messages such as WM_SETFOCUS then these won't work.

Your code fails on my computer too. I've tried for a half hour to find a workaround, with no luck other than hacks. Obviously you can just send TAB keypresses until your commit message editbox has focus, but this is unreliable since we cannot accurately check which control does have focus.

So, the best I could come up with is to just resort to sending a basic Click to the box. I tried ControlClick which would prevent mouse movement, but alas, it failed just like all the other Control commands. Ironically ControlGetPos works which allows this solution (otherwise if the Git Gui window is resized, a hardcoded coordinate would fail).

SetTitleMatchMode, 2             ;// allow partial window title matches

NumpadAdd::
   WinActivate, Git Gui
   ControlGetPos, control_x, control_y, , , TkChild18, Git Gui

   CoordMode, Mouse, Screen
   MouseGetPos, mouse_x, mouse_y    ;// grab current mouse screen position

   click_x := control_x + 5      ;// we'll click 5 pixels inside the control
   click_y := control_y + 5
   CoordMode, Mouse, Relative
   Click %click_x%, %click_y%   ;// click relative to active window (moves mouse)

   CoordMode, Mouse, Screen
   MouseMove, %mouse_x%, %mouse_y%, 0   ;// restore old mouse position
return