A Function Callback Every Time a Key Is Pressed (Regardless of Which Window Has Focus)

A function callback every time a key is pressed (regardless of which window has focus)?

Take a look at what others have done already. You can take a look on how this pykeylogger code handles Linux in its backend, and see if that works for you.

A function callback every time a key is pressed (regardless of which window has focus)?

Take a look at what others have done already. You can take a look on how this pykeylogger code handles Linux in its backend, and see if that works for you.

Detect Key Press on Windows Without Window Focus

If you want to detect 'key press' events occurred in other processes, you should implement Global Hook. You can define a callback function for keyboard input events using SetWindowsHookEx().

Note that the callback function must be in a DLL in order to make it Global Hook.

So your myprogram.exe should link a dll implementing the hook. Then myprogram.exe would be able to detect any keyboard events on Windows.

Following is a good example with an explanation.
http://www.codeproject.com/Articles/1264/KeyBoard-Hooks

Event when form is about to get focus?

Impoerant:, I agree with Jimi's and jmcilhinney's comments and I also
believe it's not the right way of implementing an on-screen keyboard,
but this post it just trying to help you on:

  • Finding handle of the deactivated window when
    this window has been activated
    .

Find handle of the deactivated window when this window has been activated

You can use SetWinEventHook you can to listen to some events from other processes and register a WinEventProc callback method to receive the event when the event raised.

Here we are interested in EVENT_SYSTEM_FOREGROUND. Every time that we receive this event, if the activated window is not our form, we track the window which has been activated, then when our window is activated we look into the value of tracked window which is now the previous window which has lost its focus.

C#

Here is the code that I tried and worked well for me:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyForm : Form
{
public const uint EVENT_SYSTEM_FOREGROUND = 0x0003;
public const uint EVENT_OBJECT_DESTROY = 0x8001;
public const uint WINEVENT_OUTOFCONTEXT = 0;

public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild,
uint dwEventThread, uint dwmsEventTime);

[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax,
IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc,
uint idProcess, uint idThread, uint dwFlags);

[DllImport("user32.dll")]
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

IntPtr hook = IntPtr.Zero;
protected override void OnLoad(EventArgs e)
{
previous = GetForegroundWindow();
hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero, new WinEventDelegate(WinEventProc),
0, 0, WINEVENT_OUTOFCONTEXT);
base.OnLoad(e);
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
UnhookWinEvent(hook);
base.OnFormClosing(e);
}
IntPtr? previous = null;
void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread,
uint dwmsEventTime)
{
if (hwnd != this.Handle)
{
previous = hwnd;
}
else
{
if (previous.HasValue)
this.Text = $"Previous window: {(int)previous:X}";
else
this.Text = $"No idea about previous window.";
}
}
}

VB.NET

Imports System.Runtime.InteropServices

Public Class MyForm
Inherits Form

Public Const EVENT_SYSTEM_FOREGROUND As UInteger = &H3
Public Const EVENT_OBJECT_DESTROY As UInteger = &H8001
Public Const WINEVENT_OUTOFCONTEXT As UInteger = 0
Public Delegate Sub WinEventDelegate(ByVal hWinEventHook As IntPtr,
ByVal eventType As UInteger,
ByVal hwnd As IntPtr,
ByVal idObject As Integer,
ByVal idChild As Integer,
ByVal dwEventThread As UInteger,
ByVal dwmsEventTime As UInteger)
<DllImport("user32.dll")>
Public Shared Function SetWinEventHook(ByVal eventMin As UInteger,
ByVal eventMax As UInteger,
ByVal hmodWinEventProc As IntPtr,
ByVal lpfnWinEventProc As WinEventDelegate,
ByVal idProcess As UInteger,
ByVal idThread As UInteger,
ByVal dwFlags As UInteger) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function UnhookWinEvent(ByVal hWinEventHook As IntPtr) As Boolean
End Function
<DllImport("user32.dll")>
Private Shared Function GetForegroundWindow() As IntPtr
End Function
Private hook As IntPtr = IntPtr.Zero
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
previous = GetForegroundWindow()
hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
New WinEventDelegate(AddressOf WinEventProc),
0, 0, WINEVENT_OUTOFCONTEXT)
MyBase.OnLoad(e)
End Sub

Protected Overrides Sub OnFormClosing(ByVal e As FormClosingEventArgs)
UnhookWinEvent(hook)
MyBase.OnFormClosing(e)
End Sub

Private previous As IntPtr? = Nothing

Private Sub WinEventProc(ByVal hWinEventHook As IntPtr,
ByVal eventType As UInteger,
ByVal hwnd As IntPtr,
ByVal idObject As Integer,
ByVal idChild As Integer,
ByVal dwEventThread As UInteger,
ByVal dwmsEventTime As UInteger)
If hwnd <> Me.Handle Then
previous = hwnd
Else

If previous.HasValue Then
Me.Text = $"Previous window: {CInt(previous):X}"
Else
Me.Text = $"No idea about previous window."
End If
End If
End Sub
End Class

How to fix this script so that it won't peg the CPU?

You can start your script using nice. The nice command will lower the priority of your script, so that it will only run when the system has nothing else to do. That way it will still eat CPU cycles, but you will be able to use your system normally for other tasks.

See the man page for details.

EDIT:

To reduce CPU usage, you could add a small delay, using time.sleep(0.01). This will reduce the CPU load, but will marginally increase the time between the keypress and the resulting beep.

onKeyDown / onKeyUp listener in React

Using onKeyDown on a certain element will require focus to work as intended.

We can make your MdOutlinePause component focus-able by adding the tabindex attribute. That will allow you to give the icon focus by hitting tab or by clicking on it. The element would look something like this:

