Как я могу обрабатывать сочетание клавиш, когда моя программа не активна?

Это нормально, если я использую его так... для нескольких событий?

unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Clipbrd;

type
  TForm4 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure WMHotkey(var Message: TWMHotKey); message WM_HOTKEY;
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

const
  MY_ID = 123;
  MY_ID1 = 123;
  MY_ID2 = 123;

{$R *.dfm}

procedure TForm4.FormCreate(Sender: TObject);
begin
  RegisterHotKey(Handle, MY_ID, MOD_CONTROL, ord('1'));
   RegisterHotKey(Handle, MY_ID1, MOD_CONTROL, ord('2'));
    RegisterHotKey(Handle, MY_ID2, MOD_CONTROL, ord('3'));
end;

procedure TForm4.FormDestroy(Sender: TObject);
begin
  UnregisterHotKey(Handle, MY_ID);
  UnregisterHotKey(Handle, MY_ID1);
  UnregisterHotKey(Handle, MY_ID2);
end;

procedure TForm4.WMHotkey(var Message: TWMHotKey);
begin
  if Message.HotKey = MY_ID then
  begin

    if not AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), true) then
      RaiseLastOSError;

    try
      Clipboard.AsText := 'text1';
      SendMessage(GetFocus, WM_PASTE, 0, 0);
    finally
      AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), false);
    end;

    if Message.HotKey = MY_ID1 then
  begin

    if not AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), true) then
      RaiseLastOSError;

    try
      Clipboard.AsText := 'text2';
      SendMessage(GetFocus, WM_PASTE, 0, 0);
    finally
      AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), false);
    end;

  if Message.HotKey = MY_ID2 then
  begin

    if not AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), true) then
      RaiseLastOSError;

    try
      Clipboard.AsText := 'text3';
      SendMessage(GetFocus, WM_PASTE, 0, 0);
    finally
      AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), false);
    end;

  end;
end;

end;
end;
end.

person andrei    schedule 06.11.2010    source источник


Ответы (3)


Используйте функцию RegisterHotKey. Если вы хотите, чтобы приложение было невидимым, вам могут понадобиться все подробности в мой ответ на аналогичный вопрос.

Попробуй это:

unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Clipbrd;

type
  TForm4 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure WMHotkey(var Message: TWMHotKey); message WM_HOTKEY;
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

const
  MY_ID = 123;

{$R *.dfm}

procedure TForm4.FormCreate(Sender: TObject);
begin
  RegisterHotKey(Handle, MY_ID, MOD_CONTROL, ord('1'));
end;

procedure TForm4.FormDestroy(Sender: TObject);
begin
  UnregisterHotKey(Handle, MY_ID);
end;

procedure TForm4.WMHotkey(var Message: TWMHotKey);
begin
  if Message.HotKey = MY_ID then
  begin

    if not AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), true) then
      RaiseLastOSError;

    try
      Clipboard.AsText := 'This is my own text!';
      SendMessage(GetFocus, WM_PASTE, 0, 0);
    finally
      AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(GetForegroundWindow), false);
    end;

  end;
end;

end.

Конечно, вам нужно будет использовать этот подход и изменить его, чтобы он подходил для вашего конкретного случая. (То есть вам, вероятно, нужно нечто большее, чем приложение, которое печатает «Это мой собственный текст!» при нажатии Ctrl+1, но ничего больше.)

