2010-04-04 2 views
2

Фон: у моей формы есть 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; 

ответ

1

Вместо этого вы можете сделать это с помощью 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 и только hook/unhook, если она является единственной формой.

+0

Спасибо, это работает хорошо! – Steve

0

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

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

+0

Да, это не работает. – Steve

0

Ну, обе формы подписаны, чтобы получить уведомление о клавиатуре, поэтому они оба закрываются. Вам нужно ввести код, чтобы решить, «этот ESC для меня?». Может быть, вы определяете, находитесь ли вы в фокусе или нет. Если это не ваша Эскапе, тогда не закрывай.

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

+0

Привет! Вот почему я использую GetForegroundWindow (см. Код), но кажется, что иногда оба окна получают нажатия клавиш. (но не всегда, и это то, что сводит меня с ума!) Как только я обработаю нажатие клавиши, другое окно не должно его получать. Почему это происходит? Примечание. У меня есть Googled в течение нескольких часов, но не нашел лучших решений, кроме использования крючка ... – Steve

+0

@Steve - возможно, я неправильно читаю ваш код, но мне кажется, что вы проверяете только взгляды, чтобы увидеть, вы просматриваете ANY TEmailDetailsForm, а не THIS TEmailDetailsForm. Я также не понимаю, почему у вас есть этот код, а также в функции CheckInstance. Кажется избыточным и неправильным. На самом деле, это, наверное, одна из твоих проблем. CheckInstance в FormCreate кажется, что он не позволит этому экземпляру подключить клавиатуру. Зачем это? Разве каждый экземпляр не обрабатывает собственную обработку? –

+0

Привет Крис. Насколько я понимаю, KeyboardHookProc должен находиться в блоке, а не внутри класса. (это не сработало иначе) Таким образом, я должен использовать глобальные переменные (KeyboardHook: HHook), но затем каждый экземпляр класса перезаписывал бы одну и ту же глобальную переменную в FormCreate, создавая два крючка клавиатуры. Я здесь не так? – Steve