i: I want to thank everyone who took the time to read my posts and especially those who posted.
Thank you one and all.
ii (small off-topic excursion):
@RAW you know you can even write the bestest ever "Hello Solar System" app, I'm still way above. I won the 42-annually award of last "42 and beyond" for writing the best "Hello Multiverse and all Alternative Timelines" app. It will be included in the next revision of the hitchhiker's guide. Wanna see you beating that one ;p
Seriously tho, thanks for your vote of confidence, truth be told I'm close, but I have some issues yet to solve.
iii (and back on-topic) (sigh):
So
I'm building a component. Therefore I will refrain from using any members/methods/handlers exposed (published) by other components for design-time use.
I will, for example, never use Tag or OnClick from inside a component, since those are there to be used by component users (devs) and can, and at times will, change at runtime by the application.
For example, lets say im writing a tStringGrid descendant and I want to catch the new control's PageUp and PageDown keys and change their behavior.
It would be wrong to assign a handler to the OnKeyDown notification event. That one is exposed to be used by the people who will use my new component.
Instead I should (and would) override my ancestor's KeyDown virtual method, where I do what needs doing and also make sure to call the inherited KeyDown to maintain the method's execution chain.
Now here, in this component, I need a way to monitor a plethora of other controls, which I am not a descendant of.
IMHO the only reasonable way of doing that is to hook into each control's messaging procedure.
(NOTE: if anyone has a better approach plase by all means, speak up and thank you kindly)
This is the basic handler every TControl + descendats have and the most centralized way of intercepting requests that controls have to respond/react to, be it PostMessage or SendMessage etc....
AFAIK all messages are routed though this method (except perhaps those issued through Perform? Q.Q)
I wrote a FocusTracker component that maintains an internal list of objects, one for every tWinControl on the form.
Each of those objects hooks into the WindowProc queue of said tWincontrol and so can monitor CM_ENTER messages and report them back to the FocusTracker, who exposes the last activated control (the one that was active bofore the current ActiveControl) and fires a notification event.
Let me introduce the
WndProc or
WindowProc.
Now, for all (me included) who feel the academic approach to be vastly inferior to a hands-on code example, here's a striped down to bare essentials (for simplicity) of the trackedItem's constructor and destructor methods:
constructor TndFocusTrackedItem.Create(p_FocusTracker:TndFocusTracker;p_TrackedControl:TWinControl);
begin
focus_tracker:=p_FocusTracker; // remember whom I report to: this is the owner of the list I am an item of .
tracked_control:=p_TrackedControl; // the tWinControl I am tracking
origiinalWindowProc:=tracked_control.WindowProc; // backup my tracked tWinControl's original WindowProc
tracked_control.WindowProc:=@TrackedWindowProc; // set a new WindowProc to my tracked tWinControl
end;
destructor TndFocusTrackedItem.Destroy;
begin
if assigned(tracked_control) then tracked_control.WindowProc:=origiinalWindowProc; // reset original WindowProc setting
inherited;
end;
The trackedItem has only 1 more method: The actual WindowProc it has set it's tracked tWinControl to point to, and here's an example:
procedure TndFocusTrackedItem.TrackedWindowProc(var p_Message:TLMessage);
begin
if p_Message.msg=CM_ENTER then ; // report to my focusTracker master: a control just received focus
//
if p_Message.msg=LM_LBUTTONDOWN then ; // report to my focusTracker master: a control got clicked on
//
if p_Message.msg=LM_KEYDOWN then ; // report to my focusTracker master: a Key just got pressed
//
origiinalWindowProc(p_Message); // this was the original WindowProc of the TWinControl I'm tracking .
// before I highjacked it and set it to point to TrackedWindowProc
// so make sure I call the original
end;
And that mostly outlines the premise.
As stated before, I already had the focus shifting solved.
(!) LM_LBUTTONDOWN may cover the mouse clicks, or may not, since I get both a CM_ENTER followed by a LM_LBUTTONDOWN in that order, whereas I would love to know the click before the focus shift. I may have to find a way to delay the focus shifting until I register the click??
(!) Another tricky part is to decode the TLMessage fields to get the actuall keyboard states.
I'm fairly certain there's a better, more sophisticated way of handling the current task, but alas this is as far as my knowledge can carry me.
And that mostly outlines my current demons.
Also whoever made it through the entire monster-of-a-post, you rock \o/