person Andreas Rejbrand    schedule 06.11.2010
comment
Можете ли вы дать мне пример, пожалуйста? - person andrei; 07.11.2010
comment
скажем, когда я нажимаю ctrl+1, слово delphi появляется в каждом приложении Windows, например Microsoft Word или около того. - person andrei; 07.11.2010
comment
@andrei: Сейчас я приведу пример именно этого. Но, по крайней мере, в Word 2010 это не работает (но Блокнот работает нормально). - person Andreas Rejbrand; 07.11.2010
comment
Андреас, вы просто используете функцию UnregisterHotKey, когда используете RegisterHotKey, чтобы освободить горячую клавишу. - person RRUZ; 07.11.2010
comment
Я знаю. Я просто небрежно продемонстрировал идею ОП. - person Andreas Rejbrand; 07.11.2010
comment
@RRUZ: я предположил, что вы имели в виду, что вы должны использовать. - person Andreas Rejbrand; 07.11.2010
comment
@RUZZ: Тем не менее, мне любопытно: ты уверен? Разве операционная система не удаляет регистрацию при завершении процесса? - person Andreas Rejbrand; 07.11.2010
comment
Андреас о вашем вопросе, да, я уверен в этом, вы можете проверить документацию MSDN, в которой указано ..the application must explicitly call UnregisterHotKey to unregister the old hot key. по этой ссылке msdn.microsoft.com/en-us/library/ms646309%28VS.85%29.aspx - person RRUZ; 07.11.2010
comment
Боюсь, это ничего не делает, друг мой... я вставил твой код, запустил приложение, открыл блокнот, нажал ctrl+1 и абсолютно ничего не происходит... - person andrei; 07.11.2010
comment
Я думаю, это работает. Вы уверены, что Блокнот имел фокус клавиатуры, когда вы нажимали Ctrl+1? @RRUZ: Тебе не подходит? - person Andreas Rejbrand; 07.11.2010
comment
Есть ли какое-либо свойство или событие, которое мне нужно установить перед компиляцией кода? - person andrei; 07.11.2010
comment
@andrei: Конечно, вам нужно установить события OnFormCreate и OnFormDestroy в IDE, но в остальном нет, вам не нужно устанавливать какое-либо свойство. (Тот факт, что в коде есть метод с именем FormCreate, не означает, что этот метод будет выполняться при создании формы. Вам нужно установить для события OnCreate в IDE значение FormCreate, и аналогично для события OnDestroy.) - person Andreas Rejbrand; 07.11.2010
comment
это работает сейчас. но скажем, я хочу одновременно нажать Ctrl + 2. это нормально использовать это так? - person andrei; 07.11.2010
comment
Просто зарегистрируйте еще одну горячую клавишу с новым идентификатором и проверьте их в ответ на WM_HOTKEY (используя оператор case). - person Andreas Rejbrand; 07.11.2010

чтобы дополнить ответ Андреаса, вы можете использовать RegisterHotKey в сочетании с сообщением Windows WM_HOTKEY .

попробуйте этот код

type
  TForm17 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    HotKey1 : Integer;
    HotKey2 : Integer;
    procedure WMHotKey(var Msg: TWMHotKey); message WM_HOTKEY;
  public
    { Public declarations }
  end;

var
  Form17: TForm17;

implementation

{$R *.dfm}

{ TForm17 }

procedure TForm17.FormCreate(Sender: TObject);
const
  MOD_CONTROL = $0002;//0x0002
begin
  // Register Ctrl + 1 hotkey
  HotKey1 := GlobalAddAtom('Hotkey1');
  RegisterHotKey(Handle, HotKey1, MOD_CONTROL, Ord('1'));
  // Register  Ctrl + 2 hotkey
  HotKey2 := GlobalAddAtom('Hotkey2');
  RegisterHotKey(Handle, HotKey2, MOD_CONTROL, Ord('2'));
end;

procedure TForm17.FormDestroy(Sender: TObject);
begin
  //unregister the hotkeys
  UnRegisterHotKey(Handle, HotKey1);
  GlobalDeleteAtom(HotKey1);
  UnRegisterHotKey(Handle, HotKey2);
  GlobalDeleteAtom(HotKey2);
end;

procedure TForm17.WMHotKey(var Msg: TWMHotKey); 
begin
  if Msg.HotKey = HotKey1 then
  begin
    ShowMessage('Ctrl + 1 was pressed');
    //do your stuff
  end
  else
  if Msg.HotKey = HotKey2 then
  begin
    ShowMessage('Ctrl + 2 was pressed');
    //do your stuff
  end;
end;
person RRUZ    schedule 06.11.2010

Как предполагали другие, это функция RegisterHotKey. Однако правильная реализация приложения, которое вы хотите разработать, требует перехвата клавиатуры и внедрения DLL в приложение.

Я бы порекомендовал вам взглянуть на приложение TypePilot. Он позволяет вам вводить или копировать/вставлять любой текст с помощью определенных сочетаний клавиш, которые вы вводите. Например. вы можете ввести «спасибо», и приложение заменит это на «спасибо».

person Eugene Mayevski 'Callback    schedule 07.11.2010
comment
Почему? Я думаю, что может быть достаточно получить дескриптор активного окна и отправить сообщение вставки? - person Remko; 07.11.2010
comment
Вставить сообщение вставит содержимое буфера обмена. Если вы думаете, что замените содержимое буфера обмена своим текстом, вставите свой текст и поместите данные обратно в буфер обмена, подумайте еще раз: буфер обмена не обязательно должен содержать данные. Можно поместить ссылку на данные в буфер обмена, и вы не сможете правильно их сохранить. - person Eugene Mayevski 'Callback; 07.11.2010