C++实现wins后台监控键盘输入(Hook)

Hook定义

钩子(Hook)实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

Hook分类

钩子技术分为系统钩子技术和线程钩子技术

  • 系统钩子:是用于监视系统中的消息的钩子技术,因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。做好之后使用其他程序将钩子挂载到系统的进程中。
  • 线程钩子:指的是对指定线程进行监视。

Hook处理流程

  • 阶段1:定义Hook。使用SetWindowsHookEx。
  • 阶段2:在Hook链表中传递Hook。使用CallNextHookEx。
  • 阶段3:卸载Hook。系统必须对每个消息处理, 钩子程序因此增加了处理的负担,因此也降低了系统的性能。UnhookWindowsHookEx可以将钩子句柄给删除。

定义Hook

HHOOK SetWindowsHookExA(
  [in] int       idHook,
  [in] HOOKPROC  lpfn,
  [in] HINSTANCE hmod,
  [in] DWORD     dwThreadId
);

idHook:钩子类型(-1~14)
lpfn:指向钩子进程的指针。如果dwThreadId参数为零或指定了由其他进程创建的线程的标识符,那么lpfn参数必须指向DLL中的钩子进程。否则,lpfn可以指向与当前进程关联的代码中的钩子进程。
hmod:lpfn形参指向的钩子子程所在DLL的句柄。 如果dwThreadId参数指定了一个由当前进程创建的线程,并且钩子子程在与当前进程相关的代码中,那么hMod参数必须设置为NULL。
dwThreadId:钩子子程要关联的线程的标识符。对于桌面应用程序,如果该参数为0,则钩子子程与调用线程在同一桌面中运行的所有现有线程相关联。对于Windows Store应用程序,请参见备注部分。
HHOOK:如果函数执行成功,返回值是钩子子程的句柄。
如果函数失败,返回值是NULL。

Hook类型

在winuser.h中定义了

#define WH_MSGFILTER (-1)
#define WH_JOURNALRECORD 0 // 记录从系统消息队列中取出的各种事件消息
#define WH_JOURNALPLAYBACK 1
#define WH_KEYBOARD 2 // 键盘输入
#define WH_GETMESSAGE 3
#define WH_CALLWNDPROC 4 // 监视所有从系统消息队列发往目标窗口的消息
#define WH_CBT 5
#define WH_SYSMSGFILTER 6
#define WH_MOUSE 7 // 鼠标输入
#define WH_HARDWARE 8
#define WH_DEBUG 9
#define WH_SHELL 10 // 监视各种Shell事件消息。比如启动和关闭应用程序
#define WH_FOREGROUNDIDLE 11
#define WH_CALLWNDPROCRET 12 // 监视所有从系统消息队列发往目标窗口的消息

#define WH_KEYBOARD_LL 13 // 底层键盘输入(不依赖本程序)
#define WH_MOUSE_LL 14 // 底层鼠标输入(不依赖本程序)

传递Hook

LRESULT CallNextHookEx(
  [in, optional] HHOOK  hhk,
  [in]           int    nCode,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);

hhk:忽略
nCode:传递给当前钩子进程的钩子代码。下一个钩子进程使用此代码来确定如何处理该钩子信息。
wParam:传递给当前钩子进程的wParam值。该参数的含义取决于与当前钩子链关联的钩子类型。
lParam:传递给当前钩子进程的lParam值。该参数的含义取决于与当前钩子链关联的钩子类型。
LRESULT:返回值,值由链表中的下一个钩子进程返回。当前钩子进程也必须返回该值。返回值的含义取决于钩子的类型。

删除Hook

BOOL UnhookWindowsHookEx(
  [in] HHOOK hhk
);

hhk:前一个调用SetWindowsHookEx获得的钩子句柄。
BOOL:删除成功与否

后台监控键盘输入

注:为了程序简洁,只监控键盘输入0和1。
完整程序参考:
https://blog.csdn.net/Simon798/article/details/98848050

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <conio.h>

using namespace std;

HHOOK keyboardHook = 0;		// 钩子句柄、

