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 

How do select an item from the desktop context menu?

 
Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
newbie83
Guest





PostPosted: Tue Oct 13, 2009 6:56 pm    Post subject: How do select an item from the desktop context menu? Reply with quote

I know that in order to invoke any context menu I need to send SHIFT+F10.

But how I make sure that it's always when the desktop is selected? And after that, how do I select a menu item by name, not by location in the menu?

Thanks!
Back to top
Carcophan



Joined: 24 Dec 2008
Posts: 1308
Location: :noitacoL

PostPosted: Tue Oct 13, 2009 8:32 pm    Post subject: Reply with quote

Sorry if I do not understand your questions fully.

Quote:

how I make sure that it's always when the desktop is selected

Windows+D will minimize all, bringing you to your desktop

After WinD you can assume that you are at your desktop, so you can send your Shift+F10

To select it by name, send the character that is underlined

'e' for refresh, 'w' for new, 'r' for properties.

Dunno if this is what you meant or not.
Back to top
View user's profile Send private message
txquestor



Joined: 22 Aug 2009
Posts: 294

PostPosted: Tue Oct 13, 2009 8:55 pm    Post subject: Reply with quote

To Activate a Context Menuitem use this script.
Code:

; ActivateContextMenuItem

; Activate the Desktop Context Menu & Select a Menuitem

; by TXQuestor

#InstallKeybdHook
SetKeyDelay, 0

+F10::
Sleep, 100
WinActivate, Program Manager

Sleep 100
;MouseMove, 50, -255, 5, R    ; VERIFIED - use only if you want to click in a specific position
Sleep 100
Send {RButton} ; VERIFIED
Sleep 100
Send {Down 8}   ; VERIFIED - number of arrow down to select the menuitem
Sleep 100
Send {Enter}   ; VERIFIED

Return
ESC::ExitApp


Sometimes you need to get the menu info by this method
and then use the 'PostMessage" command to activate a menu.
http://www.autohotkey.com/docs/misc/SendMessage.html
http://www.autohotkey.com/forum/topic40112.html

This script gets any menu's Name & ID by Micha

Code:

; Gets all Menuiteminfo values for any type of Menu

; This version Micha added the GetMenuitemID function by my request.

; AutoHotkey Version: 1.x
; Language:       English
; Platform:       Win9x/NT
; Author:         micha
;
; Script Function:
;   Demonstrates how to retrieve infos from a context/ popup menu
;

/*
  This is the struct we are using.

  typedef struct tagMENUITEMINFO {
  UINT    cbSize;
  UINT    fMask;
  UINT    fType;
  UINT    fState;
  UINT    wID;
  HMENU   hSubMenu;
  HBITMAP hbmpChecked;
  HBITMAP hbmpUnchecked;
  ULONG_PTR dwItemData;
  LPTSTR  dwTypeData;
  UINT    cch;
  HBITMAP hbmpItem;
} MENUITEMINFO, *LPMENUITEMINFO;


*/

#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
#Persistent
SetTimer, Demo, 500
return

