Triggering keyboard event with JS which pynput recognizes - javascript

I am running a website in Python's Bottle framework and I am using the keyboard listener from pynput package. The listener is stopped when delete key is pressed. I want the listener to stop, when a certain button in HTML file is clicked on as well. I want to write a function in JavaScript which will be executed when the button is clicked on and which will trigger the delete key to be pressed (which will consequently make the listener stop).
I have found many JS functions on the internet which trigger the delete button to be pressed, but in none of those examples did the keyboard listener stop. The listener in Python never recognized those events. Does anyone know a way to write such JS function that will trigger a key to be pressed and that the listener in Python will recognize that the key has been pressed?
EDIT:
Here is a part of my code (the pynput part):
def on_press(key):
try:
k = key.char
except:
k = key.name
print('Key pressed: ' + k)
if k in ['left', 'right', 'up', 'down', 'delete']:
#print('Key pressed: ' + k)
return False
def dobi_smer():
listener = keyboard.Listener(on_press = on_press)
listener.start()
listener.join()
with keyboard.Events() as events:
for event in events:
if event.key == keyboard.Key.left:
return 'L'
elif event.key == keyboard.Key.right:
return 'R'
elif event.key == keyboard.Key.up:
return 'U'
elif event.key == keyboard.Key.down:
return 'D'
elif event.key == keyboard.Key.delete:
return 'X'
It listens to the keyboard until one of the arrows or delete key is pressed.
According to the answer, I have created also created a new page in my website which would simulate the delete key being pressed. Here is the code in Bottle:
#bottle.post("/igraj/prekini/")
def igraj_prekini():
print("bla")
keyboard.press(keyboard.Key.delete)
keyboard.release(keyboard.Key.delete)
I have tried to send this post request with AJAX with the following functions:
function prekini() {$.post("/igraj/prekini/")}
and
function prekini() {$.ajax('/igraj/prekini/', {type: 'POST'})}
but neither of these two functions worked as the page /igraj/prekini/ was never reached. (string "bla" was never printed)

You can create a stop button in html, and a write javascript function to listen click in that button. Now, your function works when you clicked that button. So, in that function you can write AJAX code to call some url like /stop_pynput and a /stop_pynput route in bottle like your home page /. And write code that stops pynput there or call some functions there and return something. So, Now you have to gain skill to solve this problem with my idea, if you already know it then that's best but if you aren't familiar with ajax then try asking it in comment.
Steps to do in list form:
Stop button in HTML
Listen click using js
Ajax request to some internal url
In bottle make that route
Now, main part. Inside that route/function or inside that route write run script to stop your pynput
If any queries, then feel free to ask in comment.

Related

Javascript - How do I prevent functions from running multiple times, incrementally, after each button click?

I am flabbergasted trying to figure out a way to prevent the button click from rendering multiple times based on the number of clicks. If you I click "submitButton" once, everything runs once. If I click it a second time, everything runs twice. If I click it a third time, everything runs three times... And so on...
Here is the code I am running to initiate the running of several functions. The subsequent functions grab data from a database, creates batches of 100, then inserts that data into an HTTP POST request.
submitButton.addEventListener("click", () => {
if (document.getElementById("subject").value == "") {
alert(
"Please add a Subject for your Push Notification before sending."
);
} else if (document.getElementById("body").value == "") {
alert(
"Please add a Message Body for your Push Notification before sending."
);
} else if (
document.querySelectorAll("input[type=radio]:checked").length < 1
) {
alert("Please select a Jump-To page before sending.");
} else {
btn.classList.add("button--loading");
submitButton.disabled = true;
SelectData();
}
});
Following SelectData(); are the functions that batch, create and send the HTTP POST request. At the end of all of this, I've attempted to add the following to prevent some type of storage of EACH click event, operating under the assumption that is my problem. That is, that each click is being stored locally in the browser, and thus if number of clicks = 2 then SelectData(); will run twice along with all other functions related to the click event.
submitButton.removeEventListener("click", null);
submitButton.disabled = false;
I was hopeful the above would be my answer, but it has not done anything differently. I'd love some help and am happy to provide more specifics if necessary, but i am stumped. I appreciate your help in pointing me in the right direction!
The second argument for removeEventListener must be exactly the function provided to addEventListener
function myOnClickFunc() {
console.log("oh jolly, a click!")
}
myElement.addEventListener("click", myOnClickFunc)
myElement.removeEventListener("click", myOnClickFunc) // note the exact same object is passed
This would probably fix it. Though it is preferable for you to rewrite your code in a way where you use the same event listener repeatedly instead of removing and readding it.

Not able to shift focus to Shipment Nbr field on Shipments screen

I'm using the built in Acumatica browser commands to insert a new shipment record by pressing a function key. The function Key triggers the command with px.searchFrame(window.top,"main")['px_alls'].ds.executeCommand("Insert"); For some reason, it triggers the insert command, but it doesn't shift the focus to the Shipment Nbr input field. Also, if you try to shift the focus manually using var field=px_alls["edShipmentNbr"]; field.focus(); that doesn't work either. I've been able to shift the focus to other fields, so I know the code is correct, but I can't figure out why the focus can't be shifted to the Shipment Nbr input. Any ideas on what else can be done? It's not just the Insert command either. Calling the Cancel command, which should shift the focus, doesn't work either.
What's strange is that the Insert command can be called by pressing Ctrl+Insert, and it works perfectly.
I built some code that shifts the focus to the ship date field and then tabs backwards 5 times, which emulates correctly what the insert command should do, but it only works intermittently on the client's computer.
Thanks
The Acumatica Framework provides built-in support for keyboard shortcuts via the following properties defined in PXButtonAttribute:
ShortcutShift = true/false : Determines Shift key presence
ShortcutCtrl = true/false : Determines Control key presence
ShortcutChar = ‘x’ : Determines shortcut character
Below is the sample to insert new Shipment when the user presses F2. Since the code snippet below utilizes capabilities of the framework, by pressing F2 the user executes the Insert command from the SOShipmentEntry BLC instead of simulating button click in JavaScript. This approach guarantees that all logic embedded into the Insert command, including setting focus to the Shipment Nbr input, is properly executed.
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
public class PXInsertShortCut<TNode> : PXInsert<TNode>
where TNode : class, IBqlTable, new()
{
public PXInsertShortCut(PXGraph graph, string name)
: base(graph, name)
{
}
public PXInsertShortCut(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.Insert, MapEnableRights = PXCacheRights.Insert, MapViewRights = PXCacheRights.Insert)]
[PXInsertButton(ShortcutChar = (char)113)]
protected override IEnumerable Handler(PXAdapter adapter)
{
return base.Handler(adapter);
}
}
public PXInsertShortCut<SOShipment> Insert;
}
If you're executing a callback to the server in JavaScript, the callback return might set focus to another field after it finishes execution. Your focus() statement works but the callback return performs another focus() on a different control after yours.
Hooking the Ajax callback allows you to put your focus() statement after the Acumatica framework focus():
window.addEventListener('load', function () { px_callback.addHandler(ActionCallback); });
function ActionCallback(callbackContext) {
px_alls["edShipmentNbr"].focus();
};

How do I create a wait event in dojo that waits for a user to click a button before continuing?

