2
votes
  1. Run this script & Open Notepad
  2. Go to the View menu, and toggle the Status Bar
    If the status bar is on, a checkmark will appear next to the menu item, this script tries to detect whether the status bar menu item is checked
    The problem is it can only determine checked/nonchecked status after the menu is open, how can I alter the code to detect the checked status while the menu is closed/hidden?

    Please don't assume that just because I'm using the notepad status bar example, that all I'm trying to do is determine if the notepad status bar is on/off, I'm not. I'm trying to detect if menu items are checked/unchecked.

    #persistent
    settitlematchmode, 2
    Loop, 
    {
    WinGet, hWnd, ID, Notepad
    hMenu := DllCall("GetMenu", "UPtr", hWnd)
    MenuAndIndex := GetMenuAndIndex(hMenu, "View", "Status Bar")
    State := GetMenuState(MenuAndIndex*)
    if (State.Checked)
        {
        tooltip, View -> Status Bar is checked
        }
    else
    tooltip, View -> Status Bar is unchecked
    }
    
    ; ------------------FUNCTIONS BELOW -----------------
    
    GetMenuState(hMenu, Index)
    {
        State := DllCall("GetMenuState", "UPtr", hMenu, "UInt", Index, "UInt", 0x400)
        if (State == -1)
            return False
        return {"CHECKED": State&0x8, "DISABLED": State&0x2, "GRAYED": State&0x2
        , "HILITE": State&0x80, "MENUBARBREAK": State&0x20, "MENUBREAK": State&0x40
        , "OWNERDAW": State&0x100, "POPUP": State&0x10, "SEPARATOR": State&0x800}
    }
    
    GetMenuAndIndex(hMenu, p*)
    {
        CurrentMenu := hMenu
        For each, MenuName in p
        {
            if SubMenu
                CurrentMenu := SubMenu
            Count := DllCall("GetMenuItemCount", "UPtr", CurrentMenu)
            Loop, % Count
            {
                Index := A_Index - 1
                Name := GetMenuString(CurrentMenu, Index)
                if (RegExReplace(Name, "&|\t.*") = MenuName)
                {
                    SubMenu := DllCall("GetSubMenu", "UPtr", CurrentMenu, "UInt", Index)
                    if SubMenu
                        Continue, 2
                    else
                        return [CurrentMenu, Index]
                }
            }
            return "Item not found"
        }
        return [CurrentMenu, Index]
    }
    
    GetMenuString(hMenu, Index)
    {
            VarSetCapacity(Name, 256, 0)
            DllCall("GetMenuString", "UPtr", hMenu, "UInt", Index
            , "Str", Name, "Int", 128, "UInt", 0x400)
            return Name
    }
    
1
Try out CheckMenuItem or GetMenuItemInfo . If CheckMenuItem returns -1, the menu doesn't exist yet. - Joe DF

1 Answers

1
votes

I don't think there is direct solution for checking if menu items are checked/unchecked without actually opening that menu. So you need indirect ways to do that.

You can check registry keys that menus are changing. For example, from here: Notepad in HKEY_CURRENT_USER\Software\Microsoft\Notepad should have registry key for Status Bar. I think many other software is changing registry according to changes from menu. You can use RegRead command for reading current value of registry key.

Also some software can change .ini file according the changes done from menus. You can use IniRead command for reading values in .ini files.

Use ImageSearch command to search for images on the screen that can be changed by menus. For example, you can search the unique part of Status Bar of Notepad by ImageSearch command. For example this part:
enter image description here

There are many other ways to check the for changes done by menus (opens new window, creates file, etc). Focus on what menu changes can change in system and check for these changes.

Also, always use AutoHotkey and its documenatation from http://ahkscript.org/ (current uptodate version, new official website)! AutoHotkey and its documentation from autohotkey.com is outdated and you may have some problems using them!