Проблема с подключением клавиатуры - PullRequest
2 голосов
/ 05 апреля 2010

Фон: моя форма имеет TWebBrowser. Я хочу закрыть форму с помощью ESC, но TWebBrowser ест нажатия клавиш - поэтому я решил пойти с помощью клавиатуры.

Проблема в том, что Форма может быть открыта одновременно в нескольких экземплярах.

Что бы я ни делал, в некоторых ситуациях, если в моей форме открыты два экземпляра, закрытие одного из них также закрывает другой.

Я приложил пример кода. Любые идеи о том, что вызывает проблему?

var
  EmailDetailsForm: TEmailDetailsForm;
  KeyboardHook: HHook;

implementation

function KeyboardHookProc(Code: Integer; wParam, lParam: LongInt): LongInt; stdcall;
var
  hWnd: THandle;
  I: Integer;
  F: TForm;
begin
  if Code < 0 then
    Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam)
  else begin
    case wParam of
      VK_ESCAPE:  
        if (lParam and $80000000) <> $00000000 then
        begin
          hWnd := GetForegroundWindow;
          for I := 0 to Screen.FormCount - 1 do
          begin
            F := Screen.Forms[I];
            if F.Handle = hWnd then
              if F is TEmailDetailsForm then
              begin
                PostMessage(hWnd, WM_CLOSE, 0, 0);
                Result := HC_SKIP;
                break;
              end;
          end; //for
        end; //if
      else
        Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam);
    end;  //case
  end;  //if
end;

function TEmailDetailsForm.CheckInstance: Boolean;
var
  I, J: Integer;
  F: TForm;
begin
  Result := false;

  J := 0;

  for I := 0 to Screen.FormCount - 1 do
  begin
    F := Screen.Forms[I];
    if F is TEmailDetailsForm then
    begin
      J := J + 1;
      if J = 2 then
      begin
        Result := true;
        break;
      end;
    end;
  end;
end;

procedure TEmailDetailsForm.FormCreate(Sender: TObject);
begin
    if not CheckInstance then    
      KeyboardHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc, 0, GetCurrentThreadId());
end;

procedure TEmailDetailsForm.FormDestroy(Sender: TObject);
begin
    if not CheckInstance then
      UnHookWindowsHookEx(KeyboardHook);
end;

Ответы [ 3 ]

1 голос
/ 05 апреля 2010

Вы можете сделать это с помощью TApplicationEvents.OnMessage. Удалите компонент TApplicationEvents в главной форме приложения с помощью этого кода:

procedure TMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  C: TControl;
  H: HWND;
begin
  if (Msg.message = WM_KEYDOWN) and (Msg.wParam = VK_ESCAPE) then begin
    H := Msg.hwnd;
    while GetParent(H) <> 0 do
      H := GetParent(H);
    C := FindControl(H);
    if C is TEmailDetailsForm then begin
      TEmailDetailsForm(C).Close;
      Handled := True;
    end;
  end;
end;

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

0 голосов
/ 05 апреля 2010

Итак, обе формы подписаны на получение уведомления от клавиатуры, поэтому они закрываются. Вы должны поместить туда код, чтобы решить, "это ESC для меня?" Может быть, определив, у вас окно с фокусом или нет. Если это не ваш ESCape, не закрывайте.

Но все это выглядит довольно радикально. Должен быть более простой, ненавязчивый способ обнаружения ESC в ЭТОМ ПРИЛОЖЕНИИ, без необходимости мониторинга клавиатуры для всей системы.

0 голосов
/ 05 апреля 2010

Фон: моя форма имеет TWebBrowser. Я хочу закрыть форму с ESC, но TWebBrowser ест нажатия клавиш - поэтому я решил пойти с крючок для клавиатуры.

Возможно, есть более простое решение. Вы пытались установить для свойства KeyPreview формы значение True?

...