我正在为CMD窗口(可能是任何shell)编写一个包装器,其目的是使shell实例始终在屏幕边框外打开。将鼠标移动到屏幕边框会导致窗口向下移动。 (窗口是最顶层的窗口)。 关键是终端始终可以作为进程访问(不占用任务栏中的空间),并且在不使用时隐藏它。
一个有用的功能是强制关注该窗口,这样,一旦它开始在屏幕上移动,您可以直接开始输入而不点击它以使其聚焦。
我正在使用sfml支持在visual studio中用c ++编写所有这些代码(该程序本身有许多sfml图形窗口,并且该提示是唯一的非图形窗口)。相对于该包装器的代码中的Sfml仅用于以sf::Mouse::getPosition().x/y
的形式获取鼠标坐标。
当我从visual studio中运行程序时,无论是在调试模式还是在发布模式下,它都可以正常工作。我可以关注其他一些窗口,在那里做东西,只要我将鼠标移动到使提示窗口在屏幕中移动的位置,如果我开始打字而不点击实际页面,提示将实际开始捕获键盘按预期输入。
但是,如果我将程序作为独立的可执行文件运行,则不再实现此行为。看来提示确实得到了焦点,因为“键入光标”就在那里,但是窗口没有捕获实际的键盘输入,这很奇怪。
相关代码如下:
//create terminal window beg
STARTUPINFO prompt_startupinfo;
PROCESS_INFORMATION prompt_processinfo;
HWND prompt_window;
Win::spawn_prompt(&prompt_startupinfo, &prompt_processinfo, &prompt_window);
//always on bottom
SetWindowPos(prompt_window, HWND_TOP, 0, -PROMPT_HEIGHT + 2, Screen::get_width(), PROMPT_HEIGHT, SWP_SHOWWINDOW);
SetWindowLong(prompt_window, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
SetWindowLong(prompt_window, GWL_STYLE, WS_POPUP | WS_VISIBLE);
//create terminal window end
bool outside = false;
bool exiting = false;
while (IsWindow(prompt_window))
{
//Console move beg
int my = sf::Mouse::getPosition().y;
int mx = sf::Mouse::getPosition().x;
RECT rect;
GetWindowRect(prompt_window, &rect);
int wy = rect.bottom;
if ((my <= wy + 1) and not exiting)
{
if ((not outside) or (mx < 32))
{
if (wy < PROMPT_HEIGHT)
{
wy += WINDOW_SPEED * 4;
outside = false;
if (wy > PROMPT_HEIGHT)
{
wy = PROMPT_HEIGHT;
}
}
SetForegroundWindow(prompt_window);
}
}
else if (wy > 0)
{
wy -= WINDOW_SPEED * 4;
exiting = true;
if (wy <= 0)
{
wy = 0;
outside = true;
exiting = false;
}
}
SetWindowPos(prompt_window, 0, 0, wy - PROMPT_HEIGHT, 0, 0, SWP_NOSIZE);
//Console move end
Sleep(1000 / 60);
}
快速说明一下,当从visual studio中运行时,通过SetForegroundWindow(prompt_window);
调用即可实现所需的行为,甚至不需要SetFocus(prompt_window);
为了完成起见,这里是Win :: spawn_prompt函数:
HWND Win::find_main_window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.best_handle = 0;
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.best_handle;
}
BOOL CALLBACK Win::enum_windows_callback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !is_main_window(handle))
{
return TRUE;
}
data.best_handle = handle;
return FALSE;
}
BOOL Win::is_main_window(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
bool Win::spawn_prompt(STARTUPINFO* prompt_startupinfo, PROCESS_INFORMATION* prompt_processinfo, HWND* prompt_window)
{
// additional information
STARTUPINFO si;
PROCESS_INFORMATION pi;
pi.hProcess;
// set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// start the program up
CreateProcess(L"C:\\Windows\\System32\\cmd.exe", // the path
L"", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
);
Sleep(1000);
HWND pw = Win::find_main_window(pi.dwProcessId);
*prompt_startupinfo = si;
*prompt_processinfo = pi;
*prompt_window = pw;
return false;
}
答案 0 :(得分:0)
好的,我解决了这个问题。 由于只有当用户的鼠标位于特定位置时才会触发“设置焦点”事件,因此我能想到的最直接的解决方法是模拟该位置的点击。 感谢@DanielSęk的提示, 我仍然感谢更清洁,更少解决方法,所以任何进一步的提示都将受到赞赏。
编辑: 尽管窗口是最顶层的,但有时当前聚焦的窗口仍然位于cmd窗口上方,如果该聚焦窗口位于我模拟点击的坐标处,它会捕获点击提示解决方案并不总是可靠。