<MdOutlinePause tabIndex={0} onKeyDown={handleKey} />

If you want to detect the key event without having to focus the element, you will need to attach an event listener. We can do this with useEffect so this happens onMount, and we'll attach the event listener to the window so it works regardless of which element has focus:

  /// Don't copy and paste this - see below
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
});
}, []);
/// Don't copy and paste this - see below

This allows you to detect the keyboard event, which is great, but there's an issue: the eventListener gets added again whenever the page mounts, but is never removed. So you will likely run into issues of your function getting called multiple times on each keyPress.

We can fix this by removing the event listener in the return from useEffect. This is how we specify a function to let the useEffect clean up after itself. This ensures that our useEffect is never adding more than one "keydown" event listener at a time:

  useEffect(() => {
window.addEventListener("keydown", handleKeyPress);

return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);

Here's a full example on codesandbox

This works great if you don't need to access state in your handleKeyPress function.


It is a common use case to need to do something with state variables when the user does a certain action, and if we need to access updated state then we run into a problem: we attached handleKeyPress to the event listener onMount and the function never gets updated, so it will always use the initial version of state. This codesandbox illustrates the issue.

We can fix this by adding handleKeyPress to the dependencies array for useEffect, but this results in our event listener being removed and re-added on every render since handleKeyPress will be updated on each render. A better solution is to use the callback pattern with our handleKeyPress so that it is only updated when actually necessary (when the state it depends on is updated). We also want to add handleKeyPress to our useEffect dependency array so we create a new event listener when the handleKeyPress function changes:

  const handleKeyPress = useCallback((event) => {
// do stuff with stateVariable and event
}, [stateVariable]);

useEffect(() => {
window.addEventListener("keydown", handleKeyPress);

return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, [handleKeyPress]);

Now everything updates appropriately! Here's a full example of this on codesandbox.


There's one more solution which lets you access state in the simplest way possible. The downside is that the only state variable you have access to (with updated values) will be the state variable you are updating, so this solution is situational. To access other state variables, you'll have to use the solution above.

By passing a function to useState, we can access the previous state as the first argument of the function. This allows for a much simpler approach, shown below and in this codesandbox.

  const [text, setText] = useState("");

const handleKeyPress = event => {
setText(previousText => `${previousText}${event.key}`);
};

useEffect(() => {
window.addEventListener("keydown", handleKeyPress);

return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);

How to access the correct `this` inside a callback

What you should know about this

this (aka "the context") is a special keyword inside each function and its value only depends on how the function was called, not how/when/where it was defined. It is not affected by lexical scopes like other variables (except for arrow functions, see below). Here are some examples:

function foo() {
console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

To learn more about this, have a look at the MDN documentation.



How to refer to the correct this

Use arrow functions

ECMAScript 6 introduced arrow functions, which can be thought of as lambda functions. They don't have their own this binding. Instead, this is looked up in scope just like a normal variable. That means you don't have to call .bind. That's not the only special behavior they have, please refer to the MDN documentation for more information.

function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}

Don't use this

You actually don't want to access this in particular, but the object it refers to. That's why an easy solution is to simply create a new variable that also refers to that object. The variable can have any name, but common ones are self and that.

function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}

Since self is a normal variable, it obeys lexical scope rules and is accessible inside the callback. This also has the advantage that you can access the this value of the callback itself.

Explicitly set this of the callback - part 1

It might look like you have no control over the value of this because its value is set automatically, but that is actually not the case.

Every function has the method .bind [docs], which returns a new function with this bound to a value. The function has exactly the same behavior as the one you called .bind on, only that this was set by you. No matter how or when that function is called, this will always refer to the passed value.

function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}

In this case, we are binding the callback's this to the value of MyConstructor's this.

Note: When a binding context for jQuery, use jQuery.proxy [docs] instead. The reason to do this is so that you don't need to store the reference to the function when unbinding an event callback. jQuery handles that internally.

Set this of the callback - part 2

Some functions/methods which accept callbacks also accept a value to which the callback's this should refer to. This is basically the same as binding it yourself, but the function/method does it for you. Array#map [docs] is such a method. Its signature is:

array.map(callback[, thisArg])

The first argument is the callback and the second argument is the value this should refer to. Here is a contrived example:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Note: Whether or not you can pass a value for this is usually mentioned in the documentation of that function/method. For example, jQuery's $.ajax method [docs] describes an option called context:

This object will be made the context of all Ajax-related callbacks.



Common problem: Using object methods as callbacks/event handlers

Another common manifestation of this problem is when an object method is used as callback/event handler. Functions are first-class citizens in JavaScript and the term "method" is just a colloquial term for a function that is a value of an object property. But that function doesn't have a specific link to its "containing" object.

Consider the following example:

function Foo() {
this.data = 42,
document.body.onclick = this.method;
}

Foo.prototype.method = function() {
console.log(this.data);
};

The function this.method is assigned as click event handler, but if the document.body is clicked, the value logged will be undefined, because inside the event handler, this refers to the document.body, not the instance of Foo.

As already mentioned at the beginning, what this refers to depends on how the function is called, not how it is defined.

If the code was like the following, it might be more obvious that the function doesn't have an implicit reference to the object:

function method() {
console.log(this.data);
}

function Foo() {
this.data = 42,
document.body.onclick = this.method;
}

Foo.prototype.method = method;

The solution is the same as mentioned above: If available, use .bind to explicitly bind this to a specific value

document.body.onclick = this.method.bind(this);

or explicitly call the function as a "method" of the object, by using an anonymous function as callback / event handler and assign the object (this) to another variable:

var self = this;
document.body.onclick = function() {
self.method();
};

or use an arrow function:

document.body.onclick = () => this.method();


Related Topics



Leave a reply



Submit