Is there a way to enforce the onscreen keyboard on Android/iOS browsers to become visible when a no page element has focus, or the active input is disabled, or is set to be readOnly?
I use a Bluetooth barcode scanner. If this device is connected it represents a hardware keyboard. I already have a Javascript listening to KeyDown events. On desktop computers this works fine, so only if no input or textarea is active or the active element is readOnly, it begins capturing the key input in a hidden field to be processed later.
If however an input or textarea is active the user should be allowed to enter, append or edit the scanned input manually. But when the barcode scanner is connected in some cases the onscreen keyboard will not show up, because the browser expects the hardware keyboard to be in charge or is designed to ignore a readOnly field.
On a desktop computer one can do this with the main hardware keybaord. But to give the users the option to choose between both ways of entering data on a tablet or smartphone, I need to be able to show/hide the onscreen keyboard with a toggle while the bluetooth barcode scanner is connected and the active element might be readOnly.
The script so far is:
document.addEventListener('DOMContentLoaded', () => {
'use strict';
document.addEventListener('keydown', event => {
const charFilter = "abcdefghijklmnopqrstuvwxyzäöü1234567890_-+=%$##&!?.ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß";
const key = event.key;
const ael = document.activeElement;
const qrf = document.getElementById('qr_scanner_form');
if ((ael.nodeName=='INPUT' && ael.readOnly==false) || (ael.nodeName=='TEXTAREA' && ael.readOnly==false)){
if(ael != qrf.qr_scanner_input){
// clear the hidden element from any previous input
qrf.qr_scanner_input.value='';
// abort further processing
return;
}
}
if(key === 'Enter'){ // pre capture an enter key
var clean = qrf.qr_scanner_input.value.split("´");
qrf.qr_scanner_input.value = clean.pop(); // only process the last item
if(qrf.qr_scanner_input.value != 'stop' && qrf.qr_scanner_input.value != ''){
pWaitForServer(1); // starts hourglass animation
document.body.style.cursor = "wait";
setTimeout(function(){ pWaitForServer(0);qrf.submit(); }, 1357); // stops hourglass animation and proceeds
}
}else{
// check for unwanted characters, abort if nececary
if (charFilter.indexOf(key) === -1) return;
// append hidden element with last key
if(ael!=qrf.qr_scanner_input) qrf.qr_scanner_input.value+=key;
}
});
});
document.body.style.cursor = "auto";
I found many suggestions to hide or disable the onscreen keyboard, but I basically need to do the reverse and found nothing about it. My thoughts are going toward using a clipboard, copy the scanner input, setting the readOnly of the clicked element to false and then allow the last hardware input to be pasted there. I Hope somebody can give me a nudge toward a nicer solution.
Related
Currently trying to focus on an input type when the AJAX method went successful.
It works, but on Android it opens the virtual keyboard. As we are working on a PDA with a keyboard, I would like to hide that virtual keyboard.
On success
var inp = "$('artikeltje')"
hideKeyboard(inp);
document.getElementById("artikeltje").focus();
the function hideKeyBoard
function hideKeyboard(element) {
element.attr('readonly', 'readonly'); // Force keyboard to hide on input field.
element.attr('disabled', 'true'); // Force keyboard to hide on textarea field.
setTimeout(function () {
element.blur(); //actually close the keyboard
// Remove readonly attribute after keyboard is hidden.
element.removeAttr('readonly');
element.removeAttr('disabled');
}, 100);
}
Which was taken from this question:
https://stackoverflow.com/a/11160055/7639883
Also: I have tried to set the focus first and then apply the hideKeyboard() without luck!
I am using Ace Editor to build a code replay program. I store all the keys pressed when you type code, and then I replay them in Ace Editor. I have finished storing and replaying all keyboard/mouse input, but am having issues replaying tab presses.
Ace Editor handles tabs within a textarea DOM. The default behavior for a textarea when tab is pressed is to move to the next DOM, so I know they are using preventDefault() and using their own handler in order to allow softTab (insertion of 1,2,3, or 4 spaces before all highlighted text).
My goal is to cause Ace editor to trigger the tab event - such that whatever is currently highlighted in the Ace editor is tabbed over the correct number of spaces. Does anyone know how to do this?
Here are a list of options I've tried and why they don't work:
Store tab presses on keydown and then calculate the column value and insert the spaces in that location. BUT - this fails when you have some text half highlighted. The correct functionality should shift the entire word over, but this would just insert spaces in the middle of the word.
Store the location and keys pressed whenever editor.on('change', some_event_handler) fires, which gives me exactly what was input and the location (perfect for replay) except it doesnt tell me whether tab or spacebar was pressed (it will fire for both and spacebar is already handled). Plus this still inserts spaces at the location (potentially in middle of a word instead of shifting word over) as in number 1.
For example:
editor.getSession().on('change', function(e) {
if (handlers) {
var text = e.data.text;
if (text == ' ' || text == ' ' || text == ' ' || text == ' ') {
//FAILS because it doesn't know if its space or a single space tab.
Try to trick Ace Editor to trigger a tab by storing '/t' and inserting it into the ace Editor.
For example (storage code):
function keypress_handler(e) {
var key = e.which;
var text = String.fromCharCode(key);
switch(key) {
case 9: //Tab
text = '\t'; // manually add tab
//Code to store this event for replay later
break;
}
For example (replay code):
// Assuming the cursor/selection is in the correct position
editor.insert(log.text);
At this point, I was beginning to think about building tab from scratch (when to shift multiple things if multiple lines are selected, how far to shift, how to handle if a word is half highlighted when tab is pressed), but Ace clearly already does this when tab is pressed, so I would like to just trigger the tab press. Normally to trigger a tab press, I'd simply do:
// trigger an artificial Tab Keydown event for Ace Editor using jQuery
var tab_press= $.Event('keydown');
tab_press = 9; // Tab keycode
$('.editor').trigger(tab_press);
But this causes results in no behavior. Any suggestions?
I read through the source code here:
https://github.com/ajaxorg/ace/blob/master/lib/ace/commands/default_commands.js
And found the following snippet of code:
{
name: "indent",
bindKey: bindKey("Tab", "Tab"),
exec: function(editor) { editor.indent(); },
multiSelectAction: "forEach",
scrollIntoView: "selectionPart"
}
Thus, to trigger a tab (that works in all cases), simply call:
editor.indent();
How incredibly simple - wish there was some documentation out there for this so that many hours could have been spared.
In Ace all of the user input from keyboard is processed via commands. This is used in Ace to record and replay macros see https://github.com/ajaxorg/ace/blob/v1.1.4/lib/ace/commands/command_manager.js#L52-L96.
If you want to record user input and then to replay it you can use
// record
commands=[]
editor.commands.on("afterExec", function(e) {
commands.push({name: e.command.name, args: e.args})
});
// replay
commands.forEach(function(e) {editor.execCommand(e.name, e.args)})
Capturing mouse input is a bit tricker, but from question it seems you already know how to do it.
This pull request is somewhat related to your question. It allows to emulate user input by calling simulateKeys("a", "b", "ctrl-Left", "Tab")
I recently added some predictive text input fields to the web-app I am supporting.
Big deal, right? Not really, seems like if your web-app doesn't do this -- you are already behind the times and your end-users are complaining. (At least that's how it is over here).
So, my question has to do with the "up" arrow key.
The predictive textbox has a onkeyup listener.
The handler segregates the key strokes and does something depending on the character the user entered.
The up arrow key allows the user to navigate in a div I created loaded with "suggestions."
I have several variables tracking indexes, etc...
Basically, when the user hits the up arrow I will change the id of the div to an id that has some css associated with it that will make the div appear as though it is selected. Additionally I will grab the value in that div and assign it to the textbox where the user is able to type.
The problem is an aesthetic one. Inherently with all text boxes I am learning, the up arrow key will reset the cursor position. This is happening just before I am writing the new value to the text field.
So, on each up arrow stroke, the user is seeing a jumping cursor in the textbox (it will jump to the beginning and immediately it will appear at the end).
Here's the code -
if (event.keyCode === 38 && currentUserInput.length > 0) {
// user has toggled out of the text input field, save their typing thus far
if (currentToggledIndex == -1) {
currentToggledIndex = autoFillKeywordsList.length-1;
savedKeywordUserInput = currentUserInput;
}
else {
// revert currently selected index back to its original id
document.getElementById("kw_selected").id = "kw_" + currentToggledIndex ;
// user has toggled back into user input field
if (currentToggledIndex == 0) {
currentToggledIndex = -1;
}
// user has toggled to the next suggestion
else {
currentToggledIndex--;
}
}
// 2. Determine next action based on the updated currentToggledIndex position
// revert the user input field back to what the user had typed prior to
// toggling out of the field
if (currentToggledIndex == -1) {
element.value = savedKeywordUserInput;
}
// mark the toggled index/keyword suggestion as "selected" and copy
// its value into the text field
else {
document.getElementById("kw_"+currentToggledIndex).id = "kw_selected";
element.value = autoFillKeywordsList[currentToggledIndex];
}
// 3. Determine what the user can do based on the current value currently
// selected/displayed
displayAppropriateButtonActions(element.value);
}
The funny thing is - the "down" arrow works perfectly since by default the down arrow key will place the cursor at the end of the string currently located in the textbox.
Ok, so things that I have already tried -
event.preventDefault();
event.stopPropogation();
I also tried to set the cursor position PRIOR to setting the new value to no avail using a setCursorPosition function I found on another post here. (Yeah, I was reaching with this one)
I tagged this as JavaScript and Jquery. I prefer to use JavaScript, but open to suggestions in Jquery too!
As Ryan suggested. how I achieved this in angular 4.x is
.html
<.. (keydown)="keyDownEvent($event)" >
.ts
keyDownEvent(event: any){
if (event.keyCode === 38 && event.key == "ArrowUp")
{
event.preventDefault();
//logic..
}
I think what you can do is when they move the cursor, grab that and find out what element it is ... then store it in a variable and focus() it and erase it and then put the value you stored back into it.
var holdme = $("#myelement").val();
$("#myelement").focus().val('').val(holdme);
This works for me when having weird cursor issues in jquery/javascript most of the time. Give it a try and if it doesn't work, let me know and I'll see what else might be wrong.
I found that it worked well to capture the caret position, blur, restore the caret position, then focus again.
myTextInput.onkeydown = function(e){
//some other code
if(e.key == "ArrowDown" || e.key == 40 || e.key == "ArrowUp" || e.key == 38){
var caretPos = this.selectionStart;
//do your stuff with up and down arrows
e.preventDefault();
this.blur();
this.selectionStart = caretPos;
this.selectionEnd = caretPos;
this.focus();
}
}
The caret will very briefly disappear, but I think you have to be incredibly observant to notice.
As you tab between input fields in a browser, the browser will automatically scroll the nearest parent container to place the next focused field within the view.
Simple JSFiddle: http://jsfiddle.net/TrueBlueAussie/pxyXZ/1/
$('.section').eq(6).find('input').focus();
For example if you open the above fiddle it selects "Sample item 7" at the bottom of the yellow window. If you press tab the "Sample text 8" field jumps up towards the middle of the parent window.
Obviously this is a great thing for normal websites, but I have a custom scrolling container in which I position & scroll everything manually. I am tracking focus changes and will use a momentum scroller to bring it into view, but how do I disable the default scrolling behavior of web-browsers? Happy to accept CSS, Javascript or JQuery solutions.
This is just winging it based on my comment above:
$('input').on('keyup',function(e){
if(e.keyCode === 9) {
var $this = $(this);
// (do your scroll thing here
// ..., function(){
$this.parent().next().find('input').focus();
// });
}
});
Long as the callback timing is correct, this will only change focus after you have already scrolled. You'll need to do your own magic to determine what to scroll to, but this should give you the focus behavior you want.
Turns out you can't smooth scroll for focus changes as the events happen in the wrong order. You get an awful delay while it scrolls the field into view, before focus is set. A better move of the item onscreen, or superfast scroll, is all we can hope for.
As suggested by PlantTheIdea (+1'ed), you need to catch the TAB key and find the next focusable item, bring it into view, then set focus to it.
In practice there are a number of issues to resolve:
Change of focus occurs on TAB keydown (not keyup).
Only match non-hidden inputs (lots of web apps have hidden fields that will go bang if you try to focus them).
Allow for the selection to tab off the first or last item on the page (otherwise the browser loses the ability to tab to its address bar)
use e.keyCode || e.which to allow for older browsers
catch event at document level to allow for cases of other inputs, outside of the scrolling area, causing it to enter the scrolling area (first or last input).
The final code looks like this:
$(document).on('keydown', ':focus', function (event)
{
if ((event.keyCode || event.which) == 9)
{
var $inputs = $(":input:not(hidden)")
var index = $inputs.index(this);
// Index previous or next input based on the shift key
index += event.shiftKey ? -1 : 1;
// If we are in the range of valid inputs (else browser takes focus)
if (index >= 0 && index < $inputs.length)
{
var $next = $inputs.eq(index);
event.preventDefault();
// Move, not scroll, to the next/prev item....
MoveIntoView($next);
$next.focus();
return false;
}
}
});
I have currently an eventlistener listening for when a user enters an email address in a textbox on an html website. It then displays an alert when it detects an email address is being entered. Currently I have set it up whereby it detects the event blur then checks whether it meets the regex then an alert will display. This creates many alerts and is not very accurate as the alert
I need the eventlistener to listen for when the tab key specifically is pressed. I know I need to use KeyCodes but have not used them before. This eventlistener is currently working dynamically as it is a Firefox AddOn that scans a webpage so the eventlistener is not specifically attached to a specific input box.
Code:
vrs_getWin.document.getElementsByTagName("body")[0].innerHTML = bodyContents;
var inputFields = vrs_getWin.document.getElementsByTagName("input");
for(inputC=0; inputC < inputFields.length; inputC++) {
var elementT = inputFields[inputC].getAttribute("id");
inputFields[inputC].addEventListener("blur", function(){
var emailPattern = /(\w[-._\w]*\w#\w[-._\w]*\w\.\w{2,3})/g;
var resultEmail = emailPattern.test(vrs_getWin.document.getElementById(elementT).value);
if(result) {
prompts.alert(null, "Test", vrs_getWin.document.getElementById(elementT).value);
}
}, false);
}
Any help with this will be much appreciated.
I think from a UX stand point, I would not recommend using a javascript alert to notify the user of a problem, especially if you want the notification to happen when they have completed a single form input. The blur event would be my recommendation, and use some other visual cue to notify the user.
But, if you want to go with the tab key, the event your looking for is 'keydown', or 'keyup'. To use it you listen for the keydown event then check if the event.keyCode == '9'. (tab key)
document.addEventListener('keydown', function(e){
if( e.keyCode == '9' ){
alert('You pressed the tab key.');
}
}, false);
To get the keycodes of keys I like to pop open a console and type in:
document.addEventListener('keydown', function(e){
console.log( e.keyCode );
}, false);
Then when you press a key, it will output the keycode for that key.