Kenny Channels
Kenny Channels

Reputation: 23

Can not press enter in more than one twebbrowser

I have seen the below msghandler code in several places now as the solution to not being able to press Enter in a twebbrowser. This solution does work as long as you're only dealing with one twebbrowser. I've provided a complete unit here for discussion. If you take two twebbrowsers and make one of them the "active" browser (see code) and navigate them each to a site for example that has a username, password and button you can enter the data in the "active" browser and press Enter successfully. If you try to use the non "active" browser not only can you not press Enter but use of tab fails as well. Whichever browser you press Enter in first is the one that will continue to work so it seems to have nothing to do with order of creation of the browsers.

How do I make my additional browsers function?

unit Main_Form;

interface

uses
    Winapi.Windows, Winapi.Messages, Vcl.Controls, Vcl.Forms,
    ActiveX, Vcl.OleCtrls, SHDocVw, System.Classes, Vcl.StdCtrls;

type
    TForm1 = class(TForm)
        NavigateBrowsers: TButton;
        WebBrowser1: TWebBrowser;
        WebBrowser2: TWebBrowser;
        MakeBrowser1Active: TButton;
        MakeBrowser2Active: TButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormDeactivate(Sender: TObject);
        procedure NavigateBrowsersClick(Sender: TObject);
        procedure MakeBrowser1ActiveClick(Sender: TObject);
        procedure MakeBrowser2ActiveClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
         procedure MsgHandler(var Msg: TMsg; var Handled: Boolean);
      end;

var
  Form1: TForm1;
  ActiveBrowser: TWebBrowser;
  FOleInPlaceActiveObject: IOleInPlaceActiveObject;
  SaveMessageHandler: TMessageEvent;

implementation

{$R *.dfm}

procedure TForm1.MakeBrowser1ActiveClick(Sender: TObject);
begin
  ActiveBrowser := WebBrowser1;
end;

procedure TForm1.MakeBrowser2ActiveClick(Sender: TObject);
begin
  ActiveBrowser := WebBrowser2;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Application.OnMessage := SaveMessageHandler;
  FOleInPlaceActiveObject := nil;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Handle messages
  SaveMessageHandler := Application.OnMessage;
  Application.OnMessage := MsgHandler;
end;

procedure TForm1.FormDeactivate(Sender: TObject);
begin
  Application.OnMessage := SaveMessageHandler;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FOleInPlaceActiveObject := nil;
end;

procedure TForm1.NavigateBrowsersClick(Sender: TObject);
begin
  WebBrowser1.Navigate(''); //supply own
  WebBrowser2.Navigate(''); //supply own
end;

procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
const
  StdKeys = [VK_BACK, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT];
var
  IOIPAO: IOleInPlaceActiveObject;
  Dispatch: IDispatch;
begin
  //Exit if webbrowser object is nil
  if ActiveBrowser = nil then
    begin
      Handled := False;
      Exit;
    end;
  Handled:=(IsDialogMessage(ActiveBrowser.Handle, Msg) = True);
  if (Handled) and (not ActiveBrowser.Busy) then
    begin
      if FOleInPlaceActiveObject = nil then
        begin
          Dispatch := ActiveBrowser.Application;
          if Dispatch <>nil then
            begin
              Dispatch.QueryInterface(IOleInPlaceActiveObject, iOIPAO);
              if iOIPAO <>nil then
                FOleInPlaceActiveObject := iOIPAO;
            end;
        end;
        if FOleInPlaceActiveObject <>nil then
          if ((Msg.message = WM_KEYDOWN) or (Msg.message = WM_KEYUP)) and
            (Msg.wParam in StdKeys) then
              //nothing - do not pass on StdKeys
          else
            FOleInPlaceActiveObject.TranslateAccelerator(Msg);
    end;
end;

initialization
OleInitialize(nil);

finalization
OleUninitialize;

end.

Upvotes: 2

Views: 943

Answers (2)

Kenny Channels
Kenny Channels

Reputation: 23

After days of searching for an answer it appears I have found something that works the same day I posted the question here. Go figure! For everyone's benefit, here is what worked.

All I had to do was assign the browser as the active control when either the user changed tabs or at the time of new tab creation. The reason for the count check in the pagecontrolchange procedure is to keep from getting a list index out of bounds on initial tab creation at startup. I do realize I probably need to change my ObjectLists over to Generics, ;)

procedure TForm1.PageControl1Change(Sender: TObject);
    begin
      if PageControl1.PageCount = MyBrowsersObjectList.Count then // Not adding a page
        begin
          ActiveBrowser := MyBrowsersObjectList[PageControl1.ActivePageIndex] as TWebBrowser;
          ActiveControl := ActiveBrowser;
        end;
    end;

procedure TForm1.CreateBrowserTab(APage: TAdvOfficePage; NavigateTo: String);
    begin
      APage.Caption := 'Loading...';
      ActiveBrowser := TWebBrowser.Create(nil);
      MyBrowsersObjectList.Add(ActiveBrowser);
      TControl(ActiveBrowser).Parent := APage;
      ActiveBrowser.Align := alClient;
      ActiveBrowser.RegisterAsBrowser := True;
      ActiveBrowser.Tag := BrowserTabs.ActivePageIndex;
      ActiveBrowser.Navigate(NavigateTo);
      ActiveControl := ActiveBrowser;
    end;

Upvotes: 0

whosrdaddy
whosrdaddy

Reputation: 11860

I faced the same problem as you and I use a similar message handler, FOleInPlaceActiveObject is not really needed:

procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean);
const
  StdKeys = [VK_BACK, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT];
var
  IOIPAO: IOleInPlaceActiveObject;

begin
 try  
  if Assigned(ActiveBrowser) then
  begin
   Handled:=(IsDialogMessage(ActiveBrowser.Handle, Msg) = True);
   if Handled then
    begin
     if ((Msg.message = WM_KEYDOWN) or (Msg.message = WM_KEYUP)) and (Msg.wParam in StdKeys) then
      begin
       //nothing  -  do not pass on Backspace, Left, Right, Up, Down arrows
      end
     else
      begin
       IOIPAO := (ActiveBrowser.Application as IOleInPlaceActiveObject);
       if Assigned(IOIPAO)then
        IOIPAO.TranslateAccelerator(Msg)
      end;               
    end;
  end;
 except
  Handled := False;
 end;    
end;

Upvotes: 1

Related Questions