5

For electron applications, is there a way for me to simulate keyboard stroke actions. For example, sending the letter 'a' to the app level rather than the front end level. Another example would be for mac to simulate programmatically the command (hold) and tab to shift between applications, this triggered from electron.

I tried things like BrowserWindow.webContents.sendInputEvent and robotjs without any success so if you feel like you have a working example that would be great. I am using the electron-react-boilerplate as the starting point for these, and am using a mac os X!

EDIT: example > on a click of a button within the electron app, I want electron to fire some keyboard events to the OS level such as (cmd + tab + tab + tab, cmd + Q), in order to see my native app switch between apps and then to quit one of those. Please note that I am not interested in going through the process pid route, just keyboard manipulation.

Jules Moretti
  • 127
  • 1
  • 10
  • What is the intended use case? If you are trying to access functionality outside of the electron app itself, the answer is yes but requires a dangerous amount of privilege. Also, what do you mean by app-level as opposed to front-end level? Reactjs is a front end framework, and is normally referred to as an 'app' – Andrew May 14 '18 at 05:24
  • If I'm understood your question as it was intended (and assuming you're not looking to access functionality outside of your Electron app as @Andrew mentions), does [global shortcuts](https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md) do what you want? (If by the `app` level, you mean the `main` or `background` process). – Neil P. May 14 '18 at 15:33
  • @Andrew - I updated my original post with a use case. I am trying to access the functionality outside of the electron app itself. So how would you recommend I achieve this for both mac and windows? What I meant between the app-level vs front-end means within the react front-end environment and the OS environment. – Jules Moretti May 14 '18 at 18:36
  • @Neil - Thank you, and I am looking for functionality outside the electron app. Sorry for the confusion guys :) – Jules Moretti May 14 '18 at 18:36

2 Answers2

1

This should push you in the right direction.

Is it possible to simulate keyboard/mouse event in NodeJS?

You might hit permission errors when you run your app. You have to enable node-level permissions in your electron entry file in the BrowserWindow object.

let BrowserWindowProps = {
    // and all your other parameters...
    webPreferences: {nodeIntegration: true}
};
mainWindow = new BrowserWindow(BrowserWindowProps);
Andrew
  • 7,201
  • 5
  • 25
  • 34
  • Thank you very much for this, I tried implementing the `robotjs` example within a new `electron-react-boilerplate` project but that lead to errors. Sadly I do not think that this repo is any longer maintained. – Jules Moretti May 15 '18 at 17:40
  • 1
    @JulesMoretti I wish I could help you more, but this is now out of my domain of expertise. All I can concretely provide to you is the fact that you need to set `nodeIntegration: true` – Andrew May 15 '18 at 19:28
1

The most reliable way I have found so far was to send three events for one keystroke.

For instance, to send F1, I would do the following:

browserWindow.webContents.sendInputEvent({keyCode: "F1", type: "keyDown"});
browserWindow.webContents.sendInputEvent({keyCode: "F1", type: "char"});
browserWindow.webContents.sendInputEvent({keyCode: "F1", type: "keyUp"});

Available key codes:

https://www.electronjs.org/docs/latest/api/accelerator#available-key-codes


And here is a quick script for a whole sequence (F5, Shift+Tab, Space, Ctrl+] )

function sendKey(entry, delay)
{
    ["keyDown", "char", "keyUp"].forEach(async(type) =>
    {
        entry.type = type;
        browserWindow.webContents.sendInputEvent(entry);

        // Delay
        await new Promise(resolve => setTimeout(resolve, delay));
    });
}

async function sendSequence(sequence, delay)
{
    for (const entry of sequence)
    {
        await sendKey(entry, delay);
        await new Promise(resolve => setTimeout(resolve, delay));
    }
}

const sequence = [
    {keyCode: "F5"},
    {keyCode: "Tab", modifiers: ["Shift"]},
    {keyCode: "space"},
    {keyCode: "]", modifiers: ["Ctrl"]},
];

await sendSequence(sequence, 200);

Note: It also works when "nodeIntegration" is false or "contextIsolation" is true.