Перейти к содержанию
Fire Monkey от А до Я
  • 0

[Windows] Глобальный хук на клавиши возможно ли FMX


Просто Проги

Вопрос

Собственно сделал я  программу мини проигрователь всё вроде даже работает, но нужно переключать треки когда приложение свернуто,т.е не видно пробовал реализацию через WinApi

var
  FWnd:HWnd;

RegisterHotKey(FWnd, Ord('U'), 0, Ord('U'));

но почему то нечего не работает(

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

то же самое ошибки и ничего не происходит uses уже был прописан до этого попробовал на чистом приложении результат тот же.

ошибка такого содержания  Incompatible types: 'HWND' and 'TWinWindowHandle'

 

код.rar

Изменено пользователем Просто Проги
Ссылка на комментарий
  • 0
  • Администраторы

Потому что в FMX никакие виндовые сообщения до формы не доходят. Так как это кроссплатформенный фреймворк, где сообщения есть только на винде.

Единственный вариант, если вы хотите так делать, в разрез текущей ситуации, это можно прокинуть отправку сообщения форме. через вызов метода Form.Dispatch

Ссылка на комментарий
  • 0

Это я делал но если форма не видна то работать не будет, а мне нужно что бы при скрытой форме данное событие происходило, т.е если я скрыл проирователь но моу переключать песни через свою клавишу к примеру i

Ссылка на комментарий
  • 0

кстате забавная ситуация

 RegisterHotKey(FWnd, Ord('U'), 0, Ord('U'));

сейчас попробовал написать в браузере букву u но не получается значит клавиши назначилась осталось как то её передать форме возможно метод Form.Dispatch поможет можно поподробнее как этот метод использовать первый раз про такой метод слышу.(

Ссылка на комментарий
  • 0
  • Администраторы

Вот, посмотрите мой ответ в другой теме: Обработка WM_GETMINMAXINFO

Там же есть вариант с хуком и подменой оконной процедуры.

Ссылка на комментарий
  • 0

Спасибо,буду пробовать)

вообщем сделал всё как по примеру компилится ошибок нет но и события не происходит опять что ли handle не находит? код выглядит вот так

походу опять что то накосячил
 

Спойлер

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  {$IF Defined(WIN32) OR Defined(WIN64)}
  System.Generics.Collections, Winapi.Windows, FMX.Platform.Win, Winapi.Messages,
  {$ENDIF}
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  {$IF Defined(WIN32) OR Defined(WIN64)}
  private
   class var Callbacks: TDictionary<HWND, Pointer>;
   class constructor ClassCreate;
   class destructor ClassDestroy;
    procedure OnHotKey(var Msg: TWMHotKey); message WM_HOTKEY;
 protected
    procedure CreateHandle; override;
    procedure DestroyHandle; override;
  {$ENDIF}
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}
{$IF Defined(WIN32) OR Defined(WIN64)}

{ TfrmPersistent }
function WindowProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  frm: TCommonCustomForm;
  oldProc: Pointer;
begin
  frm := FindWindow(hwnd);
//Здесь я так понимаю происходит событие присвоения и проверка uMsg на параметр WM_GETMINMAXINFO,возможно ли здесь так же передавать кнопку горячую или сочитания ? 
  if Assigned(frm) and (uMsg = WM_GETMINMAXINFO) then
  begin
    with PMinMaxInfo(LParam)^.ptMinTrackSize, frm do
    begin
      X := 950 + Width - ClientWidth;
      Y := 500 + Height - ClientHeight;
    end;

    Result := 0;
  end else

  if TForm1.Callbacks.TryGetValue(hwnd, oldProc) and Assigned(oldProc) then
    Result := CallWindowProc(oldProc, hwnd, uMsg, wParam, lParam)
  else
    Result := DefWindowProc(hwnd, uMsg, wParam, lParam);
end;
procedure TForm1.CreateHandle;
var
  wnd: HWND;
begin
  inherited CreateHandle;

  wnd := FormToHWND(Self);

  if wnd <> 0 then
  begin
    Callbacks.Add(wnd, Ptr(GetWindowLongPtr(wnd, GWLP_WNDPROC)));

    SetWindowLongPtr(wnd, GWLP_WNDPROC, NativeInt(@WindowProc));
  end;
end;
procedure TForm1.DestroyHandle;
var
  wnd: HWND;
  oldProc: Pointer;
begin
  wnd := FormToHWND(Self);

  if (wnd <> 0) and Callbacks.TryGetValue(wnd, oldProc) then
    SetWindowLongPtr(wnd, GWLP_WNDPROC, NativeInt(oldProc));

  inherited DestroyHandle;
end;

class constructor TForm1.ClassCreate;
begin
  Callbacks := TDictionary<HWND, Pointer>.Create;
end;

class destructor TForm1.ClassDestroy;
begin
  Callbacks.Free;
