Repository: microsoft/terminal (language: cpp)

Issue:
The Explorer context menu should be run as admin when holding `ctrl`
<!-- 
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨

I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.

All good? Then proceed!
-->

# Description of the new feature/enhancement

<!-- 
A clear and concise description of what the problem is that the new feature would solve.
Describe why and how a user would use this new functionality (if applicable).
-->

When Windows Terminal (WT) is pinned to the taskbar or the start menu, and I need to run it quickly as administrator, I just have to press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>left click</kbd> over its icon, this way is faster than going to the WT icon in the taskbar (or the start menu icon), then right click, hover over "Terminal", then another right click and finally select "Run as administrator".

But this keyboard shortcut doesn't work for the WT item in the context menu of Windows Explorer. When I try the combination <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>left click</kbd>, it only opens a normal (not elevated) WT session.

Sometimes I need to run some script as admin contained in some folder, and for that I have to open WT as admin. As Ctrl+Shift+Left click doesn't work with "Open in Terminal" from the context menu of Windows Explorer, I have to use the longer path:
-Win+X (or the long path example I mentioned when WT is pinned to the taskbar)
-Click on Terminal (Admin)
-And when WT is open as admin I have to type `cd Folder_path_to_work_with `

# Proposed technical implementation details (optional)

<!-- 
A clear and concise description of what you want to happen.
-->

I would like that WT, in the context menu of Windows Explorer, can be executed as administrator just by using the shortcut <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>left click</kbd>, this way there would be no need to add another entry in the context menu such as `Open in Terminal as admin` to run WT as administrator.

This way, it would be faster to open WT as admin. When a user needs to open a folder with WT as admin, he just has to right click on the folder (or on an empty field inside the folder), then use the shortcut <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>left click</kbd> in "Open in Terminal" from the context menu to make WT open as admin, and when WT is open it is ready with the path of the folder to work with. 

But if it is not possible that Ctrl+Shift+left click to work for WT to open as admin, then it is necessary for WT to add another entry in the context menu so that it can be run as admin.

What do you think about it?




Discussion / hints:
At first I thought I'd just close this as a dupe of #9903, but you may have a point about the <kbd>ctrl</kbd>+clicking on the menu entry. That could probably be done _trivially_. 

It's kinda a hidden magic feature, but I'm not totally opposed to it. I wonder idly if the old Command Prompt / PowerShell shortcuts had that secretly baked in.

> **Note**
> ## Walkthrough

I'd look at `OpenTerminalHere::Invoke`, and in there, I'd check to see if <kbd>ctrl</kbd> is pressed when the entry is invoked. If it is, then I'd either start up `elevate-shim` in the same way that `TerminalPage::_maybeElevate` does, or I'd just skip a step and go straight to doing exactly what the body of `elevate-shim`'s `main` does. 
Hi. Thank you for your interest.

This is not a duplicate, but what the author of issue #9903 and I agree is that Windows Terminal can be easily run as admin. It would be very useful if WT could be run as admin by just using the shortcut I mentioned, which works very well when WT is pinned to the taskbar and/or the start menu. 

> I wonder idly if the old Command Prompt / PowerShell shortcuts had that secretly baked in.

Just to test, first I uninstalled WT, then I pinned the old Command Prompt to both as the taskbar as the start menu, then I used the keyboard shortcut <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>left click</kbd>, and surprise! Command Prompt also opens as admin.😀

I hope you can solve this issue. Because for me it would be very useful to be able to run WT as admin with just use a shortcut over its entry in the context menu.
I think Ctrl+Shift+Click is an OS feature. I use it with various apps. Would be nice to have similar behavior in Explorer menu. Ctrl alone would be easier.
Can non-elevated WT detect Ctrl and relaunch elevated?