I have the following code in a javascript file:
if(dojo.byId('WC_selectedColorNumber') == null && this.defaultColor != null)
{
dijit.byId('WC_color_selection').domNode.style.display = 'block';
dojo.html.set(dojo.query(".message__button .add"), "Add product with only base color " + this.defaultColor + "?");
var userResponse = true;
dojo.connect(WC_add_color_yes, "onclick", function(evt){
userResponse = true;
});
dojo.connect(WC_add_color_no, "onclick", function(evt){
userResponse = false;
});
//var userResponse = confirm("Add product with only base color " + this.defaultColor + "?");
//I WANT TO WAIT HERE FOR THE RESPONSE
if(userResponse == false) //if user clicks Cancel or 'no', display a message and leave the function.
{
alert("Remember to select a color before adding to cart."); //should be a tooltip/popup (not javascript alert) with the same message
return; //return so item doesn't get added to cart
}
}
Firstly, the logic behind this code is correct and it works perfectly well when using javascript confirm's.
As of now, everything comes up and displays correctly, and clicking the buttons perform the correct actions (if I put a console.log in the onclick dojo events, they do indeed print to the console when I click the buttons). However, the program doesn't wait for the responses and continues beyond the dojo.connect methods before it sees the user's input.
I need it to wait until either the yes or no button have been pressed, but I cannot figure out how to do it. I've tried using a
while(userResponse == null);
but a) it's generally a terrible idea and b) it didn't work anyways.
How can I make my code wait until the user has clicked one of the two buttons?
If you can make a jsfiddle I'd be able to help you more, I think, but your dojo.connect calls shouldn't be inside a logic flow like this. Instead, set up your connects on widget startup, and have them act generically.
In your example code, it looks to me like saying "Yes" means "Use default color", and "No" means "User must specify color". So...
startup: function () {
this.inherited(arguments);
dojo.connect(WC_add_color_yes, "onclick", dojo.hitch(this, function(evt){
this.useDefaultColor();
}));
dojo.connect(WC_add_color_no, "onclick", dojo.hitch(this, function(evt){
this.displayColorPicker();
}));
}
And then... only display those two buttons (or the dialog they're hopefully in) when applicable.
There is no "wait" or "sleep" function in javascript and each invocation of javascript code executes to completion (it does not get interrupted in mid execution by a response to some other event). You have correcly identified the historical execeptions that overcome this - global alert and confirm functions execute in browser native code and wait on user input.
Because of this your code will have to be restructured in some way, e.g. an event handler for "add to cart" validates the color choice and calls a function to really add it to the cart if valid. If it is not valid it modifies the DOM to present user with some buttons. The handler for the "yes" option would likewise call the same function to really add it to the cart.
Specific code is outside the scope of this answer - there must be many methods in page and code design to achieve the desired result. For example only: breaking up the sequential code and putting it in separate event handlers, coding using Promise objects defined in EC6 but not supported in MSIE, or perhaps even providing an option of "none - base color only" in the color selection logic.
FYI the dojo 1.10 toolkit documentation reports support for Dojo Promises but I leave research to determine its suitability with you.

How to have function trigger from a keypress in node?

I have a script written in javascript which does something to a drone that I have. As of now I run that script in my shell like this node foo.js and the script runs till I abort it using control C. But now I want to be able to run that script and have it listen for keyboard events that I give it (such as ENTER, up/down arrow key, spacebar), and depending on the event it performs a specific function. And when I am done I should be still able to press control C to stop the program. It would be awesome if someone could help me. I am still in highschool and very new to programming.
Here is the script for reference:
var arDrone = require('ar-drone');
var client = arDrone.createClient();
client.takeoff();
client
.after(10000, function() {
this.stop();
this.land();
});
Each keyboard key has a special key code (i.e. f = 70). You can find that here:
http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
I would use jQuery to trigger these events, the first is any keystroke:
$(function() {
$('client').keydown();
$('client').keypress();
$('client').keyup();
});
The second is specific keystrokes:
$function() {
var e = $.Event('keypress');
e.which = 39; // right arrow
$('client').trigger(e);
});
So then you would have a function called trigger that checked for specific numbers, and you would move your drone accordingly.

Finding function catching key event in Javascript?

I'm writing a user script for a complex web app. The existing code is catching the 'j' and 'k' keydown events.
I'd like to be able to find this function to see what it's doing. Is there a way to list all the key event handlers in a document? Or maybe a way to set a breakpoint somehow in Chrome Developer Tools for when I press the letter?
Yes, in the developer tools, go to the Scripts tab, select the page, go to Event Listener Breakpoints, Keyboard, keydown.
Though this might not necessarily help you much, e.g. if the script is minified or they use a library. But you can give it a try.
If you can get a piece of your script to run first and if the keys are handled at the document level, you can install this intercept to see what part of the code is setting the keyboard handler:
var oldListener = document.addEventListener;
document.addEventListener = function(type, listener, capture) {
if (type == "keydown" || type == "keyup" || type == "keypress") {
console.log("type=" + type + " listener=" + listener.toString().slice(0, 80));
}
return (oldListener.apply(this, arguments));
}

Categories