VBA Use FireEvent or something to fire KeyPress event to send Enter Key to input[type='text']

Dear Experts,

I'm always running into this issue with websites that drives me insane. I use VBA to automate IE, and the current system I'm using is IE11 but sometimes in the office we also use as low as IE9.

My goal is very simple. Anytime there is a textbox which has an event that is triggered by the keyup, keydown or keypress events, and I need to simulate a keypress. Often, that is the only way to make the controls accept the values or even fire the events.

Currently, I've gotten around this by using extremely complicated windows api, where I grab the handle to the ie window, bring it to the front, set the focus on the textbox, and use a class I wrote which is better than sendkeys but does the same thing, in order to send the enter key to it. This sucks though because any programs I do this with have to run in the foreground with the focus and you can't do anything else while it's running and automating IE.

What I would love to do is either of these two approaches, but I can't figure either one out.

Using the .fireevent function on a htmlinputelement, for example, to send the enter key to the htmlelement.

Or somehow fire a java function which creates the keyboard event and sends it to the field in question so it's like I hit the enter key in it.

I'd really like to know how to use the .fireevent() func to do it, but I haven't been able to find any documentation on the web anywhere for the second argument.

Here's the definition from the vba's object browser fro the FireEvent func..
------------------------------------------------------------------------------------------------------------
Function FireEvent(bstrEventName As String, [pvarEventObject]) As Boolean
    Member of MSHTML.HTMLInputElement

So in order to make it work I gotta do something like inputElem.FireEvent("onkeypress", <something which is set to the keycode I want to fire>)

I created a test webpage so you guys can try out your script on it and see if you can get me a working example.. Thanks so much!

Here's the url of my test page..
http://www.iondataexpress.com/test/testkeypress.htm

Thank you again Experts!
Jeffrey
JeffreyDurhamAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

JeffreyDurhamAuthor Commented:
This is the code I've got so far.. it fills in the 'hi' but even though the fireevent returns true, nothing actually happens (the alert is never called).


Public Sub TestIT()
    'myWeb is a class which wraps all the funcs on shdocvw.internetexplorer that I use
    'Just ignore this code, but realize it's creating a new shdocvw.internetexplorer,
    '  navigating to the test page, and then waiting for it to finish loading
    myWeb.initMe_MainExplorer
    myWeb.NavigateMe 1, "http://www.iondataexpress.com/test/testkeypress.htm"
    myWeb.WaitForMe 1
    Dim htmlDoc As HTMLDocument
    Set htmlDoc = myWeb.GetWebDocument(1)
   
    'Relevant code starts Here:
    Dim inputElem As HTMLInputElement, pEvent As IHTMLEventObj
    Set inputElem = htmlDoc.getElementById("txtTest")
    inputElem.Value = "hi"
   
    Set pEvent = htmlDoc.CreateEventObject()
    pEvent.keyCode = 13
   
    Debug.Print inputElem.FireEvent("onkeypress", pEvent)
    Stop
End Sub
0
Julian HansenCommented:
Why not use the jQuery .trigger() method. Here is a sample on how to extend JQuery to include a triggerAll function that triggers multiple event handlers based on a single event
(function($) {
  $.fn.extend({
    triggerAll: function(eventlist, params) {
      var me = this, i, event = eventlist.split(',');
      for(i = 0; i < event.length; i++) {
        me.trigger(event[i], params);
      }
      return me;
    }
  });
})(jQuery);

Open in new window


You could then use it like this
$(function() {
  $('#hitme').keyup(function() {
    alert('tada');
  });
  
  $('#hitme').keydown(function() {
    alert('teedee');
  });
  
  $('#hitme').keypress(function() {
    alert('boo');
  });
  
  
  $('button').click(function() {
    $('#hitme').triggerAll('keyup,keydown,keypress');
  });
});

Open in new window

Full sample here
0
JeffreyDurhamAuthor Commented:
Julian Hansen

Sadly, the page I'm actually working on doesn't use any jquery libraries. So what that means is if I want to do the java approach I will need to do it using whatever plain javascript will work with IE. (I only need IE, since that's all we ever automate).

What I can do with the working javascript is I can actually inject a script into the web page and then call it from my vb code, which is why a javascript solution will actually work for me, even though I'm using vba. I'm down for any way that works :) I do know how to call javascript from vba already.

This particular issue is one I run into all the time automating web pages..

Specifically I want to be able to send the enter key itself to an input control. I was kinda thinking keycode=13 on a keyboard event of some sort..

Thanks! ~Jeffrey
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

