How to get the ShortcutKey of a shortcut

Get help with using AutoHotkey and its commands and hotkeys
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

How to get the ShortcutKey of a shortcut

02 Dec 2019, 17:11

Hi Folks,
The FileCreateShortcut command includes an option to specify a ShortcutKey. However, the FileGetShortcut command does not retrieve that as one of the output variables. Is there some other way to determine what the ShortcutKey is? My goal is to save and restore all aspects of a shortcut, but the inability to get the ShortcutKey via FileGetShortcut makes that impossible to do via FileCreateShortcut, as far as I can tell. Thanks much, Joe
teadrinker
Posts: 1870
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 18:41

Hi
Try this:

Code: Select all

lnk := A_Desktop . "\FreeMind.lnk"

S_OK := 0, STGM_READ := 0
CLSID_ShellLink  := "{00021401-0000-0000-C000-000000000046}"
IID_IShellLinkA  := "{000214EE-0000-0000-C000-000000000046}"
IID_IShellLinkW  := "{000214F9-0000-0000-C000-000000000046}"
IID_IPersistFile := "{0000010B-0000-0000-C000-000000000046}"
IID_IShellLink := A_IsUnicode ? IID_IShellLinkW : IID_IShellLinkA

HOTKEYF_SHIFT   := 0x1
HOTKEYF_CONTROL := 0x2
HOTKEYF_ALT     := 0x4
HOTKEYF_EXT     := 0x8

IShellLink := ComObjCreate(CLSID_ShellLink, IID_IShellLink)
GetHotkey := 12
IPersistFile := ComObjQuery(IShellLink, IID_IPersistFile)
Load      := 5

XFmt := Func("Format").Bind("{:#x}")

Loop 1 {
   hr := Vtable(IPersistFile, Load).Call("Ptr", &lnk, "UInt", STGM_READ, "UInt")
   if (hr != S_OK && error := "IPersistFile::Load failed, error: " . XFmt.Call(hr))
      break
   
   hr := Vtable(IShellLink, GetHotkey).Call("UShortP", buff, "UInt")
   (hr != S_OK && error := "IShellLink::GetHotkey failed, error: " . XFmt.Call(hr))
}
ObjRelease(IPersistFile)
ObjRelease(IShellLink)
if error
   throw Exception(error)

key := GetKeyName("vk" . Format("{:X}", buff & 0xFF))
mod := buff >> 8
Shift := mod & HOTKEYF_SHIFT   ? "Shift + " : ""
Ctrl :=  mod & HOTKEYF_CONTROL ? "Ctrl + "  : ""
Alt :=   mod & HOTKEYF_ALT     ? "Alt + "   : ""
Ext :=   mod & HOTKEYF_EXT     ? "Numpad"   : "" ; not sure

MsgBox, % Shift . Ctrl . Alt . Ext . key

Vtable(ptr, n) {
   return Func("DllCall").Bind(NumGet(NumGet(ptr+0), A_PtrSize*n), "Ptr", ptr)
}
I'm not sure about HOTKEYF_EXT.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:16

For reference, I wrote something similar here:
Get shortcut target without evaluating environment variables - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=66420
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:34

Hi teadrinker,
Superb! Works perfectly! :thumbup: HOTKEYF_EXT (NumPad) works fine, too. Tested on both W7 and W10. Thanks very much! My only problem now is that FileCreateShortcut creates all shortcut keys as Ctrl+Alt shortcuts. :( Cheers, Joe
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:37

Hi jeeswg,
Thanks for the link...I'll have a look at it. Regards, Joe
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:38

My link includes an alternative version of FileCreateShortcut. :)
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:52

jeeswg wrote:an alternative version of FileCreateShortcut
Does it support other than Ctrl+Alt shortcuts?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 20:59

That was the main reason I wrote the function, to handle shortcut keys generally.
Although the functions may not handle HOTKEYF_EXT (NumPad) correctly. So you might want to tweak them.

That said, if you just wanted to store shortcut information, then restore it, you could create modified versions of the functions, that get/set the raw shortcut key number, obtained via IShellLink::GetHotkey/IShellLink::SetHotkey, but that do not convert them to a friendly string.
Last edited by jeeswg on 02 Dec 2019, 21:21, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 21:18

jeeswg wrote:if you just wanted to store shortcut information, then restore it
Yes, that's my entire purpose for this! I want to be able to delete a shortcut from the desktop, then restore it at a later time, fully intact.
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

