📄 echo.dpr
字号:
program Echo;
{$R Echo.res}
uses Windows, Messages, Recorder in 'Recorder.pas';
const
// 模板资源ID
IDD_ECHO = 101;
// 图标资源ID
IDI_ECHO = 102;
// 按钮控件ID
IDC_RECORD = 1000;
IDC_PLAY = 1001;
IDC_STOP = 1002;
// Purpose: 自定义(记录/回放)停止通知消息
// wParam: hEventList - 事件列表句柄(仅当记录停止时有效)
// lParam: TRecErr - 记录器错误类型(表示由于什么错误停止)
// Return: 略
UM_STOP = (WM_APP + 0);
// 读取事件列表句柄(实际上是指针)
function GetEventList(hWnd: HWND): hEventList;
begin
Result := GetWindowLong(hWnd, GWL_USERDATA);
end;
// 保存事件列表句柄(实际上是指针)
procedure SetEventList(hWnd: HWND; h: hEventList);
begin
SetWindowLong(hWnd, GWL_USERDATA, h);
end;
// (根据当前记录器状态)设置按钮
procedure Echo_UpdateButtons(hWnd: HWND);
var
RecMode: TRecMode;
fRec, fPlay, fStop: BOOL;
hWndRec, hWndPlay, hWndStop, hWndFocus: LongWord; // HWND
begin
// 记录器状态
RecMode := Recorder_GetMode();
// 启用/禁用
fRec := (RecMode = RECMODE_STOPPED);
fPlay := (RecMode = RECMODE_STOPPED) and (GetEventList(hWnd) <> 0);
fStop := (RecMode <> RECMODE_STOPPED);
// 按钮句柄
hWndRec := GetDlgItem(hWnd, IDC_RECORD);
hWndPlay := GetDlgItem(hWnd, IDC_PLAY);
hWndStop := GetDlgItem(hWnd, IDC_STOP);
// 设置按钮
EnableWindow(hWndRec, fRec);
EnableWindow(hWndPlay, fPlay);
EnableWindow(hWndStop, fStop);
// 焦点按钮
if fPlay then
hWndFocus := hWndPlay
else begin
if fStop then
hWndFocus := hWndStop
else
hWndFocus := hWndRec;
end;
// 设置焦点
SendMessage(hWnd, DM_SETDEFID, GetDlgCtrlID(hWndFocus), 0);
SetFocus(hWndFocus);
end;
// 对话框WM_INITDIALOG处理
function Echo_OnInitDialog(hWnd, hWndFocus: HWND; lParam: LPARAM): BOOL;
begin
// 设置窗体图标
SendMessage(hWnd, WM_SETICON, ICON_BIG, LoadIcon(HInstance, MakeIntResource(IDI_ECHO)));
// 记录列表为空
SetEventList(hWnd, 0);
// 记录器初始化
Recorder_Init();
// 初始化各按钮
Echo_UpdateButtons(hWnd);
// 接受默认焦点
Result := TRUE;
end;
// 对话框UM_STOP处理
procedure Echo_OnStop(hWnd: HWND; h: hEventList; e: TRecErr);
begin
// 本函数会因为记录/回放停止而调用,
// h非空则为前者,需要保存,以便回放
if (h <> 0) then SetEventList(hWnd, h);
Echo_UpdateButtons(hWnd);
Recorder_DisplayError(e);
end;
// 对话框WM_COMMAND处理
procedure Echo_OnCommand(hWnd: HWND; id: Integer; hWndCtl: HWND; codeNotify: UINT);
var
e: TRecErr;
begin
case (id) of
IDCANCEL: // 关闭对话框
begin
// 释放事件列表
Recorder_Free(GetEventList(hWnd));
// 结束消息循环
PostQuitMessage(0);
end;
IDC_RECORD: // 选择'记录'
begin
// 释放事件列表
if (GetEventList(hWnd) <> 0) then
begin
Recorder_Free(GetEventList(hWnd));
SetEventList(hWnd, 0);
end;
// 安装记录钩子
e := Recorder_Record(hWnd, UM_STOP);
Echo_UpdateButtons(hWnd);
Recorder_DisplayError(e);
end;
IDC_PLAY: // 选择'回放'
begin
// 安装回放钩子
e := Recorder_Play(GetEventList(hWnd), hWnd, UM_STOP);
Echo_UpdateButtons(hWnd);
Recorder_DisplayError(e);
end;
IDC_STOP: // 选择'停止'
begin
// 停止记录or回放
e := Recorder_Stop();
Echo_UpdateButtons(hWnd);
Recorder_DisplayError(e);
end;
end;
end;
// 对话框消息处理回调
function Echo_DlgProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
begin
case (uMsg) of
WM_INITDIALOG:
begin
Result := BOOL(SetWindowLong(hWnd, DWL_MSGRESULT,
Longint(Echo_OnInitDialog(hWnd, wParam, lParam))));
end;
WM_COMMAND:
begin
Echo_OnCommand(hWnd, LOWORD(wParam), lParam, HIWORD(wParam));
Result := TRUE;
end;
UM_STOP:
begin
Echo_OnStop(hWnd, wParam, TRecErr(lParam));
Result := TRUE;
end;
else Result := FALSE;
end;
end;
// 程序'主线程'入口
var
Msg: TMsg;
hWnd: LongWord; // HWND
begin
// 建立一个非模态对话框, 自己处理消息循环, 得以拦截WM_CANCELJOURNAL消息
hWnd := CreateDialog(HInstance, MakeIntResource(IDD_ECHO), 0, @Echo_DlgProc);
// 继续循环直至取出WM_QUIT消息
while GetMessage(Msg, 0, 0, 0) do
begin
// 如果是WM_CANCELJOURNAL消息, 说明钩子已经因用户按下系统快捷键而失效
Recorder_IsRecorderCanceled(@Msg);
// 调用IsDialogMessage()分发消息, 它会对键盘消息作对话框式的特殊处理
if (not IsDialogMessage(hWnd, Msg)) then
begin
// 不是对话框消息, 则作普通的分发和翻译
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
// 因PostQuitMessage()而间接跳出消息循环, 清除作为主窗口的非模态对话框
DestroyWindow(hWnd);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -