js - simulate key press without specifying an element - javascript

I would like to simulate a key press in JavaScript. preferably without specifying any element.
The way I would like to do it is to use .focus() on an input and then simulate a key press like the character "a".
Just the same thing that would happen if I would press the key myself.
Searching through the internet I found no solution. It might have something to do with the combination of the simulated event and an input field. Sometimes I can catch the events, but there is no input present in the input field.
Note that this should not be considered a duplicate of Is it possible to simulate key press events programmatically? because this does not solve my problem. I have already tried it.

If you have or can include jQuery, here's the easy way
With jQuery
jQuery.event.trigger({ type: 'keydown', which: 78 }); // press n key
To simulate the keypress event within an input field, use like this
var e = jQuery.Event("keydown");
e.which = 78; // n code value
e.altKey = true; // Alt key pressed
$("#inputBox").trigger(e);
Without jQuery
var kbEvent= document.createEvent("KeyboardEvent");
var initMethod = typeof kbEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
kbEvent[initMethod](
"keydown", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
window, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
78, // keyCodeArg : unsigned long the virtual key code , else 0
0 // charCodeArgs : unsigned long the Unicode character associated with the depressed key, else 0
);
document.dispatchEvent(kbEvent);
The above code infact will not modify the input value for you, it will only simulate keystrokes
See this post for more info
How to simulate typing in input field using jQuery?
What you need is : fn.sendKeys

I wrote this answer in Is it possible to simulate key press events programmatically?, which has been updated since this question was asked (2018), and now also includes some info about updating the input element and triggering listeners (spoiler alert, it can be sometimes easy, sometimes harder, or sometimes not doable to my knowledge).
In regards to "not specifying an element", you need an eventTarget (like an element) for dispatchEvent. If you don't use any, then you're running it in the global object, equivalent to window.dispatchEvent() in the browser.
Note: when you specify an element, the event can trigger listeners in other elements (parents) as well because of event bubbling

Related

How to tell if an element accepts keyboard input?

I'm working on keyboard shortcuts for a web application and need to check if a keypress should trigger the shortcut or if it is just the user typing and should therefore not trigger the shortcut.
For example, a common pattern is to use the / or s keys to open the global search bar. Obviously this should not open the search bar if the user is typing into another input.
The ideal logic would go something like this: On keypress, check the currently focused element. If the element accepts keyboard input (can be typed into), then do nothing. If the element does not accept keyboard input, run the shortcut.
Note that checking for focusability is not enough because links and buttons are focusable, but do not accept keyboard input (in the way I mean here).
Here's what I have so far:
function acceptsKeyboardInput(element) {
return (
element.tagName === "INPUT" ||
element.tagName === "TEXTAREA" ||
element.isContentEditable
);
}
Does this approach catch every case or is there a better way to tell if an HTML element accepts keyboard input?
Will all shortcuts be more than one key? If so you can listen for input and prevent a shortcut from running with a boolean value.
var is_input = false
window.addEventListener('keydown', function (e) {
console.log(is_input)
is_input = false
})
window.addEventListener('input', function (e) {
is_input = e.constructor.name == 'InputEvent'
})
Expected output for /s while able to type would be true or false (depending on the previous is_input value) at / keypress then true at s keypress and all keys following.
Expected output for /s while not able to type would be true or false (depending on the previous is_input value) at / keypress then false at s keypress and all keys following
From what I've seen, the suggestion given in the question seems to be the best approach—with some adjustments.
The first improvement is to blacklist a set of input types that don't accept keyboard input (e.g. checkbox or radio). I find it easier and better to use a blacklist rather than a whitelist for two reasons. The first is future-proofing against newly supported input types and in case you miss one. Second and more importantly, an invalid input type defaults back to type text, which means there are an infinite number of input types that accept keyboard input.
The second change is to also include <select> elements since they can be typed into as a sort of search/quick-select functionality.
Here's the full function:
const nonTypingInputTypes = new Set([
"checkbox",
"radio",
"button",
"reset",
"submit",
"file",
]);
export function acceptsKeyboardInput(element) {
return (
(element.tagName === "INPUT" && !nonTypingInputTypes.has(element.type)) ||
element.tagName === "TEXTAREA" ||
element.tagName === "SELECT" ||
element.isContentEditable
);
}
There are a few other inputs that don't accept keyboard input but that are less widely supported by browsers (e.g. color), so I've tried to keep it to the more commonly used and widely implemented input types.

