[SHELL32][NTUSER] Implement the SEE_MASK_HOTKEY/ICON/HMONITOR flags (#7947)

This commit is contained in:
Whindmar Saksit 2025-05-03 16:08:58 +02:00 committed by GitHub
parent 102c1db735
commit 6829350af9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 114 additions and 22 deletions

View file

@ -2687,6 +2687,14 @@ HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici)
else if (pszDirA && SHAnsiToUnicode(pszDirA, dir, _countof(dir)))
sei.lpDirectory = dir;
}
sei.dwHotKey = lpici->dwHotKey;
sei.fMask |= CmicFlagsToSeeFlags(lpici->fMask & CMIC_MASK_HOTKEY);
if (m_Header.wHotKey)
{
sei.dwHotKey = m_Header.wHotKey;
sei.fMask |= SEE_MASK_HOTKEY;
}
return (ShellExecuteExW(&sei) ? S_OK : E_FAIL);
}

View file

@ -27,6 +27,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(exec);
EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath);
#ifndef STARTF_SHELLPRIVATE
#define STARTF_SHELLPRIVATE 0x400 // From kernel32.h
#endif
#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
@ -512,6 +515,27 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
if (psei->fMask & SEE_MASK_HASLINKNAME)
startup.dwFlags |= STARTF_TITLEISLINKNAME;
if (psei->fMask & SEE_MASK_HOTKEY)
{
startup.hStdInput = UlongToHandle(psei->dwHotKey);
startup.dwFlags |= STARTF_USEHOTKEY;
}
if (psei->fMask & SEE_MASK_ICON) // hIcon has higher precedence than hMonitor
{
startup.hStdOutput = psei->hIcon;
startup.dwFlags |= STARTF_SHELLPRIVATE;
}
else if ((psei->fMask & SEE_MASK_HMONITOR) || psei->hwnd)
{
if (psei->fMask & SEE_MASK_HMONITOR)
startup.hStdOutput = psei->hMonitor;
else if (psei->hwnd)
startup.hStdOutput = MonitorFromWindow(psei->hwnd, MONITOR_DEFAULTTONEAREST);
if (startup.hStdOutput)
startup.dwFlags |= STARTF_SHELLPRIVATE;
}
if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
lpDirectory, &startup, &info))
{
@ -1942,9 +1966,7 @@ static WCHAR *expand_environment( const WCHAR *str )
static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
{
static const DWORD unsupportedFlags =
SEE_MASK_ICON | SEE_MASK_HOTKEY |
SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
SEE_MASK_ASYNCOK | SEE_MASK_HMONITOR;
SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_ASYNCOK;
DWORD len;
UINT_PTR retval = SE_ERR_NOASSOC;

View file

@ -40,6 +40,8 @@ UINT gfsModOnlyCandidate;
/* FUNCTIONS *****************************************************************/
#define IsWindowHotKey(pHK) ( (pHK)->pti == NULL && (pHK)->id == IDHK_WNDKEY )
VOID FASTCALL
StartDebugHotKeys(VOID)
{
@ -82,6 +84,18 @@ IntGetModifiers(PBYTE pKeyState)
return fModifiers;
}
/*
* IntSwapModHKF
*
* Maps to/from MOD_/HOTKEYF_ (swaps the SHIFT and ALT bits)
*/
static inline
UCHAR
IntSwapModHKF(UINT Input)
{
return (Input & 2) | ((Input & 1) << 2) | ((Input >> 2) & 1);
}
/*
* UnregisterWindowHotKeys
*
@ -290,6 +304,17 @@ co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_TASKLIST, 0);
co_IntShellHookNotify(HSHELL_TASKMAN, 0, 0);
}
else if (IsWindowHotKey(pHotKey))
{
/* WM_SETHOTKEY notifies with WM_SYSCOMMAND, not WM_HOTKEY */
if (bIsDown)
{
if (gpqForeground && gpqForeground->spwndActive)
pWnd = gpqForeground->spwndActive;
UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND,
SC_HOTKEY, (LPARAM)UserHMGetHandle(pHotKey->pWnd));
}
}
else
{
TRACE("UPM Hot key Id %d Key %u\n", pHotKey->id, wVk );
@ -318,10 +343,10 @@ DefWndGetHotKey(PWND pWnd)
while (pHotKey)
{
if (pHotKey->pWnd == pWnd && pHotKey->id == IDHK_REACTOS)
if (pHotKey->pWnd == pWnd && IsWindowHotKey(pHotKey))
{
/* We have found it */
return MAKELONG(pHotKey->vk, pHotKey->fsModifiers);
return MAKEWORD(pHotKey->vk, IntSwapModHKF(pHotKey->fsModifiers));
}
/* Move to the next entry */
@ -339,7 +364,8 @@ DefWndGetHotKey(PWND pWnd)
INT FASTCALL
DefWndSetHotKey(PWND pWnd, WPARAM wParam)
{
UINT fsModifiers, vk;
const UINT fsModifiers = IntSwapModHKF(HIBYTE(wParam));
const UINT vk = LOBYTE(wParam);
PHOT_KEY pHotKey, *pLink;
INT iRet = 1;
@ -349,17 +375,12 @@ DefWndSetHotKey(PWND pWnd, WPARAM wParam)
if (pWnd->style & WS_CHILD)
return 0;
// VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
if (LOWORD(wParam) == VK_ESCAPE ||
LOWORD(wParam) == VK_SPACE ||
LOWORD(wParam) == VK_TAB)
// VK_ESCAPE, VK_SPACE, VK_TAB and VK_PACKET are invalid hot keys.
if (vk == VK_ESCAPE || vk == VK_SPACE || vk == VK_TAB || vk == VK_PACKET)
{
return -1;
}
vk = LOWORD(wParam);
fsModifiers = HIWORD(wParam);
if (wParam)
{
pHotKey = gphkFirst;
@ -367,7 +388,7 @@ DefWndSetHotKey(PWND pWnd, WPARAM wParam)
{
if (pHotKey->fsModifiers == fsModifiers &&
pHotKey->vk == vk &&
pHotKey->id == IDHK_REACTOS)
IsWindowHotKey(pHotKey))
{
if (pHotKey->pWnd != pWnd)
iRet = 2; // Another window already has the same hot key.
@ -383,8 +404,7 @@ DefWndSetHotKey(PWND pWnd, WPARAM wParam)
pLink = &gphkFirst;
while (pHotKey)
{
if (pHotKey->pWnd == pWnd &&
pHotKey->id == IDHK_REACTOS)
if (pHotKey->pWnd == pWnd && IsWindowHotKey(pHotKey))
{
/* This window has already hotkey registered */
break;
@ -405,14 +425,14 @@ DefWndSetHotKey(PWND pWnd, WPARAM wParam)
return 0;
pHotKey->pWnd = pWnd;
pHotKey->id = IDHK_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
pHotKey->id = IDHK_WNDKEY; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
pHotKey->pNext = gphkFirst;
gphkFirst = pHotKey;
}
/* A window can only have one hot key. If the window already has a
hot key associated with it, the new hot key replaces the old one. */
pHotKey->pti = NULL;
pHotKey->pti = NULL; /* IsWindowHotKey */
pHotKey->fsModifiers = fsModifiers;
pHotKey->vk = vk;
}

View file

@ -14,7 +14,7 @@ typedef struct _HOT_KEY
#define IDHK_F12 -5
#define IDHK_SHIFTF12 -6
#define IDHK_WINKEY -7
#define IDHK_REACTOS -8
#define IDHK_WNDKEY -8 /* WM_SETHOTKEY */
/* Window Snap Hot Keys */
#define IDHK_SNAP_LEFT -10

View file

@ -13,6 +13,13 @@
#include <debug.h>
#include <kdros.h>
#ifndef STARTF_USEHOTKEY
#define STARTF_USEHOTKEY 0x0200
#endif
#ifndef STARTF_SHELLPRIVATE
#define STARTF_SHELLPRIVATE 0x0400
#endif
HANDLE hModuleWin;
NTSTATUS ExitProcessCallback(PEPROCESS Process);
@ -462,6 +469,7 @@ InitThreadCallback(PETHREAD Thread)
PTEB pTeb;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
PKL pDefKL;
BOOLEAN bFirstThread;
Process = Thread->ThreadsProcess;
@ -486,6 +494,7 @@ InitThreadCallback(PETHREAD Thread)
pTeb->Win32ThreadInfo = ptiCurrent;
ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
ptiCurrent->pcti = &ptiCurrent->cti;
bFirstThread = !(ptiCurrent->ppi->W32PF_flags & W32PF_THREADCONNECTED);
/* Mark the process as having threads */
ptiCurrent->ppi->W32PF_flags |= W32PF_THREADCONNECTED;
@ -578,6 +587,25 @@ InitThreadCallback(PETHREAD Thread)
ptiCurrent->ppi->usi.wShowWindow = (WORD)ProcessParams->ShowWindowFlags;
}
}
if (bFirstThread)
{
/* Note: Only initialize once so it can be set back to 0 after being used */
if (ProcessParams->WindowFlags & STARTF_USEHOTKEY)
ptiCurrent->ppi->dwHotkey = HandleToUlong(ProcessParams->StandardInput);
/* TODO:
else if (ProcessParams->ShellInfo.Buffer)
..->dwHotkey = ParseShellInfo(ProcessParams->ShellInfo.Buffer, L"hotkey.");
*/
if (ProcessParams->WindowFlags & STARTF_SHELLPRIVATE)
{
/* We need to validate this handle because it can also be a HICON */
HMONITOR hMonitor = (HMONITOR)ProcessParams->StandardOutput;
if (hMonitor && UserGetMonitorObject(hMonitor))
ptiCurrent->ppi->hMonitor = hMonitor;
}
}
}
/*

View file

@ -1718,13 +1718,17 @@ IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
/* default positioning for overlapped windows */
if(!(Cs->style & (WS_POPUP | WS_CHILD)))
{
PMONITOR pMonitor;
PMONITOR pMonitor = NULL;
PRTL_USER_PROCESS_PARAMETERS ProcessParams;
PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
pMonitor = UserGetPrimaryMonitor();
if (ppi && ppi->hMonitor)
pMonitor = UserGetMonitorObject(ppi->hMonitor);
if (!pMonitor)
pMonitor = UserGetPrimaryMonitor();
/* Check if we don't have a monitor attached yet */
if(pMonitor == NULL)
if (pMonitor == NULL)
{
Cs->x = Cs->y = 0;
Cs->cx = 800;
@ -2575,6 +2579,16 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs,
co_IntUserManualGuiCheck(TRUE);
}
/* Set the hotkey */
if (!(Window->style & (WS_POPUP | WS_CHILD)) || (Window->ExStyle & WS_EX_APPWINDOW))
{
if (pti->ppi->dwHotkey)
{
co_IntSendMessage(UserHMGetHandle(Window), WM_SETHOTKEY, pti->ppi->dwHotkey, 0);
pti->ppi->dwHotkey = 0; /* Only the first suitable window gets the hotkey */
}
}
TRACE("co_UserCreateWindowEx(%wZ): Created window %p\n", ClassName, hWnd);
ret = Window;