02 Dec 2019, 23:57

Hi jeeswg,
One of your comments at the thread you posted says that you updated JEE_FileGetShortcut and JEE_FileCreateShortcut. I'd like to be sure that I have the latest versions of them...please post links to both. Thanks, Joe
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 00:24

The most up-to-date version of each function, would be the lowest-down appearance of the function definition on that page. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 03:12

Hi jeeswg,

I think I got the latest ones...JEE_FileCreateShortcut is here:
https://www.autohotkey.com/boards/viewtopic.php?f=5&t=66420#p287004

But I cannot get it to create the shortcut key...can you?

Running on W7/64-bit with v1.1.32.00/U64, if that matters. The test script that I'm using is below. It creates the shortcut with everything set properly...except for the shortcut key...that displays in the shortcut's Properties as None. Regards, Joe

Code: Select all

vTarget:="c:\temp\test jeeswg.txt"
vPathLink:=A_Desktop . "\test jeeswg link " . A_Now . ".lnk"
vWorkingDir:=A_ScriptDir
vArgs:="a b c"
vDescription:="shortcut description"
vIconFile:=A_AhkPath
vShortcutKey:="^!+q"
vIconNum:=4
vRunState:=1
JEE_FileCreateShortcut(vTarget,vPathLink,vWorkingDir,vArgs,vDescription,vIconFile,vShortcutKey,vIconNum,vRunState)
MsgBox,4096,Create Done,%vPathLink%
ExitApp

