How do I detect hardware keyboard presence with javascript? - javascript

What is the best cross-browser and cross-platform way to detect hardware keyboard presence with javascript?

This may be an old question, but a few months ago, I was looking for a solution to this myself. I was building a messaging system which should send the message when someone hits Return on their physical keyboard, but inserts a newline when someone hits Return on a virtual keyboard. The way I solved it was by counting the time between keydown and keyup events and getting the average when Return was hit.
I finally got around to documenting it on my blog here.

Could you try the theoretical opposite? Instead of trying to detect keyboard hardware, why not try to detect a touch screen? With the ontouchstart event;
if ('ontouchstart' in document.documentElement) {
// show icon
}

Keyboard in JS is accessible via browser APIs which delegate to OS APIs and it's not possible to tell if there's a physical keyboard. I can cut the cord off of my physical keyboard right now, turn on virtual keyboard, click on the on-screen buttons with my mouse and the browser will still trigger every keyboard event the scripts are listening to. Form browsers's/JS's perspective the virtual keyboard is indistinguishable from a physical one.
And what does "presence" even mean? If I have a phone with a touch screen and slide-out keyboard do you expect the browser to trigger some kind of "keboardIn"/"keyboardOut" event? Same with cable plug-in/out? :)
If your app absolutely requires a physical keyboard just inform/ask the user.
Edit - after clarification by OP:
You know the facebook chat? You send messages simply by pressing
"Enter", I have to show users that do not have a keyboard button to
replace the "Enter" key.
So just make a form with text input and listen to the input/form events. Most (every?) soft keyboards have some kind of "Done", "Ready" or similar button. You don't need to know if the "keyCode" is equal to "13", but detect that the user has an intent to submit what he has typed. Or, as the last resort, detect f the device i touch-enabled and display the button then. ( if('ontouchstart' in document.documentElement)/* show touch sbmit button */ )

Use keyboard event to detect if the user have keyboard or not (he/she may press it). Save it in localStorage and the browser will remember it for the next time.
var app = this;
app.hasKeyboard = false;
this.keyboardPress = function() {
app.hasKeyboard = true;
$(window).unbind("keyup", app.keyboardPress);
localStorage.hasKeyboard = true;
console.log("has keyboard!")
}
$(window).on("keyup", app.keyboardPress)
if(localStorage.hasKeyboard) {
app.hasKeyboard = true;
$(window).unbind("keyup", app.keyboardPress);
console.log("has keyboard from localStorage")
}

When a virtual keyboard pops up on the screen on a mobile device, the height of your application reduces in order to accommodate the virtual keyboard. So, what you can do is that you can add an event listener that checks whether the screen has resized as the user focuses on the input field.
You can add this functionality using the resize event listener when the input field is focused:
const inputField = document.querySelector(".my-input");
const virtualKeyboardDetected = () => alert("Virtual keyboard detected!");
inputField.addEventListener("focusin", () => {
window.addEventListener("resize", virtualKeyboardDetected )
})
inputField.addEventListener("focusout", () => {
window.removeEventListener("resize", virtualKeyboardDetected )
})