Press Space key inside a text box field using trueclient vugen Tool?

I need to Press space Key using JavaScript Inside a TextBox after typing the string.
How can I do it inside vugen tool (Load runner) using eval js function?
can anyone guide me?
I tried inside to evaluate javascript on the object but getting an error.
var e = new KeyboardEvent('keydown',{'keyCode':32,'which':32});
object.dispatchEvent(e);
I am using Eval Js on object function in the tool and paste this script.
ERROR:
No Error it is not clicking the space key inside text box.
I also tried this code
var keyboardEvent = document.createEvent("KeyboardEvent");
var initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ?
"initKeyboardEvent" : "initKeyEvent";
keyboardEvent[initMethod](
"keypress", // event type : keydown, keyup, keypress
true, // bubbles
true, // cancelable
window, // viewArg: should be window
false, // ctrlKeyArg
false, // altKeyArg
false, // shiftKeyArg
false, // metaKeyArg
32, // keyCodeArg : unsigned long the virtual key code, else
0 // charCodeArgs : unsigned long the Unicode character
associated with the depressed key, else 0
);
document.dispatchEvent(keyboardEvent);
For this also no Error but the code is not clicking space inside text box.
If you are using TruClient, you could add a eval JS step. TruClient support AUT.document and AUT.window to reference the current page of the application under test.
If you are using a eval JS step on Object, then the target element can be referenced with "object" in the code of the step.
The detail inforamtion can be found from here
How does your server know you are pressing the space bar inside of your client.....
Please check the below demo with TruClient:

Debounce search only if search term changes [duplicate]

This question already has answers here:
Throttle event calls in jQuery
(7 answers)
Closed 5 years ago.
I'm working on a live ajax search field. So we have:
<input type="search" id="search">
And I want to trigger the search once the user has stopped typing for 500ms.
I got it working like this:
function throttle(f, delay){
var timer = null;
return function(){
var context = this, args = arguments;
clearTimeout(timer);
timer = window.setTimeout(function(){
f.apply(context, args);
},
delay || 500);
};
}
$('#search').keyup(throttle(function(){
// do ajax
}));
The problem is: if user holds shift key and releases it, the search will trigger regardless. So no new keys are added and the same search term was submitted.
How can I make it so that it triggers only if a new character has been added/removed?
Simply keep track of the state:
var currentSearch = "";
Then whenever a keyup happens, check if the input changed, if not stop updating:
if($("#search").val() === currentSearch) return;
//updated so:
currentSearch = $("#search").val();
Sidenote: as DOM lookup is time intensive you may cache $("#search") ...
You could also use the keyup event, and check if the keycode matches the keys on which you want to act on. Please refer this answer
Adapting that answer to your case:
$('#search').keyup(
function(event) {
var isWordCharacter = event.key.length === 1;
var isBackspaceOrDelete = (event.keyCode == 8 || event.keyCode == 46);
if (isWordCharacter || isBackspaceOrDelete) {
(throttle(function(){
// do ajax
})))();
}
})
You should use input event instead of keyup, which will be triggered only when the value will change.
$('#search').on('input', throttle(function(){
// do ajax
}));
The DOM input event is fired synchronously when the value of an <input>, <select>, or <textarea> element is changed. (For input elements with type=checkbox or type=radio, the input event does not fire when a user clicks the control, because the value attribute does not change.)
But be aware that this event has some problems in IE9/10/11 (and is not supported in previous IE versions at all):
[2] IE 9 does not fire an input event when the user deletes characters from an input (e.g. by pressing Backspace or Delete, or using the "Cut" operation).
[3] IE 10 and 11 has a bug, input event fires on placeholder attribute changes.
But the IE10/11 problem is kind of ok, so it depends on if you need to support IE9.
https://developer.mozilla.org/en-US/docs/Web/Events/input
EDIT: unfortunately change is not a suitable solution as it occurres only after blur (loosing focus of the input). Correct solution is to use input event.

