模拟全局热键
Posted
技术标签:
【中文标题】模拟全局热键【英文标题】:Simulate global hotkey 【发布时间】:2016-02-28 14:32:39 【问题描述】:您好,我正在使用 Visual c++ 我有一个工作程序,除了一件事我希望它能够使用单独的屏幕截图程序。我安装了单独的截图程序,它有一个注册的热键来截图,我希望我的程序来做。
我用 FindWindow 尝试了 keybd_event 和 SendInput,它在记事本上运行良好,但它的屏幕截图程序运行最小化或隐藏,我知道 SetForegroundWindow 的问题。
有没有办法让它像我刚刚在键盘上按下的所有窗口一样的 Windows 系统,就像真正的热键一样?它的屏幕截图程序可以使用真正的热键正常工作。
【问题讨论】:
【参考方案1】:也许键盘挂钩可以解决问题?
example 1 example 2 example 3并不完美,但它们非常全球化
【讨论】:
好的,我可以了解钩子,但这可以按下按键还是只听?是其他程序有热键,我想我的程序按下它。 看来我明白了。您想模拟击键,以便外部程序截取屏幕截图,对吗?好吧,那不是您遇到问题的热键。顺便说一句,请考虑以下几点: * 从您自己的代码中获取截图非常容易 * 您可以将自己的热键与对上述程序的某种管道调用结合起来 但是无论如何,您现在想要的解决方案是 SendInput() .是的,您已经尝试过了,但如果实施得当,应该可以工作。【参考方案2】:这是一个全局热键的源代码。它已设置为侦听 CTRL + y 组合键。一旦 CTRL + y 被触发,它就会抓取屏幕截图。
要关闭全局热键,只需按 CTRL + q。
要隐藏控制台窗口并保持热键在后台运行,请按 CTRL + w。
#define _WIN32_WINNT 0x0400
#pragma comment( lib, "user32.lib" )
#include <iostream>
#include <windows.h>
#include <stdio.h>
HHOOK hKeyboardHook;
__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam);
void MessageLoop();
DWORD WINAPI my_HotKey(LPVOID lpParm);
int toggleVisibility = 1;
int screenResolutionX = GetSystemMetrics(SM_CXSCREEN);
int screenResolutionY = GetSystemMetrics(SM_CYSCREEN);
POINT startCoord,endCoord;
void grabScreenshot(POINT a, POINT b);
/*********************************************
*** ***
*** ***
**********************************************/
int main(int argc, char** argv)
/* uncomment to hide console window */
//ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
HANDLE hThread;
DWORD dwThread;
printf("\n s c r e e n s h o t H O T K E Y \n\n");
printf("press CTRL-y for screenshot \n");
printf("press CTRL-w to hide or make console window visible \n");
printf("press CTRL-q to quit \n");
printf("\n\n");
hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE) my_HotKey, (LPVOID) argv[0], NULL, &dwThread);
if (hThread) return WaitForSingleObject(hThread,INFINITE);
else return 1;
/*********************************************
*** ***
*** ***
**********************************************/
__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
DWORD SHIFT_key=0;
DWORD CTRL_key=0;
DWORD ALT_key=0;
if ( (nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN) ) )
KBDLLHOOKSTRUCT hooked_key = *((KBDLLHOOKSTRUCT*)lParam);
DWORD dwMsg = 1;
dwMsg += hooked_key.scanCode << 16;
dwMsg += hooked_key.flags << 24;
char lpszKeyName[1024] = 0;
int i = GetKeyNameText(dwMsg, (lpszKeyName+1),0xFF) + 1;
int key = hooked_key.vkCode;
SHIFT_key = GetAsyncKeyState(VK_SHIFT);
CTRL_key = GetAsyncKeyState(VK_CONTROL);
ALT_key = GetAsyncKeyState(VK_MENU);
//printf("%c",key);
if ( (key >= 'A') && (key <= 'Z') || (key >= 'a') && (key <= 'z') || (key >= '0') && (key <= '9') )
if (GetAsyncKeyState(VK_SHIFT)>= 0) key +=32;
/*********************************************
*** Hotkey scope ***
*** do stuff here ***
**********************************************/
if ( (CTRL_key !=0) && (key == 'y') || (key == 'Y') )
CTRL_key=0;
// grab a screenshot
startCoord.x=0;
startCoord.y=0;
endCoord.x=screenResolutionX;
endCoord.y=screenResolutionY;
ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
Sleep(1000);
grabScreenshot(startCoord,endCoord);
ShowWindow(FindWindowA("ConsoleWindowClass", NULL), true);
printf("\nThe Screenshot is in the Clipboard \n\n");
//******************************************************
if ( (CTRL_key !=0) && (key == 'q') || (key == 'Q') )
MessageBox(NULL, "\n\n\n\nShutting down\n\nPress OK to close\n\n", " H O T K E Y ", MB_OK);
PostQuitMessage(0);
//******************************************************
if ( (CTRL_key !=0) && (key == 'w') || (key == 'W') )
toggleVisibility = - toggleVisibility;
if (toggleVisibility >0 )
ShowWindow(FindWindowA("ConsoleWindowClass", NULL), true);
else
ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
SHIFT_key = 0;CTRL_key = 0; ALT_key = 0;
return CallNextHookEx(hKeyboardHook, nCode,wParam,lParam);
/*********************************************
*** ***
*** ***
**********************************************/
void MessageLoop()
MSG message;
while (GetMessage(&message,NULL,0,0))
TranslateMessage( &message );
DispatchMessage( &message );
/*********************************************
*** ***
*** ***
**********************************************/
DWORD WINAPI my_HotKey(LPVOID lpParm)
HINSTANCE hInstance = GetModuleHandle(NULL);
if (!hInstance) hInstance = LoadLibrary((LPCSTR) lpParm);
if (!hInstance) return 1;
hKeyboardHook = SetWindowsHookEx ( WH_KEYBOARD_LL, (HOOKPROC) KeyboardEvent, hInstance, NULL );
MessageLoop();
UnhookWindowsHookEx(hKeyboardHook);
return 0;
/*********************************************
*** ***
*** ***
**********************************************/
void grabScreenshot(POINT a, POINT b)
// copy screen to bitmap
HDC hScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, abs(b.x-a.x), abs(b.y-a.y));
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BOOL bRet = BitBlt(hDC, 0, 0, abs(b.x-a.x), abs(b.y-a.y), hScreen, a.x, a.y, SRCCOPY);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
// clean up
SelectObject(hDC, old_obj);
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
DeleteObject(hBitmap);
【讨论】:
以上是关于模拟全局热键的主要内容,如果未能解决你的问题,请参考以下文章