Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.

How to set focus to / set caret into input field

Post Reply
Lu53
Posts: 8
Joined: Mon Jan 20, 2020 1:02 pm

How to set focus to / set caret into input field

Post by Lu53 »

I know this issue has been discussed many times, but still I cant get it to work. I think I tried every suggestion from every forum but still my input field does not get "a blinking caret" in it, such that the user just can start typing.

I already tried:

A)

Code: Select all

Javascript: 
element.focus(); 
This is nicely scrolling my web page such that the input field gets visible. But no caret blinking in field.

B)

Code: Select all

Javascript:
element.focus(); 

Followed by Delphi: 
MyForm.ActiveControl := CEFWindowParent1;
MyForm.Chromium1.SetFocus(True);
Still no caret blinking in field.

C)

Code: Select all

Javascript: 
element.focus(); 
var Pos = element.getBoundingClientRect(); 
and returning Pos.x and Pos.y to Delphi

Followed by Delphi: 
Var MouseEvent: TCefMouseEvent;
MouseEvent.x := X+5;
MouseEvent.y := Y+5;
Chromium1.Browser.Host.SendFocusEvent(true);
Chromium1.Browser.Host.SendMouseClickEvent(PCefMouseEvent(@MouseEvent), MBT_LEFT, false, 1);
Chromium1.Browser.Host.SendMouseClickEvent(PCefMouseEvent(@MouseEvent), MBT_LEFT, true, 1);
Still no caret blinking in field.

Using MBT_RIGHT I can see I'm on the right track because a popup menu shows up nicely in the upper left corner of the input field.

It can't be that complicated, but obviously I'm missing the obvious.

Any help would be very much appreciated.

Many thanks, Lu53
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: How to set focus to / set caret into input field

Post by salvadordf »

Hi,

I modified the SimpleBrowser2 demo to test this and I added another button with this code :

Code: Select all

  ActiveControl := CEFWindowParent1;
  Chromium1.ExecuteJavaScript('document.getElementById("auxEdt").focus();', 'about:blank', 0);
I loaded my contact form here : https://www.briskbard.com/index.php?lan ... =emailgnrl

When I run the demo and clicked the button the focus went to the email input element as expected.

...however...

If I load this page : https://mdbootstrap.com/docs/jquery/forms/contact/
and I try this code :

Code: Select all

  ActiveControl := CEFWindowParent1;
  Chromium1.ExecuteJavaScript('document.getElementById("email").focus();', 'about:blank', 0);
Then it doesn't work and the "email" input doesn't show the caret.

Something else in that page is stealing the focus and perhaps this is what's happening to you too.

The second answer of this question may have some clues :
https://stackoverflow.com/questions/108 ... t/10894719
Lu53
Posts: 8
Joined: Mon Jan 20, 2020 1:02 pm

Re: How to set focus to / set caret into input field

Post by Lu53 »

Dear Salvador,

thank you very much for your instant reply and all your good work here!

Indeed your example using Simplebrowser2 and your website works. I then checked the differences between my Delphi code and yours and found out I had a Result := True in the TMainForm.Chromium1SetFocus() event handler. Not sure why and when I put that in there, but in fact that inhibits the caret to show in the field. Still unclear to me though as to what to put in the Result and when, but returning False or nothing just works for me now.

Thank you for pointing me in the right direction!

Kind regards
Lu
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: How to set focus to / set caret into input field

Post by salvadordf »

Here you have the documentation for that event :
https://magpcss.org/ceforum/apidocs3/pr ... ndler.html
Lu53
Posts: 8
Joined: Mon Jan 20, 2020 1:02 pm

Re: How to set focus to / set caret into input field

Post by Lu53 »

Thank you for the link!
That documentation there is overwhelming!
Lu53
Posts: 8
Joined: Mon Jan 20, 2020 1:02 pm

Re: How to set focus to / set caret into input field

Post by Lu53 »

Here is some additional finding on that issue. I could'nt believe it was THAT stupid by me....

Just writing

Code: Select all

ActiveControl := CEFWindowParent1;
Chromium1.ExecuteJavaScript('document.getElementById("auxEdt").focus();', 'about:blank', 0);
works with Result := False in the TMainForm.Chromium1SetFocus() handler. But what in fact I'm doing is a little more complex. Instead of just "firing&forget" the Chromium1.ExecuteJavaScript() call, I embed each function I wish to execute (focus() here) into something like this:

Code: Select all

try {
 var El = document.getElementById("<some id here>");
 var Res = (El!=null);
 if (Res) { El.focus(); }
 myextension.ReturnToDelphi(6, Res);
} catch(err) { 
 myextension.ReturnToDelphi(6, false, "RMSG", err.message);
}
with a registered "ReturnToDelphi" extension and waiting for the response via OnBrowserMessage(). The waiting is a timed WaitLock in a separate thread on an event that gets set when the OnBrowserMessage() arrives. So I'm not blocking the main thread or any other threads at all.

Now, with having Result := False in the TMainForm.Chromium1SetFocus() handler, the problem is that the response through OnBrowserMessage() times out!! When I first was at that point some days ago, I found by try&error that having Result := True in the TMainForm.Chromium1SetFocus() circumvents this issue, i.e. the awaited OnBrowserMessage() came in. Therefore I had that True there...

Now, with False back again in TMainForm.Chromium1SetFocus() that timeout issue is back. The solution to this seems to be doing some Application.ProcessMessages; Sleep(1); loops between ActiveControl := CEFWindowParent1 and executing the JS code for some milliseconds.

It seems to me there is some deadlock when having False in TMainForm.Chromium1SetFocus() and not doing some main thread Application.ProcessMessages after an ActiveControl := CEFWindowParent1.

I am fine with that Application.ProcessMessages solution, but you might be interested in searching a little deeper to see whats causing the deadlock there. Just for curiousity...

Regards, Lu
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: How to set focus to / set caret into input field

Post by salvadordf »

There is an issue with process messages in CEF that might be what you experience :
https://bitbucket.org/chromiumembedded/ ... process-to

Try setting GlobalCEFApp.DisableSiteIsolationTrials to True before the GlobalCEFApp.StartMainProcess call in the DPR file to see if that solves your problem.
Lu53
Posts: 8
Joined: Mon Jan 20, 2020 1:02 pm

Re: How to set focus to / set caret into input field

Post by Lu53 »

Uuh, that CEF stuff is way too high for me...
But thank you for the link!

I tried GlobalCEFApp.DisableSiteIsolationTrials := True as suggested but it didn't change anything. Still get no OnBrowserMessage if I dont' do some Application.ProcessMessages after ActiveControl := CEFWindowParent1.

But anyways, as long as it works with some Application.ProcessMessages calls I'm fine.

EDIT: I was able to further narrow down the problem.

Code: Select all

Type TMainForm = Class...
 FGotFocus : Boolean;

Procedure TMainForm.Chromium1GotFocus(Sender: TObject; const browser: ICefBrowser);
Begin
 // This is called from foreign thread!
 FGotFocus := True;  
End;

Procedure TMainForm.Button5Click(Sender: TObject);
Begin
 // I want to make sure the browser window is focused
 // This is in the main VCL thread
 If ActiveControl<>CEFWindowParent1 then
  Begin
   FGotFocus := False;  
   ActiveControl := CEFWindowParent1;
   Repeat
    Sleep(1);
    Application.ProcessMessages;
   Until FGotFocus;
  End;
 
 // Continue...
End;
When I wait this way for the Chromium1GotFocus(), the wait time is limited to the minimum necessary and the problem with no more receiving any OnBrowserMessage() does not occur.
Post Reply