LRESULT CALLBACK LowLevelKeyboardProc(
	_In_ int nCode,		// 规定钩子如何处理消息,小于 0 则直接 CallNextHookEx
	_In_ WPARAM wParam,	// 消息类型
	_In_ LPARAM lParam	// 指向某个结构体的指针,这里是 KBDLLHOOKSTRUCT(低级键盘输入事件)
	){
    KBDLLHOOKSTRUCT *ks = (KBDLLHOOKSTRUCT*)lParam;		// 包含低级键盘输入事件信息
	/*
	typedef struct tagKBDLLHOOKSTRUCT {
		DWORD     vkCode;		// 按键代号
		DWORD     scanCode;		// 硬件扫描代号,同 vkCode 也可以作为按键的代号。
		DWORD     flags;		// 事件类型,一般按键按下为 0 抬起为 128。
		DWORD     time;			// 消息时间戳
		ULONG_PTR dwExtraInfo;	// 消息附加信息,一般为 0。
	}KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT;
	*/
    if(ks->flags == 128 || ks->flags == 129)
    {
		// 监控键盘
		switch(ks->vkCode){
		case 0x30: case 0x60:
			cout << "检测到按键:" << "0" << endl;
			break;
		case 0x31: case 0x61:
			cout << "检测到按键:" << "1" << endl;
			break;
		}
		
        //return 1;		// 使按键失效
    }

	// 将消息传递给钩子链中的下一个钩子
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int _tmain(int argc, _TCHAR* argv[])
{
    SetConsoleOutputCP(65001);// 更改cmd编码为utf8
	// 安装钩子
	keyboardHook = SetWindowsHookEx(
		WH_KEYBOARD_LL,			// 钩子类型,WH_KEYBOARD_LL 为键盘钩子
		LowLevelKeyboardProc,	// 指向钩子函数的指针
		GetModuleHandleA(NULL),	// Dll 句柄
		NULL					
		);
    if (keyboardHook == 0){cout << "挂钩键盘失败" << endl; return -1;}

    //不可漏掉消息处理,不然程序会卡死
    MSG msg;
    while(1)
    {
		// 如果消息队列中有消息
        if (PeekMessageA(
			&msg,		// MSG 接收这个消息
			NULL,		// 检测消息的窗口句柄,NULL:检索当前线程所有窗口消息
			NULL,		// 检查消息范围中第一个消息的值,NULL:检查所有消息(必须和下面的同时为NULL)
			NULL,		// 检查消息范围中最后一个消息的值,NULL:检查所有消息(必须和上面的同时为NULL)
			PM_REMOVE	// 处理消息的方式,PM_REMOVE:处理后将消息从队列中删除
			)){
				// 把按键消息传递给字符消息
				TranslateMessage(&msg);

				// 将消息分派给窗口程序
				DispatchMessageW(&msg);
		}
        else
            Sleep(0);    //避免CPU全负载运行
    }
	// 删除钩子
    UnhookWindowsHookEx(keyboardHook);

	return 0;
}

程序运行情况参考:(支持后台监控)
在这里插入图片描述

  • 14
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是基于C++的alpha-beta剪枝算法五子棋代码示例: ```cpp #include <iostream> #include <limits> #include <vector> using namespace std; const int BOARD_SIZE = 15; const int WIN_COUNT = 5; const int HUMAN = 1; const int COMPUTER = 2; struct Position { int x; int y; Position(int x, int y) : x(x), y(y) {} }; class Board { public: Board() { board = new int*[BOARD_SIZE]; for (int i = 0; i < BOARD_SIZE; i++) { board[i] = new int[BOARD_SIZE]; for (int j = 0; j < BOARD_SIZE; j++) { board[i][j] = 0; } } } ~Board() { for (int i = 0; i < BOARD_SIZE; i++) { delete[] board[i]; } delete[] board; } int get(int x, int y) const { return board[x][y]; } void set(int x, int y, int value) { board[x][y] = value; } bool isFull() const { for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == 0) { return false; } } } return true; } bool hasWon(int player) const { int count = 0; // Check rows for (int i = 0; i < BOARD_SIZE; i++) { count = 0; for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == player) { count++; if (count == WIN_COUNT) { return true; } } else { count = 0; } } } // Check columns for (int j = 0; j < BOARD_SIZE; j++) { count = 0; for (int i = 0; i < BOARD_SIZE; i++) { if (board[i][j] == player) { count++; if (count == WIN_COUNT) { return true; } } else { count = 0; } } } // Check diagonals for (int k = 0; k < BOARD_SIZE * 2 - 1; k++) { count = 0; for (int i = 0; i < BOARD_SIZE; i++) { int j = k - i; if (j >= 0 && j < BOARD_SIZE) { if (board[i][j] == player) { count++; if (count == WIN_COUNT) { return true; } } else { count = 0; } } } } // Check anti-diagonals for (int k = 0; k < BOARD_SIZE * 2 - 1; k++) { count = 0; for (int i = 0; i < BOARD_SIZE; i++) { int j = k - (BOARD_SIZE - 1 - i); if (j >= 0 && j < BOARD_SIZE) { if (board[i][j] == player) { count++; if (count == WIN_COUNT) { return true; } } else { count = 0; } } } } return false; } vector<Position> getEmptyPositions() const { vector<Position> emptyPositions; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == 0) { emptyPositions.push_back(Position(i, j)); } } } return emptyPositions; } private: int** board; }; int score(const Board& board, int player) { if (board.hasWon(player)) { return numeric_limits<int>::max(); } else if (board.hasWon(3 - player)) { return numeric_limits<int>::min(); } else { return 0; } } int alphaBeta(const Board& board, int depth, int alpha, int beta, int player) { if (depth == 0 || board.isFull()) { return score(board, player); } if (player == COMPUTER) { int value = numeric_limits<int>::min(); for (const auto& emptyPosition : board.getEmptyPositions()) { Board newBoard = board; newBoard.set(emptyPosition.x, emptyPosition.y, player); value = max(value, alphaBeta(newBoard, depth - 1, alpha, beta, 3 - player)); alpha = max(alpha, value); if (alpha >= beta) { break; } } return value; } else { // player == HUMAN int value = numeric_limits<int>::max(); for (const auto& emptyPosition : board.getEmptyPositions()) { Board newBoard = board; newBoard.set(emptyPosition.x, emptyPosition.y, player); value = min(value, alphaBeta(newBoard, depth - 1, alpha, beta, 3 - player)); beta = min(beta, value); if (alpha >= beta) { break; } } return value; } } Position findBestMove(const Board& board, int depth, int player) { int alpha = numeric_limits<int>::min(); int beta = numeric_limits<int>::max(); int bestValue = numeric_limits<int>::min(); Position bestMove(-1, -1); for (const auto& emptyPosition : board.getEmptyPositions()) { Board newBoard = board; newBoard.set(emptyPosition.x, emptyPosition.y, player); int value = alphaBeta(newBoard, depth - 1, alpha, beta, 3 - player); if (value > bestValue) { bestValue = value; bestMove = emptyPosition; } } return bestMove; } int main() { Board board; int player = HUMAN; while (!board.isFull() && !board.hasWon(HUMAN) && !board.hasWon(COMPUTER)) { if (player == HUMAN) { int x, y; cout << "Enter your move (x y): "; cin >> x >> y; while (board.get(x, y) != 0) { cout << "Invalid move. Please try again." << endl; cout << "Enter your move (x y): "; cin >> x >> y; } board.set(x, y, HUMAN); player = COMPUTER; } else { // player == COMPUTER int depth = 5; // You can adjust the search depth here Position bestMove = findBestMove(board, depth, COMPUTER); cout << "Computer's move: " << bestMove.x << " " << bestMove.y << endl; board.set(bestMove.x, bestMove.y, COMPUTER); player = HUMAN; } // Print the board for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { cout << board.get(i, j) << " "; } cout << endl; } cout << endl; } if (board.hasWon(HUMAN)) { cout << "You win!" << endl; } else if (board.hasWon(COMPUTER)) { cout << "Computer wins!" << endl; } else { cout << "Draw." << endl; } return 0; } ``` 这个代码实现了基本的alpha-beta剪枝算法,你可以根据自己的需求进行调整和拓展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值