Demo:
;constants
  MFS_ENABLED = 0
  MFS_CHECKED = 8
  MFS_DEFAULT = 0x1000
  MFS_DISABLED = 2
  MFS_GRAYED = 1
  MFS_HILITE = 0x80
  ;MFS_UNCHECKED = 0
  ;MFS_UNHILITE = 0

  ;Get mouse position and handle to wnd under the mouse cursor
  MouseGetPos, MouseScreenX, MouseScreenY, MouseWindowUID, MouseControlID
  WinGet,ControlHwnd, ID,ahk_id %MouseWindowUID%
  ;Get count of menu items
  ContextMenCnt := GetContextMenuCount(ControlHwnd)
  if ContextMenCnt < 1
  {
   Tooltip,
   return
  }
  TooltipText =
  ;Read info for each menu item
  loop, %ContextMenCnt%
  {
   IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
   {
    CurrentText =
    if IsEnabled = 0
     CurrentText = %CurrentText% Enabled
    if (IsEnabled & MFS_CHECKED)
       CurrentText = %CurrentText% Checked
    if (IsEnabled & MFS_DEFAULT)
       CurrentText = %CurrentText% Default
    if (IsEnabled & MFS_DISABLED)
       CurrentText = %CurrentText% Disabled
    if (IsEnabled & MFS_GRAYED)
       CurrentText = %CurrentText% Grayed
    if (IsEnabled & MFS_HILITE)
       CurrentText = %CurrentText% Highlight
    TooltipText = %TooltipText%%a_index%:%CurrentText%`n
   }
  }
  TextText =
  loop, %ContextMenCnt%
  {
    StrSize := GetContextMenuText(ControlHwnd, a_index-1)
    nID := GetContextMenuID(ControlHwnd, a_index-1)
    TextText = %TextText%%a_index%:%StrSize%-ID=%nID%`n   
  }
  CoordMode, Tooltip, Screen
  ;Tooltip, %TooltipText%---`n%TextText%, 0, 0      ; Shows Enabled/Disabled, Empty, Name, Hotkey & ID of Menuitems
  Tooltip, %TextText%, 0, 0      ; ONLY shows Name, Hotkey & ID of Menuitems

return

/***************************************************************
 * returns the count of menu items
 ***************************************************************
*/
GetContextMenuCount(hWnd)
{
  WinGetClass, WindowClass, ahk_id %hWnd%
  ;All popups should have the window class #32768
  if WindowClass <> #32768
  {
   return 0
  }
  ;Retrieve menu handle from window
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel
  menuitemcount:=DllCall("GetMenuItemCount",UInt,hMenu)
  Return, menuitemcount
}

/***************************************************************
 * returns the state of a menu entry
 ***************************************************************
*/
GetContextMenuState(hWnd, Position)
{
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;We need to allocate a struct
  VarSetCapacity(MenuItemInfo, 60, 0)
  ;Set Size of Struct to the first member
  InsertInteger(48, MenuItemInfo, 0, 4)
  ;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
  InsertInteger(1, MenuItemInfo, 4, 4)

  ;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes != 0
     return -1

  ;Get Flag from struct
  GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 12, false, 4)
  /*
  IsEnabled = 1
  if GetMenuItemInfoRes > 0
     IsEnabled = 0
  return IsEnabled
  */
  return GetMenuItemInfoRes
}

/***************************************************************
 * returns the ID of a menu entry
 ***************************************************************
*/
GetContextMenuID(hWnd, Position)
{
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;UINT GetMenuItemID(          HMENU hMenu,    int nPos);
  InfoRes := DllCall("user32.dll\GetMenuItemID",UInt,hMenu, Uint, Position)

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes != 0
     return -1

  return InfoRes
}

/***************************************************************
 * returns the text of a menu entry (standard windows context menus only!!!)
 ***************************************************************
*/
GetContextMenuText(hWnd, Position)
{
  WinGetClass, WindowClass, ahk_id %hWnd%
  if WindowClass <> #32768
  {
   return -1
  }
  SendMessage, 0x01E1, , , , ahk_id %hWnd%
  ;Errorlevel is set by SendMessage. It contains the handle to the menu
  hMenu := errorlevel

  ;We need to allocate a struct
  VarSetCapacity(MenuItemInfo, 200, 0)
  ;Set Size of Struct (48) to the first member
  InsertInteger(48, MenuItemInfo, 0, 4)
  ;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
  InsertInteger(64, MenuItemInfo, 4, 4)
  ;Set type - Get only size of string we need to allocate
  ;InsertInteger(0, MenuItemInfo, 8, 4)
  ;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
  if InfoRes = 0
     return -1

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes <> 0
     return -1

  ;Get size of string from struct
  GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 40, false, 4)
  ;If menu is empty return
  If GetMenuItemInfoRes = 0
     return "{Empty String}"

  ;+1 should be enough, we'll use 2
  GetMenuItemInfoRes += 2
  ;Set capacity of string that will be filled by windows
  VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)
  ;Set Size plus 0 terminator + security ;-)
  InsertInteger(GetMenuItemInfoRes, MenuItemInfo, 40, 4)
  InsertInteger(&PopupText, MenuItemInfo, 36, 4)

  InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
  if InfoRes = 0
     return -1

  InfoResError := errorlevel
  LastErrorRes := DllCall("GetLastError")
  if InfoResError <> 0
     return -1
  if LastErrorRes <> 0
     return -1

  return PopupText
}

; *********************************
; *********************************
; Original versions of ExtractInteger and InsertInteger provided by Chris
; - from the AutoHotkey help file - Version 1.0.37.04
; *********************************
; *********************************
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).
{
   SourceAddress := &pSource + pOffset  ; Get address and apply the caller's offset.
   result := 0  ; Init prior to accumulation in the loop.
   Loop %pSize%  ; For each byte in the integer:
   {
      result := result | (*SourceAddress << 8 * (A_Index - 1))  ; Build the integer from its bytes.
      SourceAddress += 1  ; Move on to the next byte.
   }
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result  ; Signed vs. unsigned doesn't matter in these cases.
   ; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
   return -(0xFFFFFFFF - result + 1)
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; To preserve any existing contents in pDest, only pSize number of bytes starting at pOffset
; are altered in it. The caller must ensure that pDest has sufficient capacity.
{
   mask := 0xFF  ; This serves to isolate each byte, one by one.
   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  ; Write one byte.
         , UChar, (pInteger & mask) >> 8 * (A_Index - 1))  ; This line is auto-merged with above at load-time.
      mask := mask << 8  ; Set it up for isolation of the next byte.
   }
}
; *********************************
; *********************************

PrintScreen::reload
ESC::ExitApp


Have Fun Exclamation Exclamation Surprised
_________________

"Man's quest for knowledge is an expanding series whose limit is infinity"


Last edited by txquestor on Tue Oct 13, 2009 11:14 pm; edited 2 times in total
Back to top
View user's profile Send private message
newbie83
Guest





PostPosted: Wed Oct 14, 2009 4:48 pm    Post subject: Reply with quote

Carcophan wrote:
Windows+D will minimize all, bringing you to your desktop

Thank you Carcophan txquestor. I am still struggling with this. Right now, all I am trying to do is to minimize all windows. I tried
Code:
Send {#D}

but it didn't work. So I tried:
Code:
Send {LWin Down}
Send {D}
Send {LWin Up}

And it still didn't work.

What am I doing wrong?

I have Windows XP SP2 with an old keyboard that doesn't have the Windows key. Could that be the reason?

Thanks!
Back to top
newbie83
Guest





PostPosted: Wed Oct 14, 2009 4:53 pm    Post subject: Reply with quote

I forgot to mention that in my attempts to minimize all windows I also tried:
Code:
WinActivate, Program Manager

And it didn't work either.

I must be doing something wrong but what is it?
Back to top
newbie83
Guest





PostPosted: Wed Oct 14, 2009 5:10 pm    Post subject: Reply with quote

Taking back my last statement:
newbie83 wrote:
I forgot to mention that in my attempts to minimize all windows I also tried:
Code:
WinActivate, Program Manager

And it didn't work either.

This works! (unlike the suggested #D) but it doesn't minimize all windows, it only deactivates them.

This is fine with me. I now need to find a way to find an empty spot on the desktop ("Program Manager") to access its context menu.

Thanks!
Back to top
txquestor



Joined: 22 Aug 2009
Posts: 294

PostPosted: Wed Oct 14, 2009 7:26 pm    Post subject: Reply with quote

You don't need a empty postion on the desktop to activate the context menu with the code I gave you above.
However, look at the code line I commented out. "MoiuseMove"
Just change the mouse position to choose the posttion you want
Code:

^!m::
; Minimize all windows on the desktop
MinimizeAllWindows:
WinMinimizeAll
return

_________________

"Man's quest for knowledge is an expanding series whose limit is infinity"
Back to top
View user's profile Send private message
newbie83
Guest





PostPosted: Thu Oct 15, 2009 4:08 pm    Post subject: Reply with quote

txquestor wrote:
You don't need a empty postion on the desktop to activate the context menu with the code I gave you above.


txquestor, thanks again but try the following complete script:
Code:
Hotkey, F12, WINACT
return

WINACT:
WinActivate, Program Manager

Sleep 100
Sleep 100
Send {RButton}
Sleep 100
Send {Down 5}   ;  number of arrow down to select the menuitem

return

When you press F12 while a file is selected in Windows Explorer, the context menu invoked is not the Desktop's one.

Can you explain this? What is the solution?

Thanks!
Back to top
sinkfaze



Joined: 18 Mar 2008
Posts: 5044
Location: the tunnel(?=light)

PostPosted: Thu Oct 15, 2009 4:47 pm    Post subject: Reply with quote

Carcophan wrote:
Windows+D will minimize all, bringing you to your desktop


If I'm not mistaken Win+D brings the desktop to the top of the stack but does not minimize all windows (which explains why you can toggle back and forth with that command). Win+M is the true minimize all un-minimized windows command (and Win+Shift+M restores them). They essentially perform the same function just in different ways but some applications are known to conflict with stack order/priority, which is why I tend not to use Win+D.

So if you have no luck with Win+D, try Win+M.

newbie83 wrote:
I know that in order to invoke any context menu I need to send SHIFT+F10.


Why not just use APPSKEY?

newbie83 wrote:
When you press F12 while a file is selected in Windows Explorer, the context menu invoked is not the Desktop's one.

Can you explain this? What is the solution?


You have to take the focus back from a specific item to the desktop in general:

Code:
ControlFocus, , Program Manager ; sets focus to the desktop's topmost control
Send {APPSKEY}
return

_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message Send e-mail
newbie83
Guest





PostPosted: Thu Oct 15, 2009 5:49 pm    Post subject: Reply with quote

sinkfaze wrote:
Why not just use APPSKEY?

Great idea. I didn't know about it. Thank you.

sinkfaze wrote:
You have to take the focus back from a specific item to the desktop in general:

Code:
ControlFocus, , Program Manager ; sets focus to the desktop's topmost control
Send {APPSKEY}
return

Hmmm... I tried this:
Code:
Hotkey, F12, WINACT
return


WINACT:
ControlFocus, , Program Manager
Send {APPSKEY}

Sleep 100
Sleep 100
Send {RButton}
Sleep 100
Send {Down 5}   ;  number of arrow down to select the menuitem

return

It works - but not when a file is selected in Windows Explorer. Try this. Do you see the problem? Smile
Back to top
sinkfaze



Joined: 18 Mar 2008
Posts: 5044
Location: the tunnel(?=light)

PostPosted: Thu Oct 15, 2009 6:19 pm    Post subject: Reply with quote

Try running only this:

Code:
SetControlDelay, -1
Hotkey, F12, WINACT
return


WINACT:
ControlFocus, , Program Manager
Send {APPSKEY}
return


I tested this on my machine (XP SP3) and it worked fine.
_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message Send e-mail
OceanMachine



Joined: 15 Oct 2007
Posts: 780
Location: England

PostPosted: Thu Oct 15, 2009 7:22 pm    Post subject: Reply with quote

Hmm, I see what the OP is saying - sinkfaze, try running your script, but before you press F12, click to just select an icon on your desktop.

When you press F12 now, the context menu appears as if the context is for the selected icon/file, rather than the 'desktop' itself.

I wonder if there is a way to tell the "Program Manager" window to de-select any icons (similar to how just left-clicking in a blank space on the desktop would do this) prior to sending APPSKEY?

I tried looking at how I might use PostMessage to do this, but then got completely lost on MSDN Smile

Alternatively, is there a way to just send a message to the desktop window to say 'display my context menu' or something like that? Not sure...
Back to top
View user's profile Send private message
sinkfaze



Joined: 18 Mar 2008
Posts: 5044
Location: the tunnel(?=light)

PostPosted: Thu Oct 15, 2009 9:03 pm    Post subject: Reply with quote

How weird, that was working fine just before I went to lunch and now it's very scattershot. Strange.

OceanMachine wrote:
I tried looking at how I might use PostMessage to do this, but then got completely lost on MSDN Smile

Alternatively, is there a way to just send a message to the desktop window to say 'display my context menu' or something like that? Not sure...


I'm betting that this thread holds the key but I can't figure out how to invoke the proper desktop context menu. For instance, the below code will invoke the true Desktop Properties but not the Display Properties one expects to invoke from the Desktop window:

Code:
sPath := "C:\Documents and Settings\sinkfaze\Desktop" ; path of the target file

SplitPath, sPath, sName, sDir
COM_Init()
psh := COM_CreateObject("Shell.Application")
COM_Invoke(psh, "NameSpace[" sDir "].ParseName[" sName "].InvokeVerb","Properties")
COM_Release(psh)
COM_Term()
return


I'm guessing the answer lies somewhere in this post but I lack the requisite knowledge of DllCalls to know what to make of it.
_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message Send e-mail
newbie83
Guest





PostPosted: Thu Oct 15, 2009 9:03 pm    Post subject: Reply with quote

sinkfaze wrote:
Try running only this:

Code:
SetControlDelay, -1
Hotkey, F12, WINACT
return


WINACT:
ControlFocus, , Program Manager
Send {APPSKEY}
return


I tested this on my machine (XP SP3) and it worked fine.

This doesn't work for me either (XP SP2 and XP SP3). Are you sure that you selected a file before pressing F12 when testing this?
Back to top
..:: Free Radical ::..



Joined: 20 Sep 2006
Posts: 72

PostPosted: Fri Oct 16, 2009 2:32 am    Post subject: Reply with quote

Code:
PostMessage, 0x111, 415, 0,, ahk_class Shell_TrayWnd ; WinMinimizeAll
PostMessage, 0x111, 407, 0,, ahk_class Shell_TrayWnd ; Shows the desktop
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Page 1 of 1

 
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