Reputation: 7394
I'm using a home-grown translation tool. (Next time I'll use one of the libraries, as described here: delphi translation tool.)
My translators complain that translating a long list of strings is difficult because they're not seeing them in context (on the screen in which they appear.)
One translator made a great suggestion that he should be able to click on a component to change its text. I can implement this if I can find an way to hook program wide, an event so that when a user clicks on a component while holding down the CTRL key, an event handler is called. The event handler would determine if the component has a .Caption property, and if so, get the value of the Tag component (and then allow some user input.)
(Each translatable component has unique integer in its Tag properly, which I use to look up the component's .Caption.)
Any suggestions on how to go about this? It's over my head. I need something like a form's KeyPreview, but for mouse-clicks that would figure out what VCL component was clicked, and determine it's .Tag value.
Tom
EDIT:
Using David H.'s suggestion, the only events I get are when the app gets focus or loses it. What have I done wrong?
function TForm1.AppHookFunc(var Message : TMessage) : Boolean;
begin
Result := FALSE;
inc(i); outputdebugstring(Pchar(inttostr(i) + ': ' + IntTostr(Message.msg)));
if Message.Msg = WM_MBUTTONDOWN then
begin Beep;
//...DoSomething...
//Result := True;
end;
end;
procedure TForm1.FormCreate( Sender: TObject);
begin
Application.HookMainWindow(AppHookFunc);
end;
procedure TForm1.FormDestroy(
Sender: TObject);
begin
Application.UnHookMainWindow(AppHookFunc);
end;
EDIT 2
I'm almost there! But FindDragTarget seldom returns anything but nil. If I make an enormous button covering most of the control, I can sometimes get it to work. The X,Y coordinates in the tagMSG received are relative to the control. I would have though they'd relative to the form. Am I still using a different event hook than I should? Any suggestions:
procedure TForm1.ApplicationEvents1Message( var Msg: tagMSG;
var Handled: Boolean);
var
Target: TControl;
Point: TPoint;
begin
Handled := FALSE;
if (Msg.Message = WM_LBUTTONDOWN) And isAltDown then
begin
Point.X := LongRec(Msg.lParam).Lo;
Point.Y := LongRec(Msg.lParam).Hi;
Target := FindDragTarget( Point, {AllowDisabled=}TRUE);
if Assigned(Target) then
begin
if Target Is TButton then
outputdebugString(Pchar(TButton(Target).Caption));
end
else
outputdebugstring(Pchar(IntToStr(Point.X) + ', ' + IntToStr(Point.Y)));
end;
end;
FINAL EDIT:
I changed the code above to use GetCursorPos rather than Msg.lParam. It's working now. Very cool! SO Rocks!
THANK YOU BOTH FOR YOUR HELP!
Upvotes: 8
Views: 11351
Reputation: 612894
I'm assuming this is a VCL app. For FireMonkey this would not work.
Application.OnMessage
event handler.WM_LBUTTONDOWN
or perhaps WM_LBUTTONUP
and check that the modifier key state is as you desire, e.g. CTRL is down.FindDragTarget
passing the position associated with the mouse event. This will give you the control under the mouse, if indeed there is one (i.e. check for nil
).Upvotes: 10