This is doable if you want to change the VCL code.
KeyPreview is handled by the TWinControl.DoKeyDown method. As you can see from the code that has focus, it will look for its parent form and call its DoKeyDown method if KeyPreview enabled.
function TWinControl.DoKeyDown(var Message: TWMKey): Boolean; var ShiftState: TShiftState; Form, FormParent: TCustomForm; LCharCode: Word; begin Result := True;
To change this behavior, you need to either change the TWinControl.DoKeyDown code to scan frames, or intercept WM_KEYDOWN and WM_SYSKEYDOWN for each TWinControl descendant you want to use, and finally add the KeyPreview field to the base class.
Probably the best option would be to declare the IKeyPreview interface when scanning for parent forms / frames, if the parent implements this interface. If you do not find them, you can return to the source code. This will contain VCL code changes only for the TWinControl.DoKeyDown method, and you can easily implement the interface in frames where necessary.
Note. A Windows control that focuses on key events. Therefore, a frame could be found above the modifications only if some of its controls have focus. Regardless of whether the mouse is above the frame or not, this will not affect the functionality.
A more detailed code would look like this:
The definition of the interface that Frame should have implemented:
IKeyPreview = interface ['{D7318B16-04FF-43BE-8E99-6BE8663827EE}'] function GetKeyPreview: boolean; property KeyPreview: boolean read GetKeyPreview; end;
The search function for the parent frame that implements the IKeyPreview interface should be placed somewhere in the Vcl.Controls section:
function GetParentKeyPreview(Control: TWinControl): IKeyPreview; var Parent: TWinControl; begin Result := nil; Parent := Control.Parent; while Assigned(Parent) do begin if Parent is TCustomForm then Parent := nil else if Supports(Parent, IKeyPreview, Result) then Parent := nil else Parent := Parent.Parent; end; end;
TWinControl.DoKeyDown modification (paste into source code):
var PreviewParent: IKeyPreview; PreviewParent := GetParentKeyPreview(Self); if PreviewParent <> nil then begin if PreviewParent.KeyPreview and TWinControl(PreviewParent).DoKeyDown(Message) then Exit; end;