Results 1 to 17 of 17

Thread: [resolved, critiques welcome, post #16] Setting default path for Win E

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Resolved [resolved, critiques welcome, post #16] Setting default path for Win E

    I asked a similar question earlier, and got bogged down. I've still got the same problem, but I'm wondering if there's another way to skin this cat.

    Here's the issue. In my application, there are several places where I allow the user to "pop out" to some folder. Basically, I just Shell to "Explorer" with the path on the command line.

    However, I'm trying to make this option somewhat more universal in my application. Previously, I asked if I could "capture" when the user hit Win E, but that didn't go anywhere, and I understand why. It would take a universal keyboard hook, which wouldn't be a good thing.

    However, I'm now wondering if I can just tell Windows what folder it should open up Explorer in when you do a Win E. If I could do that, I wouldn't need a universal hook. I could monitor GotGlobalFocus and LostGlobalFocus to set-and-unset this default on the forms on which I wanted to do this, and all would work fine.

    Any Ideas?
    Elroy

    EDIT1: Just as a bit more info, on my Win 10 computer, when I hit Win E, I get an Explorer that always starts in my Quick Access area. That's what I'd like to change under certain circumstances. I suppose I could figure out how to add something to the Quick Access list, but that's sloppy. I'd rather just open directly in the folder that I want when Win E is pressed.

    EDIT2: Just to be clear ...

    Name:  WinE.png
Views: 358
Size:  3.0 KB
    Last edited by Elroy; Dec 6th, 2017 at 08:48 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    PowerPoster jdc2000's Avatar
    Join Date
    Oct 2001
    Location
    Idaho Falls, Idaho USA
    Posts
    2,393

    Re: Setting default path for Win E


  3. #3

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Setting default path for Win E

    Hi jdc,

    I took a look at your link, and it came close, but no cigar. It did spur me to Google similar ideas, and now I've become somewhat convinced that I can't skin this cat with this approach either. It appears that the options are "Quick Access" or "This PC", with no other options allowed. In fact, I found a registry setting, but it's either a 1 or 2, for one of those options just mentioned. I saw no mechanism for actually putting in another path as the default place for Explorer to open. :/

    Thanks Though,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4
    PowerPoster jdc2000's Avatar
    Join Date
    Oct 2001
    Location
    Idaho Falls, Idaho USA
    Posts
    2,393

    Re: Setting default path for Win E

    It looks like you would have to re-map the Win+e hotkey to get it to work. AutoHotKey is one way, but you may not want to use that method.

  5. #5

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Setting default path for Win E

    Well, I don't really use AutoHotKey, but does it have the ability to remap the "Win" key? I'd be a bit surprised if it does.

    Also, yeah, I've got to keep this completely contained with VB6. But if AutoHotKey can do it, I'm sure that there's VB6 code that can also do it.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  6. #6
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,997

    Re: Setting default path for Win E

    Quote Originally Posted by Elroy View Post
    Well, I don't really use AutoHotKey, but does it have the ability to remap the "Win" key? I'd be a bit surprised if it does.

    Also, yeah, I've got to keep this completely contained with VB6. But if AutoHotKey can do it, I'm sure that there's VB6 code that can also do it.
    Sure you can do it, but you need to do the same. And my guess is that AutoHotKey is run when Windows starts and have the keyboard hooked.

    Some info.

  7. #7

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Setting default path for Win E

    Dang, I can't even hook that stupid Win key just for my own PID. And I really don't want to write some kind of "service" that does this. It's got to be very easy, as my program is entirely portable.

    I'm giving it up yet again.

    Y'all Take Care,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  8. #8
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [ABANDONED IDEA] Setting default path for Win E

    why would you need a service?

    AHK code should be on github, and last I checked it uses a low level keyboard hook, which can be setup by any running program.
    I do however challenge you to figure out how to keep a state machine that knows when to swallow up the relevant key presses.
    Last edited by DEXWERX; Dec 5th, 2017 at 08:01 AM.

  9. #9

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: [ABANDONED IDEA] Setting default path for Win E

    Hi Dex,

    Yesterday, I actually re-visited the idea of a low-level keyboard hook that was based on my PID. I could successfully hook the Win key. However, the moment I touched the "E" key (while holding down Win), I got nothing, and a copy of Explorer immediately popped up. No matter what I did, I couldn't figure out how to "catch" it.

    When I visited all this before, I remember LaVolpe looking into it, and finally deciding that Windows is just doing something funky with this Win key, and not giving all the info about it to the user. That's what let me to mention the idea of a "service", thinking that that could probably do it, but it's just not a way of doing it that I'm interested in.

    I've tried several things, but here's what I tried that seemed to have the best hope of succeeding:

    For BAS module:

    Code:
    
    Option Explicit
    '
    Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    '
    Public Const WH_KEYBOARD = 2
    '
    Public hHook As Long
    '
    
    Public Function KeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        Debug.Print nCode, wParam, lParam
        KeyboardProc = CallNextHookEx(hHook, nCode, wParam, lParam)
    End Function
    
    
    For a Form1 test:

    Code:
    
    Option Explicit
    '
    
    Private Sub Form_Load()
       hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, 0&, App.ThreadID)
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
       Call UnhookWindowsHookEx(hHook)
    End Sub
    
    
    Take Care,
    Elroy
    Last edited by Elroy; Dec 5th, 2017 at 09:17 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  10. #10
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: [ABANDONED IDEA] Setting default path for Win E

    I suspect that these things are processed as shortcut hot keys, and that processing occurs before any "normal" keystroke processing via window message queues occurs. Otherwise they wouldn't work (for example) while a console window has focus.

    What makes me think this is that subclassing and trying to just "eat" the LWIN and RWIN keys isn't effective. You get the keys but the normal action has already occurred as well. If you try to subclass the Shell window you never get them at all but the action still occurs.

    Also see: Windows Confidential: The Third Rail of Keyboard Shortcuts. This isn't what you might think, but the last part is interesting:

    Here’s a deployment tip: You can create a shortcut that opens an Explorer window on a folder of your choosing by simply creating a shortcut to that folder. You can give the shortcut a name of your choosing and deploy it to your users. If you’re really sneaky, you can even call that shortcut Windows Explorer.
    I suspect the hidden implication is that you could globally change what folder Explorer opens to when Win+E is pressed by users.

  11. #11
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [ABANDONED IDEA] Setting default path for Win E

    To set a low level hook try this instead.
    Code:
        m_Hook = SetWindowsHookEx(WH_KEYBOARD_LL, _
                                  AddressOf LowLevelKeyboardProc, _
                                  App.hInstance, _
                                  0)
    Also you need to track the state of the windows key yourself if you are going to suppress it.

    as a reference --> https://github.com/AutoHotkey/AutoHo...ource/hook.cpp

  12. #12
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [ABANDONED IDEA] Setting default path for Win E

    notice line 622

    https://github.com/AutoHotkey/AutoHo.../hook.cpp#L622

    lots of info in there.
    notice they mention messing with the shift state to get around windows taking over the LWIN/RWIN

    also they re-inject the key presses afterward in the case where you actually don't want hijack the sequence, which you then have to worry about re-entrancy.
    Last edited by DEXWERX; Dec 5th, 2017 at 02:11 PM.

  13. #13

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: [MAYBE NOT ABANDONED] Setting default path for Win E

    Hi Dex,

    I think you might actually give me enough tips to get this thing going. The WH_KEYBOARD_LL is doing much better. I've "pretty much" got it all up and running.

    Just one small glitch.

    I'm not sure how to tell Windows that the WIN key is no longer depressed. I'd hate to suppress the WIN keys entirely in my application. I'd like to just suppress (and use) only WIN-E.

    Here's where I am with the code:

    BAS module:

    Code:
    
    Option Explicit
    '
    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
    '
    Public Const WH_KEYBOARD_LL = 13
    '
    Public Type KBDLLHOOKSTRUCT
        vkCode As Long
        scanCode As Long
        flags As Long
        Time As Long
        dwExtraInfo As Long
    End Type
    '
    Private hHook As Long
    '
    
    Public Sub SetKeyboardHook()
        hHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0&)
    End Sub
    
    Public Sub RemoveKeyboardHook()
        UnhookWindowsHookEx hHook
    End Sub
    
    Public Function LowLevelKeyboardProc(ByVal uCode As Long, ByVal wParam As Long, lParam As KBDLLHOOKSTRUCT) As Long
        Const VK_E          As Long = &H45&
        Const VK_LWIN       As Long = &H5B&
        Const VK_RWIN       As Long = &H5C&
        Const HC_ACTION     As Long = &H0&
        Const WM_KEYDOWN    As Long = &H100&
        Const WM_KEYUP      As Long = &H101&
        '
        Static bLWinDown As Boolean
        Static bRWinDown As Boolean
        Static bSuppressNextWinUp As Boolean
        '
        If uCode = HC_ACTION Then
            Select Case True
            Case lParam.vkCode = VK_LWIN
                Select Case wParam
                Case WM_KEYDOWN
                    bLWinDown = True
                Case WM_KEYUP
                    bLWinDown = False
                    If bSuppressNextWinUp Then
                        ' If we just suppressed an "E", we must also suppress the Win_Up, or Windows will click the Start button.
                        bSuppressNextWinUp = False
                        LowLevelKeyboardProc = 1
                        Exit Function
                    End If
                End Select
            Case lParam.vkCode = VK_RWIN
                Select Case wParam
                Case WM_KEYDOWN
                    bRWinDown = True
                Case WM_KEYUP
                    bRWinDown = False
                    If bSuppressNextWinUp Then
                        ' If we just suppressed an "E", we must also suppress the Win_Up, or Windows will click the Start button.
                        bSuppressNextWinUp = False
                        LowLevelKeyboardProc = 1
                        Exit Function
                    End If
                End Select
            Case lParam.vkCode = VK_E And (bLWinDown Or bRWinDown)
                If wParam = WM_KEYDOWN Then
                    ' Found a Win-E, so do our thing.  We're doing it on WM_KEYDOWN so we don't have to worry about releasing WIN key first.
    
    
    
    
                    Debug.Print "Detected Win-E, do what we want."
    
    
    
    
    
                End If
                ' Suppress the "E" so Windows doesn't open Explorer.
                bSuppressNextWinUp = True
                LowLevelKeyboardProc = 1
                Exit Function
            End Select
        End If
        '
        ' We fell through so pass things along.
        LowLevelKeyboardProc = CallNextHookEx(hHook, uCode, wParam, lParam)
    End Function
    
    Form1 code for testing:

    Code:
    
    Option Explicit
    '
    
    Private Sub Form_Load()
        SetKeyboardHook
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        RemoveKeyboardHook
    End Sub
    
    The problem is, that, after I capture a WIN-E, Windows thinks the WIN key is still down. For instance, I just press the "W" key and get all kinds of "Windows Ink Workspace" stuff. I have to tap the WIN key again to reset things, but then this clicks the Start button.

    I tried flushing the keyboard buffer with calls to PeekMessage and PM_REMOVE, but that didn't work.

    Any ideas?

    Thanks,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  14. #14
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [MAYBE NOT ABANDONED] Setting default path for Win E

    yeah that was the "challenge" I was talking about.

    are you suppressing the WIN key? I thought the comments in AHK talk about toggling a SHIFT state to suppress it, but I' not completely sure. (though it seems clever enough)

    Also once you're sure you've either got your WIN+E, or it's another WIN key sequence, you probably need to re-inject the WIN keypress. I think that's how AHK does it. A lot of time went into AHK figuring this all out.
    Last edited by DEXWERX; Dec 5th, 2017 at 02:55 PM.

  15. #15

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: [MAYBE NOT ABANDONED] Setting default path for Win E

    Quote Originally Posted by DEXWERX View Post
    re-inject the WIN keypress
    Yes, I could "monitor" enough things for that to work (re-injecting the Win_Key_Down if it's not an "E" that's subsequently pressed). How would you go about doing that? keybd_event? SendInput?

    It seems that the keybd_event structure is almost exactly the same as the KBDLLHOOKSTRUCT, so that seems like a pretty good way to do it.

    I'm tied up with some other stuff at the moment, but I'll probably try that later today.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  16. #16

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: [resolved, critiques welcome] Setting default path for Win E

    Alrighty, Dex spurred me on enough to get something together that seems to be working.

    Here's the code I have in a BAS module:

    Code:
    
    Option Explicit
    '
    Private Declare Function GetForegroundWindow Lib "user32" () As Long    ' Retrieves a handle to the foreground window (the window with which the user is currently working).
    Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
    Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
    '
    Public Const WH_KEYBOARD_LL As Long = 13&
    '
    Public Type KBDLLHOOKSTRUCT
        vkCode As Long
        scanCode As Long
        flags As Long
        Time As Long
        dwExtraInfo As Long
    End Type
    '
    Dim mhHook As Long
    '
    
    Public Sub SetWinE_Hook()
        ' Don't call this more than once for any one entire VBP project, or we'll have problems.
        mhHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0&)
        SaveSetting App.Title, "Settings", "WinE_Hook", mhHook
    End Sub
    
    Public Sub RemoveWinE_Hook()
        UnhookWindowsHookEx GetSetting(App.Title, "Settings", "WinE_Hook", 0&)
    End Sub
    
    Public Function LowLevelKeyboardProc(ByVal uCode As Long, ByVal wParam As Long, lParam As KBDLLHOOKSTRUCT) As Long
        Const VK_E          As Long = &H45&
        Const VK_LWIN       As Long = &H5B&
        Const VK_RWIN       As Long = &H5C&
        Const HC_ACTION     As Long = &H0&
        Const WM_KEYDOWN    As Long = &H100&
        Const WM_KEYUP      As Long = &H101&
        '
        Static bLWinDown As Boolean
        Static bRWinDown As Boolean
        Static bSuppressNextWinUp As Boolean
        Static bIgnoreNextWinDown As Boolean
        '
        Static kbWinKeyStruct As KBDLLHOOKSTRUCT
        '
        ' A bit of IDE protection.
        If Forms.Count = 0 Then
            UnhookWindowsHookEx GetSetting(App.Title, "Settings", "WinE_Hook", 0&)
            LowLevelKeyboardProc = CallNextHookEx(GetSetting(App.Title, "Settings", "WinE_Hook", 0&), uCode, wParam, lParam)
            Exit Function
        End If
        '
        ' Let's make sure we're the one with the focus.
        If App.ThreadID = GetWindowThreadProcessId(GetForegroundWindow, ByVal 0&) Then
            If uCode = HC_ACTION Then
                Select Case True
                Case (lParam.vkCode = VK_LWIN) Or (lParam.vkCode = VK_RWIN)
                    ' Something with a WIN key is happening.
                    Select Case wParam
                    Case WM_KEYDOWN
                        If bIgnoreNextWinDown Then
                            bIgnoreNextWinDown = False
                        Else
                            If lParam.vkCode = VK_LWIN Then bLWinDown = True Else bRWinDown = True
                            kbWinKeyStruct = lParam
                            LowLevelKeyboardProc = 1    ' We suppress for now, and maybe re-inject later.
                            Exit Function
                        End If
                    Case WM_KEYUP
                        If lParam.vkCode = VK_LWIN Then bLWinDown = False Else bRWinDown = False
                        If bSuppressNextWinUp Then
                            ' If we just suppressed an "E", we must also suppress the Win_Up, or Windows will click the Start button.
                            bSuppressNextWinUp = False
                            LowLevelKeyboardProc = 1
                            Exit Function
                        End If
                    End Select
                Case lParam.vkCode = VK_E And (bLWinDown Or bRWinDown)
                    ' Something with E key is happening, and a WIN key is down.
                    If wParam = WM_KEYDOWN Then
                        ' Found a Win-E, so do our thing.  We're doing it on WM_KEYDOWN so we don't have to worry about releasing WIN key first.
    
    
    
    
                        Debug.Print "Detected Win-E, do what we want."
    
    
    
    
    
                    End If
                    ' Suppress the "E" so Windows doesn't open Explorer.
                    bSuppressNextWinUp = True
                    LowLevelKeyboardProc = 1
                    Exit Function
                Case bLWinDown Or bRWinDown
                    ' Something is happening with some other key (while WIN key is down), so it must NOT be a Win-E happening.
                    bIgnoreNextWinDown = True
                    '
                    ' We must re-inject both, and then ignore this one to get the key order correct.
                    keybd_event CByte(kbWinKeyStruct.vkCode), CByte(kbWinKeyStruct.scanCode), kbWinKeyStruct.flags, kbWinKeyStruct.dwExtraInfo
                    keybd_event CByte(lParam.vkCode), CByte(lParam.scanCode), lParam.flags, lParam.dwExtraInfo
                    LowLevelKeyboardProc = 1
                    Exit Function
                End Select
            End If
        End If
        '
        ' We fell through so pass things along.
        LowLevelKeyboardProc = CallNextHookEx(mhHook, uCode, wParam, lParam)
    End Function
    
    And here's a bit of test code for a Form1:

    Code:
    
    Option Explicit
    '
    
    Private Sub Form_Load()
        SetWinE_Hook
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        RemoveWinE_Hook
    End Sub
    

    Now, I did a couple of things that may look a bit strange. For one, I made a bit of use of the registry. That was an easy way to store some persistent data between run-time and design-time, and it allows me to unhook after the user presses the IDE's stop button. As far as I can tell, it's completely IDE safe (other than hitting the IDE's stop and immediately editing the hook's procedure).

    I also just checked Forms.Count to determine run-time vs design-time. This certainly works for me, and I don't know of another way to check this without a user-control, which seemed like overkill.

    I also made sure that we were in our own thread, or I didn't do anything. This made perfect sense to me, as I'm not trying to do any global hotkey type thing.

    Critiques welcome.

    Best Regards,
    Elroy
    Last edited by Elroy; Dec 6th, 2017 at 09:03 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  17. #17
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: [MAYBE NOT ABANDONED] Setting default path for Win E

    Nice. You've addressed any issues I perceived, even with the bIgnoreNextWinDown.

    edit: you should post it in the code bank. It's a good example of using a low level hook, to override the WIN Key.
    And you've worked out the pitfalls other VBers would miss, trying to get something like this going.
    Last edited by DEXWERX; Dec 6th, 2017 at 07:58 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width