Julian HansenCommented:
I would imagine you would need to look at the initKeyboardEvent (https://msdn.microsoft.com/en-us/library/ff975297(v=vs.85).aspx)

And potentially this .js library that handles cross browser initKeyboardEvent (https://gist.github.com/termi/4654819)

However, I was unable to get much success with this.
0
JeffreyDurhamAuthor Commented:
Oh wow, I'm still finding out all the differences between internet explorer (older versions) and the edge, but I had no idea there was a new way of firing events. I will read more about this over the weekend and see if I can do the same thing to construct an event, in the same manner as their mouse click example I suppose.. I will be able to test it out more on Monday for sure. Thanks, I'll let you know how that goes! ~Jeffrey
0
JeffreyDurhamAuthor Commented:
I've made some progress on using the new keyboardevent thing.. if you check my example page again you can see the javascript part in the head tag and see what I've got so far. ~Jeffrey

http://iondataexpress.com/test/testkeypress.htm
0
Julian HansenCommented:
Yup that's along the lines I was going as well - just could not get the initKeyboardEvent to fire the way I wanted it - will let you know if I come across anything.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
JeffreyDurhamAuthor Commented:
It seems like the keyCode is always 0 and so is the which value.
I don't have a version of IE that is ie 9 or 10 to test it on, but I did check it in emulation mode for this web page here.. I guess I'm using IE11 on my computer and we also have IE11 on our main computer. So I think I need to figure out how to use the new "synthetic events".. sadly, the only documentation I could find on it was for a click event.

http://output.jsbin.com/awenaq/3
(this page is pretty awesome, seems to have a workaround that uses a generic event instead of keyboardevent)

I've been messing with this for hours today.. irk. It also seems that ie9 or ie10 are the only ones that even use the createevent/initkeyboardevent construct and now in the edge they are doing something different.

I gotta leave off on this for now, but maybe tomorrow I'll have more time to mess with it. I think I'm going to try implementing the generic event like they're doing in the page I just mentioned..

~Jeffrey
0
JeffreyDurhamAuthor Commented:
Solution: Create events object (   document.createEvent("Events");   ) instead of using initKeyboardEvent() and then add the keyCode and which properties to the object manually. Then use dispatchEvent to fire it.

This seems to work, although it doesn't actually type the characters themselves to the field. I also am not sure if it's necessary to send the keydown and keyup events, except to mimic the natural order the events would go themselves. I did find a reference online that said that the keydown and keyup events wouldn't actually cause the chars to appear in the field, that you just needed to set the value as you call the events. Which is fine, as far as I know, my real goal was just to send the Enter key to the field on this one website anyways, not set the value by typing it in.

So I'm going to post this as a working solution as I did figure out how to make it work in IE. Best working example is actually the http://output.jsbin.com/awenaq/3 site.

But my working code for the test page I set up is here..
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test KeyPress</title>
    <script type="text/javascript">
        // this script is designed to work with IE11, although it seems to work on Chrome too

        function Handle_KeyPress(e) {
            if (e.keyCode == 13) {
                alert(document.getElementById('txtTest').value);
            }
            return true;
        }

        function RunExample() {
            // send the H, then the I, then the enter keys
            document.getElementById('txtTest').value = 'H';
            SendKey(72);  // 'H', 72, 0); 
            document.getElementById('txtTest').value = 'HI';
            SendKey(73);  // 'I', 73, 0);
            // send the Enter key
            SendKey(13);  // '\n', 13, 0);
        }

        function SendKey(iKeyCode) {
            //works
            var txtTest = document.getElementById('txtTest');
            txtTest.focus();

            // the keydown and keypress events may not even be necessary but they do follow the same
            // flow that the events would normally fire in..
            var eventObj_down = document.createEvent("Events");
            eventObj_down.initEvent("keydown", true, true);
            eventObj_down.keyCode = iKeyCode;
            eventObj_down.which = iKeyCode;
            txtTest.dispatchEvent(eventObj_down);

            var eventObj = document.createEvent("Events");
            eventObj.initEvent("keypress", true, true);
            eventObj.keyCode = iKeyCode;
            eventObj.which = iKeyCode;
            txtTest.dispatchEvent(eventObj);

            var eventObj_up = document.createEvent("Events");
            eventObj_up.initEvent("keyup", true, true);
            eventObj_up.keyCode = iKeyCode;
            eventObj_up.which = iKeyCode;
            txtTest.dispatchEvent(eventObj_up);
        }

        function GetKeyLocation(e) {
            // echo the key location arg so us programmers know what value to put in the locationArg for the initKeyboardEvent()
            document.getElementById('lblKeyLoc').innerHTML = 'location:&nbsp;' + e.location + '<br />keyCode:&nbsp;' + e.keyCode +
                '<br />locale:&nbsp;' + e.locale;
        }

    </script>
</head>
<body>

Goal is to enter the word 'hi' into this textbox below and then send it the keypress event. Ideally, through<br />
VBA, but worst case through javascript which I should be able to run from VBA.<br /><br />
<input id="txtTest" type="text" onkeypress="return Handle_KeyPress(event);" /><br /><br />
<input type="button" onclick="return RunExample();" value="Send Event" /><br /><br />
Enter keys in this field below to see what location arg they are for when calling the keypress event.<br /><br />
<input id="txtGetLocation" type="text" onkeydown="return GetKeyLocation(event);" /><br />
<label id="lblKeyLoc"></label>

</body>
</html>

Open in new window

0
JeffreyDurhamAuthor Commented:
Use document.createEvent("Events") instead, combined with initEvent func, instead of the initKeyboardEvent. Add .keyCode and .which properties to the event object instead.

I.E.
var eventObj = document.createEvent("Events");
            eventObj.initEvent("keypress", true, true);
            eventObj.keyCode = iKeyCode;
            eventObj.which = iKeyCode;
            txtTest.dispatchEvent(eventObj);

Your answer led me to the ultimate answer. Thanks a bunch Julian, I really appreciate all your help!
~Jeffrey
0
Julian HansenCommented:
You are most welcome - well done on finding the solution and good luck.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Access

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.