📄 sendkey.pas
字号:
unit SendKey;
interface
uses Windows, Messages;
type
// 错误种类
TSKErr = (
SKERR_NOERROR = 0, // 没有错误
SKERR_MISSINGCLOSEBRACE = 1, // 找不到与左大括号匹配的右大括号
SKERR_INVALIDKEY = 2, // 所使用的特殊键无法辨别
SKERR_MISSINGCLOSEPAREN = 3, // 找不到与左括号匹配的右括号
SKERR_INVALIDCOUNT = 4, // 指定了一个非法的重复次数
SKERR_STRINGTOOLONG = 5, // 传入字符串过长
SKERR_CANTINSTALLHOOK = 6 // 无法安装回放钩子
);
// 发送一系列按键
function SendKeys(hWndQueueSyncTarget: HWND; pszKeys: PChar): TSKErr; stdcall;
implementation
var
g_SKD: record
asVirtKeys: array[0..1023] of SHORT; // 虚拟键值列表
nVirtKeyNum: Integer; // 下一个被播放的按键
nMaxVirtKeys: Integer; // 列表长度
pszKeys: PChar; // 输入字串中下一个字符地址
fNoTokensRetrievedYet: BOOL; // Flag that indicates playback beginning
hhook: LongWord; // HHOOK, 回放钩子句柄
hWndQueueSyncTarget: HWND; // 接受WM_QUEUESYNC通知的窗口
end;
const
// 自定义虚拟键值, 遇此键值'回放'WM_QUEUESYNC消息
VK_QUEUESYNC = -1;
type
// 特殊按键信息
PSpecialKey = ^TSpecialKey;
TSpecialKey = record
sVirtKey: SHORT; // 键值
szKeyName: PChar; // 键名
end;
const
// 特殊按键列表
g_SpecialKeys: array[0..42] of TSpecialKey = (
( sVirtKey: VK_QUEUESYNC; szKeyName: 'QUEUESYNC' ),
( sVirtKey: VK_CAPITAL; szKeyName: 'CAPSLOCK' ),
( sVirtKey: VK_NUMLOCK; szKeyName: 'NUMLOCK' ),
( sVirtKey: VK_SCROLL; szKeyName: 'SCROLLOCK' ),
( sVirtKey: VK_ESCAPE; szKeyName: 'ESCAPE' ),
( sVirtKey: VK_ESCAPE; szKeyName: 'ESC' ),
( sVirtKey: VK_RETURN; szKeyName: 'ENTER' ),
( sVirtKey: VK_HELP; szKeyName: 'HELP' ),
( sVirtKey: VK_SNAPSHOT; szKeyName: 'PRTSC' ),
( sVirtKey: VK_TAB; szKeyName: 'TAB' ),
( sVirtKey: VK_CONTROL; szKeyName: 'BREAK' ),
( sVirtKey: VK_CLEAR; szKeyName: 'CLEAR' ),
( sVirtKey: VK_BACK; szKeyName: 'BACKSPACE' ),
( sVirtKey: VK_BACK; szKeyName: 'BS' ),
( sVirtKey: VK_BACK; szKeyName: 'BKSP' ),
( sVirtKey: VK_DELETE; szKeyName: 'DELETE' ),
( sVirtKey: VK_DELETE; szKeyName: 'DEL' ),
( sVirtKey: VK_INSERT; szKeyName: 'INSERT' ),
( sVirtKey: VK_LEFT; szKeyName: 'LEFT' ),
( sVirtKey: VK_RIGHT; szKeyName: 'RIGHT' ),
( sVirtKey: VK_UP; szKeyName: 'UP' ),
( sVirtKey: VK_DOWN; szKeyName: 'DOWN' ),
( sVirtKey: VK_PRIOR; szKeyName: 'PGUP' ),
( sVirtKey: VK_NEXT; szKeyName: 'PGDN' ),
( sVirtKey: VK_HOME; szKeyName: 'HOME' ),
( sVirtKey: VK_END; szKeyName: 'END' ),
( sVirtKey: VK_F1; szKeyName: 'F1' ),
( sVirtKey: VK_F2; szKeyName: 'F2' ),
( sVirtKey: VK_F3; szKeyName: 'F3' ),
( sVirtKey: VK_F4; szKeyName: 'F4' ),
( sVirtKey: VK_F5; szKeyName: 'F5' ),
( sVirtKey: VK_F6; szKeyName: 'F6' ),
( sVirtKey: VK_F7; szKeyName: 'F7' ),
( sVirtKey: VK_F8; szKeyName: 'F8' ),
( sVirtKey: VK_F9; szKeyName: 'F9' ),
( sVirtKey: VK_F10; szKeyName: 'F10' ),
( sVirtKey: VK_F11; szKeyName: 'F11' ),
( sVirtKey: VK_F12; szKeyName: 'F12' ),
( sVirtKey: VK_F13; szKeyName: 'F13' ),
( sVirtKey: VK_F14; szKeyName: 'F14' ),
( sVirtKey: VK_F15; szKeyName: 'F15' ),
( sVirtKey: VK_F16; szKeyName: 'F16' ),
( sVirtKey: 0; szKeyName: nil ) );
// 字符(串)转成虚拟键值
function SendKeys_SpecialKeyToVirtKey(const pszSpecialKey: PChar): SHORT;
var
psk: PSpecialKey;
begin
// 遍历按键列表
psk := @g_SpecialKeys[0];
Result := psk.sVirtKey;
while (Result <> 0) and (lstrcmpi(pszSpecialKey, psk.szKeyName) <> 0) do
begin
Inc(psk);
Result := psk.sVirtKey;
end;
if (Result = 0) and (lstrlen(pszSpecialKey) = 1) then
begin
// 单个字符转成虚拟键值
Result := VkKeyScan(pszSpecialKey^);
end;
end;
// 分析字符串得出重复次数
function PCharToInt(P: PChar): Integer;
begin
Result := 0;
while (P^ <> '}') do
begin
if (P^ < '0') or (P^ > '9') then
begin
Result := 0;
Exit;
end;
Result := Result * 10 + Byte(P^) - $30;
Inc(P);
end;
end;
// 在字符串S定位指定字符C
function SearchChar(S: PChar; C: Char): PChar;
begin
while (S^ <> #0) and (S^ <> C) do Inc(S);
if (S^ = C) then Result := S else Result := nil;
end;
// 预处理下一个按键
function SendKeys_PreprocessKeys(): TSKErr;
var
cChar: Char; // 当前字符
szSpecialKey: array[0..15] of Char; // 特殊键名
pEndOfToken: PChar; // 当前尾部
sVirtKey: SHORT; // 虚拟键值
nCount: Integer; // 重复次数
nNumChars: Integer;
label
Other;
begin
sVirtKey := 0;
nCount := 1;
Result := SKERR_NOERROR;
cChar := g_SKD.pszKeys^;
Inc(g_SKD.pszKeys);
// 当前字符
case (cChar) of
#0: // 末尾
begin
Dec(g_SKD.pszKeys); // 调整指针指向#0
end;
'(': // 成组
begin
// 添加组内字符
while (g_SKD.pszKeys^ <> #0) and (g_SKD.pszKeys^ <> ')') do
begin
Result := SendKeys_PreprocessKeys();
if (Result <> SKERR_NOERROR) then Break; // 出错
end;
// 因#0跳出循环
if (g_SKD.pszKeys^ = #0) then
Result := SKERR_MISSINGCLOSEPAREN // 缺少右括号
else
Inc(g_SKD.pszKeys); // 跳过右括号
end;
'~': // 回车
begin
if (g_SKD.nMaxVirtKeys = High(g_SKD.asVirtKeys) + 1) then
begin
Result := SKERR_STRINGTOOLONG; // 字串太长
end else
begin
g_SKD.asVirtKeys[g_SKD.nMaxVirtKeys] := VK_RETURN; // 添加回车
Inc(g_SKD.nMaxVirtKeys);
end;
end;
'+', // Shift
'^', // Control
'%': // Alt
begin
if (cChar = '+') then
cChar := Char(VK_SHIFT)
else
if (cChar = '^') then
cChar := Char(VK_CONTROL)
else
cChar := Char(VK_MENU);
// 按下自己
if (g_SKD.nMaxVirtKeys = High(g_SKD.asVirtKeys) + 1) then
begin
Result := SKERR_STRINGTOOLONG; // 字符串太长
Exit;
end else
begin
g_SKD.asVirtKeys[g_SKD.nMaxVirtKeys] := Byte(cChar);
Inc(g_SKD.nMaxVirtKeys);
end;
// 中间按键
Result := SendKeys_PreprocessKeys();
if (Result <> SKERR_NOERROR) then Exit;
// 释放自己
if (g_SKD.nMaxVirtKeys = High(g_SKD.asVirtKeys) + 1) then
begin
Result := SKERR_STRINGTOOLONG; // 字串太长
Exit;
end else
begin
g_SKD.asVirtKeys[g_SKD.nMaxVirtKeys] := Byte(cChar);
Inc(g_SKD.nMaxVirtKeys);
end;
end;
'{':
begin
// 可能是 "{}}", 也就是单个字符"}"
if (g_SKD.pszKeys^ = '}') then
begin
sVirtKey := VkKeyScan('}');
Inc(g_SKD.pszKeys);
end;
// 搜寻空格或者右花括号
pEndOfToken := SearchChar(g_SKD.pszKeys, ' ');
if (pEndOfToken = nil) then pEndOfToken := SearchChar(g_SKD.pszKeys, '}');
// 没有找到
if (pEndOfToken = nil) then
begin
Result := SKERR_MISSINGCLOSEBRACE; // 缺少花括号
Exit;
end;
// 并非'{}}'
if (sVirtKey = 0) then
begin
// 虚拟键串
nNumChars := pEndOfToken - g_SKD.pszKeys;
lstrcpyn(szSpecialKey, g_SKD.pszKeys, nNumChars + 1);
szSpecialKey[nNumChars] := #0;
// 虚拟键值
sVirtKey := SendKeys_SpecialKeyToVirtKey(szSpecialKey);
if (sVirtKey = 0) then
begin
Result := SKERR_INVALIDKEY;
Exit;
end;
end;
// 计算重复次数
if (pEndOfToken^ = ' ') then
begin
Inc(pEndOfToken);
nCount := PCharToInt(pEndOfToken);
if (nCount = 0) then
begin
Result := SKERR_INVALIDCOUNT; // 非法次数
Exit;
end;
end;
// 跳过右大括号
g_SKD.pszKeys := SearchChar(pEndOfToken, '}');
if (g_SKD.pszKeys = nil) then
begin
Result := SKERR_MISSINGCLOSEBRACE;
Exit;
end;
Inc(g_SKD.pszKeys);
// 自定义"键值"
if (sVirtKey = VK_QUEUESYNC) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -