Einzelnen Beitrag anzeigen

chrschn
(Gast)

n/a Beiträge
 
#2

DLL-Fenster erhält nicht alle Keyboard-Events?! GEHT JETZT!

  Alt 18. Nov 2004, 18:20
Ich habe es jetzt nach einigen Experimenten hinbekommen. Die Lösung baut auf dem schon geposteten Versuch auf, die Keyboard-Messages über ein TApplicationEvents-Objekt abzufangen und an das Control mit dem Focus weiterzuleiten, also sowohl an die eigenen als auch an die DLL.

Allerdings müssen dazu nicht nur die WM_KEYDOWN und WM_KEYUP-Messages weitergeleitet werden. Darüber hinaus müssen die WM_KEYDOWN-Messages noch mit TranslateMessage in eine WM_CHAR oder WM_DEADCHAR-Message umgewandelt werden, welche dann auch noch weitergeleitet werden müssen. Außerdem dürfen die Tabulator oder Enter-Taste nicht weitergeleitet werden, sonst verlieren sie ihre spezielle Funktion. Keine Idee, woran das liegen könnte.

Was jetzt funktioniert:
  • Sämtliche Zeichen können erzeugt werden, auch Akzente (Dead-Chars), [ALT GR]-Zeichen usw.
  • Pfeiltasten, Home, End, PgUp, PgDn usw. können erzeugt werden
  • Die Hostanwendung funktioniert nach meiner Beobachtung genauso wie vorher ([Tab]: Focuswechsel, Return: Default-Button, [ALT]+MenuAccel: Tastenkürzel, ...)
Was allerdings (noch) nicht funktioniert:
  • [TAB] innerhalb des DLL-Fensters wechselt nicht den Focus innerhalb desselben, sondern springt zum nächsten Control der Hostanwendung
  • Der Focuswechsel durch [TAB] in der Hostanwendung überspringt das DLL-Fenster
  • MenuAccels im DLL-Fenster funktionieren nicht, also z. B. Button-Captions wie '&OK' können nicht mit [ALT]+[O] aktiviert werden
Mit diesen Einschränkunten kann ich allerdings erstmal leben .

Um die Tabulator-Geschichte hinzubiegen, kam mir schon folgende Idee: Man könnte das Panel in den Focuswechsel mit einbeziehen (TPanel.TabStop := True) und sich das Handle des aktuell angezeigten DLL-Fensters von selbiger erfragen. Dann kann man im TPanel.OnEnter-Event-Handler das Fenster per Windows-API aktivieren, mit SetFocus(HandleOfCurrentDLL). Aber für weitere Experimente habe ich immo leider keine Zeit. Falls es jemand ausprobiert, bitte (Miss-)Erfolgsbereichte hier posten 8)

Hier nun der Code für das TApplicationEvents.OnMessage in der Hostanwendung:
Delphi-Quellcode:
procedure TConfigForm.ApplicationKeyboardEventsMessage(var Msg: tagMSG;
  var Handled: Boolean);
const
  DONT_FORWARD_KEYS: set of Byte = [VK_RETURN, VK_TAB];

var
  Handle: THandle;
  VKey: Byte;
begin
  // This event handler forwards the keyboard events to the DLL window.
  // Without it some keys would not be sent to the DLL window. This seems
  // to be an issue of either Delphi or the Windows message handling.
  case Msg.message of
    WM_KEYDOWN:
      begin
        // Translate the virutal key into a character key (0..255)
        VKey := Lo(MapVirtualKey(Msg.wParam, 2));
        // If no translation has to be made, MapVirtualKey returns 0.
        if (VKey = 0) then VKey := Lo(Msg.wParam);
        // Don't handle the DONT_FORWARD_KEYS keys as they have special
        // functions and must be handled by the application itself.
        if not (VKey in DONT_FORWARD_KEYS) then
          begin
            // Get current focused control
            Handle := GetFocus;
            // Forward the message to it
            SendMessage(Handle, Msg.message, Msg.wParam, Msg.lParam);
            // Process message by translating the WM_KEYUP message into a
            // WM_CHAR message.
            Handled := TranslateMessage(Msg);
          end;
      end;

    WM_KEYUP:
      begin
        // Translate the virutal key into a character key (0..255)
        VKey := Lo(MapVirtualKey(Msg.wParam, 2));
        // If no translation has to be made, MapVirtualKey returns 0.
        if (VKey = 0) then VKey := Lo(Msg.wParam);
        // Don't handle the DONT_FORWARD_KEYS keys as they have special
        // functions and must be handled by the application itself.
        if not (VKey in DONT_FORWARD_KEYS) then
          begin
            // Get current focused control
            Handle := GetFocus;
            // Forward the message to it
            SendMessage(Handle, Msg.message, Msg.wParam, Msg.lParam);
            Handled := True;
          end;
      end;

    WM_DEADCHAR,
    WM_CHAR:
      begin
        VKey := Msg.wParam;
        // Don't handle the DONT_FORWARD_KEYS keys as they have special
        // functions and must be handled by the application itself.
        if not (VKey in DONT_FORWARD_KEYS) then
          begin
            // Get current focused control
            Handle := GetFocus;
            // Forward the message to it
            SendMessage(Handle, Msg.message, Msg.wParam, Msg.lParam);
            Handled := True;
          end;
      end;
  end;
end;
Gruß,
Christian
  Mit Zitat antworten Zitat