Search code examples
pythonnode.jschild-processpynput

How to communicate between NodeJS and Python (pynput) with child process


I made a script in python which uses pynput and displays the keys pressed from a keyboard in the console.

from pynput.keyboard import Listener

def on_press(key):
    try:
        print('keydown : {0}'.format(
            key.char))
    except AttributeError:
        print('keydown : {0}'.format(
            key))

def on_release(key):
    try:
        print('keyup : {0}'.format(
            key.char))
    except AttributeError:
        print('keyup : {0}'.format(
            key))


with Listener(on_press=on_press, on_release=on_release) as listener:  
    listener.join()

I point out that I have never made a python in my life, and that this code works when I run it. We get the expected result :

keydown : a
keyup : a
keydown : b
keyup : b
keydown : Key.enter
keyup : Key.enter

However, I want to run it in a child process with NodeJS :

const child = require('child_process')
var py = child.spawn('python3', ['myFile.py'])
py.sdout.on('data', (data) => { console.log(data.toString()) })
py.stderr.on('data', (data) => { console.error(data.toString()) })

But when I execute the javascript file with NodeJS, I do not receive any data or error when I press a key ... Yet my child process works with any other python script...

If anyone knows why I can't do it or knows a solution, thank you in advance for their response.


Solution

  • As I pointed out in the comments, your Node.js app does not pass its input stream to its child process, nor its child process finishes for their parent to read their output. So here's an example that works, but only reads the first keypress before finishing:

    Node.js (same script, but we pipe the keypresses to the child process):

    const { spawn } = require('child_process');
    const readline = require('readline');
    
    const py = spawn('python3', ['/home/telmo/Desktop/myFile.py']);
    
    readline.emitKeypressEvents(py.stdin);
    process.stdin.setRawMode(true);
    
    py.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });
    
    py.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });
    
    py.on('close', (code) => {
      console.log(`child process exited with code ${code}`);
    });
    

    Python (same script, but we finish after the first key up event):

    from pynput.keyboard import Listener
    import sys
    
    def on_press(key):
        try:
            print('keydown : {0}'.format(
                key.char))
        except AttributeError:
            print('keydown : {0}'.format(
                key))
    
    def on_release(key):
        try:
            print('keyup : {0}'.format(
                key.char))
            sys.exit()
        except AttributeError:
            print('keyup : {0}'.format(
                key))
    
    with Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()
    

    Running these when I pressed 'a' I got the following output:

    stdout: keyup : Key.enter
    keydown : a
    keyup : a
    
    child process exited with code 0