How to capture a backspace on the onkeydown event

I have a function that is triggered by the onkeydown event of a textbox. How can I tell if the user has hit either the backspace key or the del key?
Try this:
document.addEventListener("keydown", KeyCheck); //or however you are calling your method
function KeyCheck(event)
{
var KeyID = event.keyCode;
switch(KeyID)
{
case 8:
alert("backspace");
break;
case 46:
alert("delete");
break;
default:
break;
}
}
event.key === "Backspace" or "Delete"
More recent and much cleaner: use event.key. No more arbitrary number codes!
input.addEventListener('keydown', function(event) {
const key = event.key; // const {key} = event; ES6+
if (key === "Backspace" || key === "Delete") {
return false;
}
});
Mozilla Docs
Supported Browsers
Nowadays, code to do this should look something like:
document.getElementById('foo').addEventListener('keydown', function (event) {
if (event.keyCode == 8) {
console.log('BACKSPACE was pressed');
// Call event.preventDefault() to stop the character before the cursor
// from being deleted. Remove this line if you don't want to do that.
event.preventDefault();
}
if (event.keyCode == 46) {
console.log('DELETE was pressed');
// Call event.preventDefault() to stop the character after the cursor
// from being deleted. Remove this line if you don't want to do that.
event.preventDefault();
}
});
although in the future, once they are broadly supported in browsers, you may want to use the .key or .code attributes of the KeyboardEvent instead of the deprecated .keyCode.
Details worth knowing:
Calling event.preventDefault() in the handler of a keydown event will prevent the default effects of the keypress. When pressing a character, this stops it from being typed into the active text field. When pressing backspace or delete in a text field, it prevents a character from being deleted. When pressing backspace without an active text field, in a browser like Chrome where backspace takes you back to the previous page, it prevents that behaviour (as long as you catch the event by adding your event listener to document instead of a text field).
Documentation on how the value of the keyCode attribute is determined can be found in section B.2.1 How to determine keyCode for keydown and keyup events in the W3's UI Events Specification. In particular, the codes for Backspace and Delete are listed in B.2.3 Fixed virtual key codes.
There is an effort underway to deprecate the .keyCode attribute in favour of .key and .code. The W3 describe the .keyCode property as "legacy", and MDN as "deprecated".
One benefit of the change to .key and .code is having more powerful and programmer-friendly handling of non-ASCII keys - see the specification that lists all the possible key values, which are human-readable strings like "Backspace" and "Delete" and include values for everything from modifier keys specific to Japanese keyboards to obscure media keys. Another, which is highly relevant to this question, is distinguishing between the meaning of a modified keypress and the physical key that was pressed.
On small Mac keyboards, there is no Delete key, only a Backspace key. However, pressing Fn+Backspace is equivalent to pressing Delete on a normal keyboard - that is, it deletes the character after the text cursor instead of the one before it. Depending upon your use case, in code you might want to handle a press of Backspace with Fn held down as either Backspace or Delete. That's why the new key model lets you choose.
The .key attribute gives you the meaning of the keypress, so Fn+Backspace will yield the string "Delete". The .code attribute gives you the physical key, so Fn+Backspace will still yield the string "Backspace".
Unfortunately, as of writing this answer, they're only supported in 18% of browsers, so if you need broad compatibility you're stuck with the "legacy" .keyCode attribute for the time being. But if you're a reader from the future, or if you're targeting a specific platform and know it supports the new interface, then you could write code that looked something like this:
document.getElementById('foo').addEventListener('keydown', function (event) {
if (event.code == 'Delete') {
console.log('The physical key pressed was the DELETE key');
}
if (event.code == 'Backspace') {
console.log('The physical key pressed was the BACKSPACE key');
}
if (event.key == 'Delete') {
console.log('The keypress meant the same as pressing DELETE');
// This can happen for one of two reasons:
// 1. The user pressed the DELETE key
// 2. The user pressed FN+BACKSPACE on a small Mac keyboard where
// FN+BACKSPACE deletes the character in front of the text cursor,
// instead of the one behind it.
}
if (event.key == 'Backspace') {
console.log('The keypress meant the same as pressing BACKSPACE');
}
});
In your function check for the keycode 8 (backspace) or 46 (delete)
Keycode information
Keycode list
not sure if it works outside of firefox:
callback (event){
if (event.keyCode === event.DOM_VK_BACK_SPACE || event.keyCode === event.DOM_VK_DELETE)
// do something
}
}
if not, replace event.DOM_VK_BACK_SPACE with 8 and event.DOM_VK_DELETE with 46 or define them as constant (for better readability)