JEE_FileCreateShortcut(vTarget, vPathLink, vWorkingDir:="", vArgs:="", vDescription:="", vIconFile:="", vShortcutKey:="", vIconNum:=0, vRunState:="")
{
  local
  static IID_IShellLinkW := "{000214F9-0000-0000-C000-000000000046}"
  static CLSID_ShellLink := "{00021401-0000-0000-C000-000000000046}"
  static IID_IPersistFile := "{0000010b-0000-0000-C000-000000000046}"
  if !(pSL := ComObjCreate(CLSID_ShellLink, IID_IShellLinkW))
    return 0

  ;set Target
  ;SLGP_RAWPATH := 0x4 ;SLGP_UNCPRIORITY := 0x2 ;SLGP_SHORTPATH := 0x1 ;source: ShObjIdl.h
  if DllCall(NumGet(NumGet(pSL+0) + 20*A_PtrSize), "Ptr",pSL, "WStr",vTarget) ;IShellLink::SetPath
    return 0

  ;set WorkingDir
  if !(vWorkingDir = "")
  && DllCall(NumGet(NumGet(pSL+0) + 9*A_PtrSize), "Ptr",pSL, "WStr",vWorkingDir) ;IShellLink::SetWorkingDirectory
    return 0

  ;set Args
  if !(vArgs = "")
  && DllCall(NumGet(NumGet(pSL+0) + 11*A_PtrSize), "Ptr",pSL, "WStr",vArgs) ;IShellLink::SetArguments
    return 0

  ;set Description
  if !(vDescription = "")
  && DllCall(NumGet(NumGet(pSL+0) + 7*A_PtrSize), "Ptr",pSL, "WStr",vDescription) ;IShellLink::SetDescription
    return 0

  ;set IconFile and IconNum
  if !(vIconFile = "")
  && DllCall(NumGet(NumGet(pSL+0) + 17*A_PtrSize), "Ptr",pSL, "WStr",vIconFile, "Int",vIconNum) ;IShellLink::SetIconLocation
    return 0

  if !(vShortcutKey = "")
  {
    vHotkeyNum := 0
    if RegExMatch(vShortcutKey, "^.?\+.")
    {
      vHotkeyNum |= (0x1 << 8) ;HOTKEYF_SHIFT := 0x1
      vShortcutKey := StrReplace(vShortcutKey, "+", "",, 1)
    }
    if RegExMatch(vShortcutKey, "^.?\^.")
    {
      vHotkeyNum |= (0x2 << 8) ;HOTKEYF_CONTROL := 0x2
      vShortcutKey := StrReplace(vShortcutKey, "^", "",, 1)
    }
    if RegExMatch(vShortcutKey, "^.?!.")
    {
      vHotkeyNum |= (0x4 << 8) ;HOTKEYF_ALT := 0x4
      vShortcutKey := StrReplace(vShortcutKey, "!", "",, 1)
    }
    if vVK := GetKeyVK(vShortcutKey)
      vHotkeyNum |= vVK
    if vVK
    && DllCall(NumGet(NumGet(pSL+0) + 13*A_PtrSize), "Ptr",pSL, "UShort",vHotkeyNum) ;IShellLink::SetHotkey
      return 0
  }

  if !(vRunState = "")
  && DllCall(NumGet(NumGet(pSL+0) + 15*A_PtrSize), "Ptr",pSL, "Int",vRunState) ;IShellLink::SetShowCmd
    return 0

  if !(pPF := ComObjQuery(pSL, IID_IPersistFile))
    return 0
  vSize := DllCall("kernel32\GetFullPathNameW", "WStr","\\?\" vPathLink, "UInt",0, "Ptr",0, "Ptr*",0, "UInt")
  VarSetCapacity(vPath2, vSize*2, 0)
  if !DllCall("kernel32\GetFullPathNameW", "WStr","\\?\" vPathLink, "UInt",vSize, "Ptr",&vPath2, "Ptr*",0, "UInt")
    return 0
  if DllCall(NumGet(NumGet(pPF+0) + 6*A_PtrSize), "Ptr",pPF, "Ptr",&vPath2, "Int",1) ;IPersistFile::Save
    return 0

  ObjRelease(pPF)
  ObjRelease(pSL)
  return 1
}
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 03:27

Try vShortcutKey:="+^!q".
There's a slight issue with the RegEx, I'll post again when I've replaced it with something slightly more intuitive.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 03:50

vShortcutKey:="+^!q"
That works!
I'll post again when I've replaced it with something slightly more intuitive.
Looking forward to it, but it's almost 3:00am in my neck of the woods, so this is my last post for the night. Will check back into the thread first thing in my morning. Regards, Joe
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 04:35

OK. Done.

I'm thinking we need a built-in HotkeySplit function.
So +^!a would split to +^! and a.

Code: Select all

;q:: ;test split hotkeys
vList := " ;continuation section
(
!+^q
!^+q
+!^q
+^!q
^!+q
^+!q
!+q
!^q
+!q
+^q
^!q
^+q
!q
+q
^q
q
)"

vList2 := vList
vList2 .= "`n" StrReplace(vList, "q", "Left")
vList2 .= "`n" StrReplace(vList, "q", "")
vList2 .= "`n" StrReplace(vList, "q", "+")
vList2 .= "`n" StrReplace(vList, "q", "^")
vList2 .= "`n" StrReplace(vList, "q", "!")

vIsV1 := RegExMatch("", "", o) && !IsObject(o)
vPfx := vIsV1 ? "O)" : ""
vOutput := ""
Loop Parse, vList2, % "`n", % "`r"
{
	vHotkey := A_LoopField
	RegExMatch(vHotkey, vPfx "^([+^!]{0,3})(.+)$", oMatch)
	vOutput .= vHotkey "`t" oMatch.1 "`t" oMatch.2 "`r`n"
}
Clipboard := vOutput
MsgBox, % "done"
return

That might seem like a relatively minor function to have.
However, the way AHK parses hotkeys is pretty complex, and only if it were built-in, would it be really reliable.
And extra modifiers like $ would have to be handled also.
So I think it's just about worth implementing, and hopefully should be relatively trivial since AutoHotkey already contains the logic to do this.

Similarly, it would be useful to have an IsHotkey or IsValidHotkey function.
One use would be in parsing AHK scripts.
does string look like a hotkey - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=58131

Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
JoeWinograd
Posts: 1608
Joined: 10 Feb 2014, 20:00

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 15:08

Hi jeeswg,

Thanks for the updates. Just tested both on W7...worked perfectly! Btw, you should change a comment there...both sentences before the links say, "Get shortcut target..." You should change the second one to say, "Create shortcut target..."

Interesting idea on the HotkeySplit and IsValidHotkey functions...post them on the Wish List.

Thanks again to both teadrinker and you...great stuff! Regards, Joe
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: How to get the ShortcutKey of a shortcut

03 Dec 2019, 15:18

In the post, I'd written the thread title (which starts with 'Get shortcut target') before each of the 2 urls, I've now removed the thread titles, leaving just the urls. Good suggestion. Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask For Help”

Who is online

Users browsing this forum: Adamyounguk, boiler, bxgchoi, hasantr, mikeyww, Xsawers and 52 guests