Fix patch:
diff --git a/src/cascadia/ShellExtension/OpenTerminalHere.cpp b/src/cascadia/ShellExtension/OpenTerminalHere.cpp
index 4aee550e5c8..34360d9d7e1 100644
--- a/src/cascadia/ShellExtension/OpenTerminalHere.cpp
+++ b/src/cascadia/ShellExtension/OpenTerminalHere.cpp
@@ -27,6 +27,8 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
                                  IBindCtx* /*pBindContext*/)
 try
 {
+    const auto runElevated = IsControlPressed();
+
     wil::com_ptr_nothrow<IShellItem> psi;
     RETURN_IF_FAILED(GetBestLocationFromSelectionOrSite(psiItemArray, psi.put()));
     if (!psi)
@@ -42,10 +44,18 @@ try
         STARTUPINFOEX siEx{ 0 };
         siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
 
+        std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
         std::wstring cmdline;
-        RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
+        if (runElevated)
+        {
+            RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-(-d %s)-", QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
+        }
+        else
+        {
+            RETURN_IF_FAILED(wil::str_printf_nothrow(cmdline, LR"-("%s" -d %s)-", GetWtExePath().c_str(), QuoteAndEscapeCommandlineArg(pszName.get()).c_str()));
+        }
         RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
-            nullptr, // lpApplicationName
+            runElevated ? modulePath.replace_filename(ElevateShimExe).c_str() : nullptr, // if elevation requested pass the elevate-shim.exe as the application name
             cmdline.data(),
             nullptr, // lpProcessAttributes
             nullptr, // lpThreadAttributes
@@ -193,3 +203,15 @@ HRESULT OpenTerminalHere::GetBestLocationFromSelectionOrSite(IShellItemArray* ps
     RETURN_IF_FAILED(psi.copy_to(location));
     return S_OK;
 }
+
+// This method checks if any of the ctrl keys are pressed during activation of the shell extension
+bool OpenTerminalHere::IsControlPressed()
+{
+    const auto ControlPressed = 1U;
+
+    const auto control = GetKeyState(VK_CONTROL);
+    const auto leftControl = GetKeyState(VK_LCONTROL);
+    const auto rightControl = GetKeyState(VK_RCONTROL);
+
+    return WI_IsFlagSet(control, ControlPressed) || WI_IsFlagSet(leftControl, ControlPressed) || WI_IsFlagSet(rightControl, ControlPressed);
+}
diff --git a/src/cascadia/ShellExtension/OpenTerminalHere.h b/src/cascadia/ShellExtension/OpenTerminalHere.h
index bfcf660faee..f5b294942c8 100644
--- a/src/cascadia/ShellExtension/OpenTerminalHere.h
+++ b/src/cascadia/ShellExtension/OpenTerminalHere.h
@@ -58,6 +58,7 @@ struct
 private:
     HRESULT GetLocationFromSite(IShellItem** location) const noexcept;
     HRESULT GetBestLocationFromSelectionOrSite(IShellItemArray* psiArray, IShellItem** location) const noexcept;
+    bool IsControlPressed();
 
     wil::com_ptr_nothrow<IUnknown> site_;
 };
diff --git a/src/cascadia/WinRTUtils/inc/WtExeUtils.h b/src/cascadia/WinRTUtils/inc/WtExeUtils.h
index 0b0d40e23af..306af685e1f 100644
--- a/src/cascadia/WinRTUtils/inc/WtExeUtils.h
+++ b/src/cascadia/WinRTUtils/inc/WtExeUtils.h
@@ -2,6 +2,7 @@ constexpr std::wstring_view WtExe{ L"wt.exe" };
 constexpr std::wstring_view WtdExe{ L"wtd.exe" };
 constexpr std::wstring_view WindowsTerminalExe{ L"WindowsTerminal.exe" };
 constexpr std::wstring_view LocalAppDataAppsPath{ L"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\" };
+constexpr std::wstring_view ElevateShimExe{ L"elevate-shim.exe" };
 
 _TIL_INLINEPREFIX bool IsPackaged()
 {


Test patch: