Solved

how to prevent focus changing?

Posted on 2002-06-18
13
1,415 Views
Last Modified: 2010-04-04
I have a Delphi app with a single edit control on a form.

I have second app with a single button on it.

I set the input focus to the edit control. When I click the button, I want to put "A" (or whatever) in the edit box.

This is easy to do, except:
I don't want the edit control to lose focus,
and I may have multiple apps with edit controls running, or a form may have multiple edit controls on it.

In any case, the app with the button needs to send the "A" to the edit control that has focus (assume an edit control always has the focus when the button is pressed), regardless of which form or application it resides in.

At runtime, I don't know or care about window titles, appnames or whatever. I just want to send a keystroke to the focused edit control, and leave it focused.

TIA.
0
Comment
Question by:mullet_attack
  • 6
  • 3
  • 2
  • +2
13 Comments
 
LVL 17

Expert Comment

by:geobul
ID: 7091999
Hi,
In order to demonstrate how it works I've put the code in a Timer.OnTimer event. The reason is that if you press a button on app B then the current active app A will lose the focus.
-----
procedure SendToApp(h:HWND; what:string);
begin
  SendMessage(h,wm_setText,0,Integer(what));
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  h1, h2: HWND;
  buf: string;
begin
  h1 := GetForegroundWindow(); // Get active window
  if IsWindow(h1) then begin
    // Associate the input of the active window
    if AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(h1, nil) ,true) then begin
      h2 := GetFocus; // Get the focused control
      if IsWindow(h2) then begin
        SetLength(buf,10);
        GetClassName(h2, PChar(buf), 11);
        // Check if it's a TEdit and assign the text
        if Trim(buf) = 'TEdit' then SendToApp(h2,'Hello');
      end;
      AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(h1, nil) ,false)
    end;
  end;
end;
-----
Regards, Geo
0
 

Expert Comment

by:penich
ID: 7092118
I think i will not say something new but you can do the following to do it faster.

1. If app which contains Edit's shoudl have special message method
For example :
{
....
const
  FU_UPDATEEDIT = WM_USER + 20;
...
    procedure FUUpdateFocus(var Message: TMessage); message FU_UPDATEEDIT;
}

2. Each time you need to pass some text into other app you will just generate your own message for all windows in your system.
Message may contain for example the name  of the Edit control and text to pass.

In this case you will have common mechanism for all app's in your enrinonment

good luck
0
 
LVL 9

Expert Comment

by:ginsonic
ID: 7092461
procedure TForm1.FormCreate(Sender: TObject);
begin
 h:=Edit1.Handle;
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
Windows.SetFocus(H);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text:='KO';
end;

I give you a sample for a single application. All what have to do is to get the edit box handle .
0
 
LVL 2

Author Comment

by:mullet_attack
ID: 7092698
thanx for your suggestions, but none of these ideas are appropriate, unfortunately.

The app that receives the characters may not be a Delphi app, i just used that as an example. It could be M$ Word, notepad etc, in fact any app that could normally receive keyboard characters.

check out

http://www.rjcooper.com/onscreen/index.html

for a product called "OnScreen" that provides an on-screen keyboard. It does exactly what I want, except I need to do it with a single button only.
0
 
LVL 17

Expert Comment

by:geobul
ID: 7092813
Well...

    if IsWindow(h2) then begin
//       SetLength(buf,10);
//       GetClassName(h2, PChar(buf), 11);
       // Check if it's a TEdit and assign the text
//       if Trim(buf) = 'TEdit' then
       SendToApp(h2,'Hello');
     end;

Regards, Geo
0
 
LVL 2

Author Comment

by:mullet_attack
ID: 7095286
thanks again, but the crutial ingredient is missing - the button click.

The problem is the button click takes the focus, and that is what I don't want to happen. The focus _must_ stay where it is when the button is clicked.

0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Expert Comment

by:penich
ID: 7095298
He he ;))
You should've said "it should look like focus is still there"
;)
0
 
LVL 17

Expert Comment

by:geobul
ID: 7095447
Open two notepad instances, run the app below and enjoy. There are a timer and two buttons on a form. Set timer interval to 100 for example. Set the focus to one of the notepad windows and press one of the buttons here. Btn1 sends 'A' and Btn2 sends 'B' to notepad. Select the other notepad and try again. Notepad windows do not lose their focus.
---
type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  CurrentWindow, CurrentControl: HWND;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  CurrentWindow := 0;
  CurrentControl := 0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
 h: HWND;
begin
 h := GetForegroundWindow;
 if IsWindow(h) then begin
   if Application.MainForm.Handle <> h then begin
     CurrentWindow := h;
     if AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(h, nil) ,true) then begin
       try
         CurrentControl := GetFocus; // Get the focused control
       finally
         AttachThreadInput(GetCurrentThreadId, GetWindowThreadProcessId(h, nil), false)
       end;
     end;
   end;
 end;
end;

function AddToWindowText(h:HWND; what:string) : boolean;
var
 buf : string;
 NewStr : string;
 len : integer;
begin
 result := true;
 try
   len := SendMessage(h,wm_getTextLength,0,0);
   SetLength(buf,len);
   SendMessage(h,wm_getText,len+1,Integer(buf));
   NewStr := buf + what;
   SendMessage(h,wm_setText,0,Integer(NewStr));
 except
   result := false;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if CurrentControl <> 0 then AddToWindowText(CurrentControl,'A');
  if CurrentWindow <> 0 then SetForegroundWindow(CurrentWindow);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if CurrentControl <> 0 then AddToWindowText(CurrentControl,'B');
  if CurrentWindow <> 0 then SetForegroundWindow(CurrentWindow);
end;

end.
---
Regards, Geo
0
 
LVL 2

Author Comment

by:mullet_attack
ID: 7095910
Geo, thanx again, but....

The Notepad still loses focus, although successive chars are sent to it. I suggest you put more than one page of text into notepad, and then try adding to it. The pages scroll to the top when the notepad loses focus.

Please dl the "Onscreen" app I mentioned earlier, and you will get a good idea of how I want it to work.

Increasing points to 300. Is that a limit or can I offer say 1000 points simply because I need an answer?
0
 
LVL 17

Accepted Solution

by:
geobul earned 300 total points
ID: 7098310
I finally got the idea:

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    btnA: TButton;
    btnB: TButton;
    btnShift: TSpeedButton;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure SendKey(Key: byte);
    procedure btnAClick(Sender: TObject);
    procedure btnBClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  CurrentWindow: HWND;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  CurrentWindow := 0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
 h: HWND;
begin
 h := GetForegroundWindow;
 if IsWindow(h) then begin
   if Application.MainForm.Handle <> h then begin
     CurrentWindow := h;
   end;
 end;
end;

procedure TForm1.SendKey(Key: byte);
begin
   if CurrentWindow <> 0 then begin
    SetForegroundWindow(CurrentWindow);
    if btnShift.Down then keybd_event(VK_SHIFT, 0, 0, 0);
    keybd_event(Key, 0, 0, 0);
    keybd_event(Key, 0, KEYEVENTF_KEYUP, 0);
    if btnShift.Down then keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
  end;
end;

procedure TForm1.btnAClick(Sender: TObject);
begin
  SendKey($41);
end;

procedure TForm1.btnBClick(Sender: TObject);
begin
  SendKey($42);
end;

Regards, Geo
0
 
LVL 17

Expert Comment

by:geobul
ID: 7098372
Forgot to say:
btnShift.AllowAllUp := true;
btnShift.GroupIndex := 1;
0
 
LVL 17

Expert Comment

by:geobul
ID: 7098385
I'm sorry, one more thing I've forgotten:

procedure TForm1.btnShiftClick(Sender: TObject);
begin
  if CurrentWindow <> 0 then SetForegroundWindow(CurrentWindow);
end;

And how to implement 'Enter' key:

procedure TForm1.btnEnterClick(Sender: TObject);
begin
  SendKey(VK_RETURN);
end;

Regards, Geo
0
 

Expert Comment

by:CleanupPing
ID: 9343182
mullet_attack:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now