if (confirm('Do you have hardware keyboard?')) {
} else {
}
Edit according to description in comments under question:
What about support 'Enter' everytime and add 'Send' icon only for touch screens (What's the best way to detect a 'touch screen' device using JavaScript?) and as a 'hover' pseudoclass for mouse?

Related

How to simulate key presses in JS

I wish to click on an <img> and make the browser simulate the typing out of a variable + [ENTER]. This should basically simulate the same thing that would happen if a scanner scanned a barcode
I'm developing an add-on for a webapp that we use at work. This work includes needing to scan barcodes which I've gotten to show on screen and we can scan, however in some instances it has proven to be a little difficult to scan. I'd like to be able to click on the barcode that is generated and have it simulate keystrokes. The characters don't need to end up in any input field as I assume the webapp is set to capture keystrokes for the whole window. I just need the keystrokes to be entered pretty fast to simulate a barcode scanner.
The jsfiddle provided currently has the variable being sent to an input field but that is not necessary for the final results.
I'd like to keep this vanilla javascript as I'm still learning it and don't wish to move on to Jquery until i have my feet firmly planted in JS.
https://jsfiddle.net/pshock13/o2gtzaj5/215
document.getElementById('barcode').addEventListener('click', function() {
//this is where I want theBarcode to be typed out + [ENTER] automatically.
main_input.value = theBarcode;
})
You can simulate a keypress by dispatching a KeyboardEvent for keydown and keyup.
E.g. simulating keypresses for your barcode:
document.getElementById('barcode').addEventListener('click', function() {
main_input.value = theBarcode;
[...theBarcode].forEach(function(c) {
window.dispatchEvent(new KeyboardEvent('keydown',{'key':c}));
window.dispatchEvent(new KeyboardEvent('keyup',{'key':c}));
});
window.dispatchEvent(new KeyboardEvent('keydown',{'key':'Enter'}));
window.dispatchEvent(new KeyboardEvent('keyup',{'key':'Enter'}));
});

Detect Hide Keyboard Button on Ipad Iphone in Javascript

I am trying to intercept "Hide keyboard button" specific for Ipad in Javascript. I searched everywhere but could not find correct keycode for that.
I pressed any keys and I get a keycode map (for characters, but also for enter, space and delete..).
This is an example of what I want to accomplish
$( "#mydiv" ).on( "keydown", function( event ) {
if (event.which == xx){
//do something
}
}
where xx is my keycode on 'hide keyboard button'. No method is called to the delegate when the button is pressed nor a KeyCode.
I took a look at detect iPad keyboard Hiding button, but I get a solution on a different level (with Xcode), but I need a solution with Javascript.
Hope someone could help.
I found a workaroud for iPad IOS7. I will test on IOS8 to make sure it works. So basically I create a listener on every FOCUSOUT event (for all my texts) and I call my function.
It fires when you have your keyboard open and when you close your "keyboard". It doesn't fire when you select another text field or button, because it targets on null. If you use in combination with keydown, you can save multiple value and call your submit function only when you release your keyboard.
It works for my specific project.
document.addEventListener('focusout', function(e) {
if (e.relatedTarget === null) {
alert("close keyboard without click on something else");
callYourFunction();
}
});
p.s
I'm pretty new here in SO, so I don't know if I can reply myself or I should edit my question or make a comment.

Can I trigger Android soft keyboard to open via javascript ( without phonegap )?

I have some custom web components in my mobile web app, whereas I need to manually fire 'focus' events on a field, to simulate the 'NEXT' functionality in the Android soft keyboard feature. ( using Galaxy S3 native browser ).
However, when I manually fire a focus event on a 'select' field, the native soft keyboard does not show. I have to subsequently click on the field to get it to show. (In IOS, of course, it works just fine).
So I'm wondering, if a 'focus' event doesn't trigger the soft keyboard to open, what JS event will ???
I am not using phonegap so I'm hoping there's a way without it.
Thanks for any help!!!
Here's a link from StackOverflow:
Showing Android's soft keyboard when a field is .focus()'d using javascript
Just focussing without an event doesnt seem to work. - you DO need a
click event triggering this.
$(document).ready(function() {
$('#field').click(function(e){
$(this).focus();
});
$('#button').click(function(e) {
$('#field').trigger('click');
});
});
You can do this by calling focus() then click() on the input. No need for jquery. Beware of endless loops if your script is triggered by an onclick() on a containing element. Make sure as well that this script is triggered by some user interaction. It won't work from document.onload(), or from a setTimeout(). It's also fragile with things like simultaneous style changes on the elements. The script below is working for me on Chrome for android 58 and Safari mobile 602.1.
var target = document.getElementsByTagName("input")[0];
if (event.target != target) {
target.focus();
target.click();
}
Vanilla JS solution:
let button = document.getElementById("b");
let input = document.getElementById("i");
// Keyboard opens when focusing the input from a click listener
button.addEventListener("click", () => {
input.focus();
});
// Input field gets focus but keyboard doesn't open.
setTimeout(() => {
input.focus();
}, 1000);

Prevent scrolling on mobile browser, without preventing input focusing

I use preventDefault() on touchstart on the document to prevent scrolling on a page. Unfortunately this prevents too much. The user can no longer give focus to an input (and open the soft keyboard). Using jQuery focus(), I can give the focus to the input on a touchstart. This opens the soft keyboard on iOS (most of the time), but never on Android.
Background:
I have a webpage that I want to make as much like a mobile app as possible. I'm only really concerned with Android and iOS, but any form factor. I start by making the content in the page exactly the same size as the screen size. This is nice until the user puts their finger on the page. I need to prevent user scrolling. The following code accomplishes this, but in slightly different ways on the two operating systems.
$(document).on('touchstart', function(e) {
e.preventDefault();
});
On iOS, this prevents the elastic scrolling: where a user can reveal a texture behind the webpage by attempting to scroll off the page. The feature is nice for a regular webpage, but in my case it detracts from the UX.
On Android, prevents the revelation of a handy hack that I use to hide the address bar. Android browsers start with the address bar visible, but as the user scrolls down the page, it disappears. To programmatically force the browser hide the address bar, simply add this line of code to your function called at load.
$('html, body').scrollTop(1);
This is a hacky (but also the only) way to tell the android browser that we have scrolled, and the address bar is no longer necessary.
Without the preventDefault on the document, the Android browser will allow scrolling and the address bar can be revealed.
So, both OS's have a good reason to have this preventDefault() called on every touchstart on the document, but it prevents too much. Tapping on an input field does nothing. Using a call to jQuery focus() can help, but only opens the soft keyboard on iOS, not Android.
$('input').on('touchstart', function() {
$(this).focus();
});
How can I prevent the page from scrolling, but use the browser native functionality for giving focus to input fields?
Note:
This code
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
is flawed because the user can still scroll the page as long as the initial touch originates from within the input field.
I actually solved this problem on another project, forgot about it, and remembered it most of the way through typing this up.
They key is to just do it on touchmove.
$(document).on('touchmove', function(e) {
e.preventDefault();
});
However, preventDefault on touchstart does all kinds of nice things like preventing the image save menu on a gesture enabled slideshow. My projects also include this.
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
If anyone has some suggestions on additional content or how to reformat this so that it can reach a greater audience that would be great. I haven't ever seen the content I have here all in one place, so I felt that it needed to be on SO.
Combine the two!
// prevent scrolling from outside of input field
$(document).on('touchstart', function(e) {
if (e.target.nodeName !== 'INPUT') {
e.preventDefault();
}
});
// prevent scrolling from within input field
$(document).on('touchmove', function(e) {
if (e.target.nodeName == 'INPUT') {
e.preventDefault();
}
});
This probably isn't perfect either, and I am especially worried that the first function will prevent following links, but I'll leave it to others to do extensive tests.
The simple answer to your question is don't use "preventDefault" instead use pointer-events css property to disable the scrolling on the element that scrolls.
CSS for your inputs:
input {
pointer-events: auto !important;
}
touchstart event listener:
document.body.addEventListener('touchstart', function(e) {
if (e.target.nodeName === 'INPUT') {
this.style.pointerEvents = 'none';
}
});
You will need to reset the pointer-events when you blur the input.
document.body.pointerEvents = 'auto';
+1 Good Question

Determining the correct Android WebView screen size after soft keyboard hides with JavaScript?

I'm working on a "Mobile Web" app, and relying completely on javascript to solve this problem. On certain Android devices, most notably the Samsung Galaxy family, a window.resize event fires when the soft keyboard appears, shortening the height of my screen.height. When a user taps the "Go" button of the soft keyboard, my app reloads with a height that is less the height of the soft keyboard.
Now, I am listening to the window.resize event, so if the user rotates the device, everything will right itself. However, I'm hoping to figure out a way to fire off the window.resize event programmatically, so that every action performed when I rotate the device is triggered.
Can this be done?
if you're using jQuery mobile use jQuery trigger()
if not use this code from a stackoverflow question:
You can use fireEvent on IE, and w3c's dispatchEvent on most other
browsers. To create the event you want to fire, you can use either
createEvent or createEventObject depending on the browser.
Here is a self-explanatory piece of code (from prototype) that fires
an event dataavailable on an element:
var event;
if (document.createEvent) {
event = document.createEvent("HTMLEvents");
event.initEvent("dataavailable", true, true);
} else {
event = document.createEventObject();
event.eventType = "ondataavailable";
}
event.eventName = eventName;
event.memo = memo || { };
if (document.createEvent) {
element.dispatchEvent(event);
} else {
element.fireEvent(event.eventType, event);
}
Update:
There is a fireEvent() for IE and dispatchEvent() method for non IE browser. You can manually fire your events. The trick is to create an event just like window.resize and fire that. I never tried this. But I hope that can help.
I had this same problem and abandoned trying to fire the events and went with modifying the meta viewport after keyboard has gone. See answer here: https://stackoverflow.com/a/11321889/1500269

Categories

Resources