end;
{$ENDIF}
procedure TForm1.OnHotKey(var Msg: TWMHotKey);
begin
   inherited;
 ShowMessage('stop');
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
// RegisterHotKey(hwnd, Ord('U'), 0, Ord('U')); //гор. клавишиа U
end;

 

Ссылка на комментарий
  • 0

Это тоже пробовал результата 0 компилится но события так и нет(

Всё спасибо всем всё заработало))

Походу рано радовался на одно событие работает, а второе нет как можно проверить что именно данный hot key был нажат
 

 if Assigned(frm) and (uMsg = WM_HOTKEY) then
  begin

ShowMessage('событие след трек');
  end;

задаю hot следующим методом

RegisterHotKey(WindowHandleToPlatform(Self.Handle).Wnd, Ord('U'), 0, Ord('U')); //регистрац. гор. клавиши U

 

Ссылка на комментарий
  • 0

а куда можно подставить проверку пробовал проверять так

if uMsg=Ord('U') then

но резултата это не принесло(

тк  umsg =WM_HOTKEY

Изменено пользователем Просто Проги
Ссылка на комментарий
  • 2

Легче всего, по моему мнению, сделать так:

...
  FWnd := AllocateHWnd(WindowProc);
...

procedure WindowProc(var AMsg: TMessage);
begin
  case AMsg.Msg of
    WM_HOTKEY:
      case TWMHotKey(AMsg).hotkey of
        1: ...;
        2: ...;
        ...
      end;
  end;
end;

...
RegisterHotkey(FWnd, ...); // как обычно в VCL
...
UnregisterHotkey(...); // как обычно в VCL
...

 

Ссылка на комментарий
  • 0

Сделал на чистом примере  так, но нечего не происходит замкнутый круг походу:blink:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,Winapi.Messages,FMX.Platform.Win,Winapi.Windows;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
  procedure WindowProc(var AMsg: TMessage);
    { Public declarations }
  end;

var
  Form1: TForm1;
  FWnd:HWND;
implementation

{$R *.fmx}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
//FWnd := WindowHandleToPlatform(Self.Handle).Wnd;
FWnd := AllocateHWnd(WindowProc);
RegisterHotKey(FWnd, Ord('U'), 0, Ord('U'));
end;

procedure TForm1.WindowProc(var AMsg: TMessage);
begin
case AMsg.Msg of
    WM_HOTKEY:
      case TWMHotKey(AMsg).hotkey of
        1: ShowMessage('Событие первого hotkey');
        2: ShowMessage('Событие первого hotkey');
      end;
  end;
end;

end.

 

Ссылка на комментарий
  • 0
  • Администраторы

Так, то что в VCL вы привыкли писать так:

procedure OnHotKey(var Msg: TWMHotKey); message WM_HOTKEY;

Это заслуга Delphi TObject.Dispatch. Суть простая, вызвав Dispatch и передав внутрь сообщение TMessage с ID, TObject автоматически найдет среди ваших методов метод, у которого WM_HOTKEY будет равен ID сообщения. Таким образом можно передавать любые варианты сообщений. Главное, чтобы первые 4 байта - это были ID сообщения. 

В VCL оконная процедура просто вызывает у формы Form.Dispatch и передает туда виндовое сообщение. Так все и работает.

В FMX другая идеология, она не редиректит сообщения из оконной процедуры в форму. Поэтому вам предложили сделать следующее:

  1. Или повесить хук на оконную процедуру и обрабатывать свои сообщения там.
  2. Либо сделать редирект сообщения, как я указал на уровне платформы.

 

Ссылка на комментарий
  • 0

 

В 10/18/2016 в 18:54, Brovin Yaroslav сказал:
  • Или повесить хук на оконную процедуру и обрабатывать свои сообщения там.
  • Либо сделать редирект сообщения, как я указал на уровне платформы.

Есть еще вариант - Заменить оконную процедуру на свою.

Второй вариант с модификацией юнита FMX.Platform.Win я бы вообще исключил, т.к. модуль поменяться в будущем и придут новые проблемы.

Вот есть вариант с хуком:

http://teran.karelia.pro/articles/item_6148.html

Ссылка на комментарий
  • 0
1 час назад, Brovin Yaroslav сказал:

Это и называется хук

Насколько я знаю хук устанавливается при помощи SetWindowsHookEx. 

А оконная процедура (WndProc ) переопределяется в своем процессе при помощи SetWindowLong и GWL_WNDPROC без каких то плясок.

Изменено пользователем ENRGY
Ссылка на комментарий
  • 0
  • Администраторы
16 минут назад, ENRGY сказал:

Насколько я знаю хук устанавливается при помощи SetWindowsHookEx. 

А оконная процедура (WndProc ) переопределяется в своем процессе при помощи SetWindowLong и GWL_WNDPROC без каких то плясок.

Простая замена не поможет. Так как придется попотеть и заново восстановить всю логику работы платформы fmx для винды. Иначе ни один контрол работать и рисоваться не будет.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...