How to change characters typed in Firefox

I need to change in a text input the character '.' to ',' while typing.
In IE I change the keyCode event property in the keypress event, like this
document.getElementById('mytext').onkeypress =
function (evt) {
var e = evt || window.event;
if (e.keyCode && e.keyCode==46)
e.keyCode = 44;
else if (e.which && e.which==46) {
e.which = 44;
}
};
but it seemes that in Firefox it's impossible to change characters typed in key events.
Any suggestions?
Try this. It works on all browsers:
window.onload = function () {
var input = document.getElementById("mytext");
input.onkeypress = function () {
var evt = arguments[0] || event;
var char = String.fromCharCode(evt.which || evt.keyCode);
// Is it a period?
if (char == ".") {
// Replace it with a comma
input.value += ",";
// Cancel the original event
evt.cancelBubble = true;
return false;
}
}
};
Update: Pier Luigi pointed out a problem with the above. It doesn't take care of the caret position not being at the end of the text. It will append the command to the end even if you're inserting some text to the value.
The solution would be, instead of appending a comma, to simulate a keypress event for the comma key. Unfortunately the way dispatching of synthetic events work in different browsers seems to show a lot of variety and isn't an easy feat. I'll see if I can find a nice and generic method for it.
Assume that all properties in an Event object are immutable. The DOM spec doesn't address what happens when you change those values manually.
Here's the logic you need: listen for all key events. If it's a period, suppress the event, and manually add the comma at the cursor position. (Here's a code snippet for inserting arbitrary text at the cursor position.)
You'd suppress the event in Firefox by calling event.preventDefault(); this tells the browser not to go ahead with the default action associated with this event (in this case, typing the character). You'd suppress the event in IE by setting event.returnValue to false.
If it's not a period, return early from your handler.
Technically you just want to replace all dots with commas.
document.getElementById('mytext').onkeyup = function(){
this.value = this.value.replace('.', ',');
}
If I look at the official Document Object Model Events document, mouse events fields are defined as read-only. Keyboard events are not defined there, I suppose Mozilla followed this policy for them.
So basically, unless there is some smart trick, you cannot alter an event the way you want. You probably have to intercept the key and insert the char (raw or translated) where the caret is, the way JS HTML editors do.
Does this really need to be done on the fly? If you are collecting the information to be posted to a form or submitted to a database, would it not be better to modify the data once it was submitted? That way the user never sees the confusing change.
This is possible now by intercepting and cancelling the default keydown event and using HTMLInputElement.setRangeText to insert your desired character. This would look something like this:
document.addEventListener('keydown', $event => {
if($event.code === 'Period'){
$event.preventDefault();
let inputEl = document.querySelector("#my-input");
inputEl.setRangeText(
',',
inputEl.selectionStart,
inputEl.selectionEnd,
"end"
);
}
})
setRangeText will insert text at the cursor position in a given input. The "end" string as the last argument sets the cursor to the end of the inserted content.
More info here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText

Categories