title: Catch a mouse click on any VCL component, and determine its .Tag value
body: <p>I'm using a home-grown translation tool. (Next time I'll use one of the libraries, as described here: <a href="https://stackoverflow.com/questions/7056098/delphi-translation-tool">delphi translation tool</a>.)</p>
  
  <p>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.)</p>
  
  <p>One translator made a great suggestion that he should be able to click on a component to change its text.  I can implement this <strong>if</strong> 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.)</p>
  
  <p>(Each translatable component has unique integer in its Tag properly, which I use to look up the component's .Caption.)</p>
  
  <p>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.</p>
  
  <p>Tom</p>
  
  <p>EDIT:</p>
  
  <p>Using David H.'s suggestion, the only events I get are when the app gets focus or loses it. What have I done wrong?</p>
  
  <pre><code>    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;
  </code></pre>
  
  <p>EDIT 2</p>
  
  <p>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:</p>
  
  <pre><code>  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;
  </code></pre>
  
  <p>FINAL EDIT:</p>
  
  <p>I changed the code above to use GetCursorPos rather than Msg.lParam.  It's working now. Very cool!  SO Rocks!</p>
  
  <p>THANK YOU BOTH FOR YOUR HELP!</p>