close

如何寫一個全域快速鍵 隨時隨地 按鍵盤的按鍵即可撥放音樂 放開即停止

https://tw.answers.yahoo.com/question/index?qid=20160929044947AAzPzY3

 

使用Hook可以全域偵測鍵盤(即使焦點不再該Application內)

但必須註冊DLL檔才能全域偵測

以下源碼 使用Hook 製作DLL檔  並使用PostMessage 將按鍵訊息傳回專案

 

由於使用了兩個專案 所以弄一個ProjectGroup

 

定義一個Message常數 放在Unit 兩個專案共用

unit HOOK_Const;

interface

uses Messages;

const WM_MyMessage = WM_USER + 1;

implementation

end.


 

Hook DLL程式碼

library KeyboardHook;

uses
  SysUtils,
  Windows,
  Messages,
  Classes,
  HOOK_Const in 'HOOK_Const.pas';

{$R *.res}

var
  hook: HHOOK; {钩子变量}
  MainFormHandle: HWND;

{键盘钩子函数}
function KeyboardHookProc(iCode: Integer; wParam: WPARAM; lParam:LPARAM):LRESULT;stdcall;
var
  vKey:integer;      //表示按下了哪个键
  PEvt:^EventMsg;         //EventMsg的指针
begin
  if iCode<0 then //遵照SDK文档
  begin
    Result:=CallNextHookEx(hook,iCode,wParam,lParam);
    Exit;
  end;

  PEvt := pointer(Dword(lparam));           //将lparam的指针传递给PEvt事件消息指针

  if (PEvt.message = WM_KEYDOWN) or (PEvt.message = WM_KEYUP) then
  begin
    vkey := LoByte(PEvt.paramL );         //取得16进制数最低位那个字节的内容
    {通过消息把数据传递给指定窗口}
    PostMessage(MainFormHandle, WM_MyMessage, PEvt.message, vkey);
  end;

  result := CallNextHookEx(hook,iCode,wparam,lparam);
end;

{建立钩子}
function SetHook(H:HWND):Boolean;stdcall;
begin
  if (hook = 0) then
  begin
    hook := SetWindowsHookEx(WH_JOURNALRECORD,KeyboardHookProc,HInstance,0);    //调用API HOOK
    Result:=hook<>0;
    MainFormHandle:=H;
  end
  else
    Result:=False;
end;

{释放钩子}
function DelHook:Boolean;stdcall;
begin
  if (hook <> 0 ) then
  begin
      Result:=UnHookWindowsHookEx(hook);    //卸载HOOK
      hook:=0;
  end
  else
      Result:=False;
end;

{按DLL的要求输出函数}
exports
SetHook name 'SetHook',
DelHook name 'DelHook';

//SetHook,DelHook;{如果不需要改名,可以直接这样exports}
begin
end.

 


主程式

unit Hook_Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls
  ,HOOK_Const, Vcl.ExtCtrls, Vcl.MPlayer;

type
  Tfrm_Hook_Main = class(TForm)
    pnl_Top: TPanel;
    btn_StartHook: TButton;
    btn_StopHook: TButton;
    btn_AddRecord: TButton;
    btn_DelRecord: TButton;
    mo_Setup: TMemo;
    OpenDialog: TOpenDialog;
    MediaPlayer: TMediaPlayer;
    btn_test: TButton;
    procedure btn_StartHookClick(Sender: TObject);
    procedure btn_StopHookClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure MyMessage(var msg: TMessage); message WM_MyMessage;{定义一个消息方法接受消息}
    procedure btn_AddRecordClick(Sender: TObject);
    procedure btn_testClick(Sender: TObject);
  private
    WorkIngKey:Integer;     //正在按的按鍵
    isHookInstalled:Boolean;       //是否正在Hook
    Function GetINIPath:String;    //取得INI路徑
    { Private declarations }
  public
    { Public declarations }
  end;

  {DLL 中的函数声明}
  function SetHook(H:HWND): Boolean; stdcall;
  function DelHook: Boolean; stdcall;

var
  frm_Hook_Main: Tfrm_Hook_Main;

implementation

{$R *.dfm}

uses HOOK_SendKey;

{DLL 中的函数实现, 也就是说明来自那里, 原来叫什么名}
function SetHook; external 'KeyboardHook.dll' name 'SetHook';
function DelHook; external 'KeyboardHook.dll' name 'DelHook';

