Detecting virtual keyboards (when typing in an input field)
12 Feb 2016
Sometimes, it is useful to differentiate between physical and virtual keyboards in a web application. In my case, I had built a new messaging system for Yanteres with a responsive design which could be used on any device. While responsive design is a given on today’s web, the behavior of certain actions – which can’t be controlled via CSS – is different on mobile vs desktop. In the case of the aforementioned messaging system, hitting Return on physical keyboards is expected to send a message, while hitting Return on a phone’s or tablet’s virtual keyboard is expected to insert a newline.
Screen width media queries won’t cut it
On first thought, one may be tempted to use a media query in JavaScript to change the behavior for mobile vs desktop. However, let’s not forget that the screen size isn’t what changes the behavior here. A mobile phone or tablet can be hooked up to a physical keyboard and a desktop computer can also have a touch screen. Also, in landscape mode, a tablet resolution is essentially that of a small desktop in most responsive designs.
We need to differentiate between a physical and a virtual keyboard rather than screen size, and browsers currently have no API to do so that I am aware of. Searching high and low, I’ve found many people asking for a way to change the layout in response to the presence of a virtual keyboard, or lack thereof, but only one discussion on the actual behavior of the keyboard, which had no solution. Then I had a thought – does a virtual keyboard care about when you press and release keys the way a physical keyboard does, or does it fire keydown
and keyup
events instantaneously?
Counting key press and release time
I got the hunch that perhaps virtual keyboards fire the events in rapid succession in a way that was impossible for humans, and immediately went on to test my hunch on iOS and Android devices and desktop browsers by binding the keydown
and keyup
events that would log the time difference between key press and release.
Note: I use jQuery and CoffeeScript in my examples, but the concepts can be applied in vanilla JS easily.
Update : I’m migrating away from CoffeeScript, so I’ve updated the code to JavaScript.
The results were pretty much as I had expected. Virtual keyboards on mobile devices fire the events at physically impossible speeds.
When it came to Windows and Linux, I got pretty much the same results as with Mac, Android was slightly slower, and I didn’t get to test it on Windows touch devices (if anyone wants to help with that, please do). In summary, physical keyboards almost always returned over 30ms – even with quickly jabbing the keys, iOS virtual keyboards always took less than 10ms, and Android virtual keyboards were around 12ms.
Key press and release times are not 100% consistent
So, the answer is to count the milliseconds between keyup
and keydown
and you shall know whether or not you have a virtual or physical keyboard, right? Unfortunately, one key press and release won’t always give you the right answer. In some cases, a physical keyboard will have an odd key press that lasts less than 10ms (pictured above) and Android will have an odd one that lasts up to 25ms. The solution I came up with was to keep count of each key press time and then to find the average when I needed it. In my application, that would be when the user presses the Return key. If the average time is over 25ms, chances are good that it’s a physical keyboard.
Newlines with physical keyboards
The last step for a proper messaging system is to allow users of physical keyboards to enter newlines using Shift/Option/Meta/Etc + Return. All that needs to be done here is to check whether those keys are pressed on the keydown
event, and we’re done! I didn’t want a very large if
statement, so I put it in its own function.
TL;DR
The average time difference between keydown
and keyup
can be a good indicator of whether a user is typing on a physical or virtual keyboard. Here is the full code to an example that sends the message when Return is pressed on a physical keyboard and adds a newline when pressed on a virtual keyboard.
- Posted in:
- Web Development