//增加一個按鍵紀錄
procedure Tfrm_Hook_Main.btn_AddRecordClick(Sender: TObject);
var key:integer;
begin
  key:=GetAKey;
  //Caption:=IntToStr(Key);
  if Sender = btn_AddRecord then
  begin
    if not OpenDialog.Execute then
      Exit;
    mo_Setup.Lines.Values[inttostr(key)]:=OpenDialog.FileName;
  end
  else
    with mo_Setup.Lines do
      Delete(IndexOfName(inttostr(key)));
end;

//開始Hook
procedure Tfrm_Hook_Main.btn_StartHookClick(Sender: TObject);
begin
   btn_StartHook.Enabled:=False;
   btn_StopHook.Enabled:=True;

   if SetHook(Handle) then
     isHookInstalled:=True;
end;

//停止Hook
procedure Tfrm_Hook_Main.btn_StopHookClick(Sender: TObject);
begin
   if DelHook then
    isHookInstalled:=False;

   btn_StartHook.Enabled:=True;
   btn_StopHook.Enabled:=False;
end;

//音樂測試按鈕
procedure Tfrm_Hook_Main.btn_testClick(Sender: TObject);
begin
  if not OpenDialog.Execute then
    Exit;
  MediaPlayer.Close;
  MediaPlayer.FileName:=OpenDialog.FileName;
  MediaPlayer.open;
  MediaPlayer.Play;
end;

//FormCreate事件
procedure Tfrm_Hook_Main.FormCreate(Sender: TObject);
begin
  btn_StartHook.Enabled:=True;
  btn_StopHook.Enabled:=False;
  isHookInstalled:=False;

  if not FileExists(GetINIPath) then
    With TStringlist.Create do
    begin
      SaveToFile(GetINIPath);
      Free;
    end;

  mo_setup.Lines.LoadFromFile(GetINIPath);
end;

//FormDestroy事件
procedure Tfrm_Hook_Main.FormDestroy(Sender: TObject);
begin
  if isHookInstalled then
    DelHook;
  mo_setup.Lines.SaveToFile(GetINIPath);
end;

//取得INI路徑
function Tfrm_Hook_Main.GetINIPath: String;
begin
  Result:=ExtractFileDir(Application.ExeName)+'\'+'setup.ini';
end;

//自訂義 接收Hook DLL回傳訊息
procedure Tfrm_Hook_Main.MyMessage(var msg: TMessage);
var index:integer;
begin
  //Caption:=IntToStr(msg.WParam)+' '+IntToStr(msg.LParam);
  if msg.WParam = WM_KEYUP then
  begin
    WorkIngKey:=0;
    MediaPlayer.Close;
    Exit;
  end;
  if msg.WParam = WM_KEYDOWN then
  begin
    if WorkIngKey=msg.lParam then
      Exit;

    WorkIngKey:=msg.lParam;

    with mo_Setup.Lines do
    begin
      index:=IndexOfName(IntToStr(WorkIngKey));
      if index>=0 then
      begin
        with MediaPlayer do
        begin
          Close;
          FileName:=ValueFromIndex[index];
          open;
          Play;
        end;
      end;
    end;
  end;
end;

end.

 


使用一個彈窗 HOOK_SendKey 來增加或減少鍵盤紀錄 (偵測鍵盤 然後選擇音樂檔)

unit HOOK_SendKey;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  Tfrm_SendKey = class(TForm)
    Label1: TLabel;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    FResult:integer; //回傳值
    { Private declarations }
  public
    { Public declarations }
  end;

function GetAKey:Integer;

var
  frm_SendKey: Tfrm_SendKey;

implementation

{$R *.dfm}

function GetAKey:Integer;
begin
  with frm_SendKey do
  begin
    //設定 顯示在正中央
    Top:=(Screen.Height-Height) div 2;
    Left:=(Screen.Width-Width) div 2;

    ShowModal;
    Result:=FResult;
  end;
end;

procedure Tfrm_SendKey.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  FResult:=Key;
  Close;
end;

end.

 


參考網址

Hook

http://www.cnblogs.com/edisonfeng/archive/2012/05/18/2507858.html

Message傳遞

http://www.cnblogs.com/del/archive/2008/07/14/1242391.html

 

 

附上檔案

https://github.com/Kamilia1470/XBHook

arrow
arrow
    文章標籤
    Delphi Hook dll
    全站熱搜

    抓狂小白 發表在 痞客邦 留言(0) 人氣()