Issue
I'm trying to stream my global mouse cursor position to a web client using a super simple websocket.
I've got both of those things happening, and my client (in JS) works fine, but I don't know how to connect them; I want to send a websocket message whenever on move()
is called, but everything I've tried throws an error.
This code prints out mouse locations and runs the websocket, but how can I get the two to 'talk' to each other?
import asyncio
import websockets
from pynput import mouse
def onmove(x, y):
print(x,y)
async def socket_handler(websocket, path):
while True:
message = await websocket.recv()
print(f"Received {message}")
resp = f'WS Message Was: {message}'
await websocket.send(resp)
listener = mouse.Listener(on_move = onmove)
listener.start()
start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
I feel like there must be a really obvious answer and I just don't understand async and event loops well enough
Solution
You've got multiple threads going there with your pynput and asyncio stuff. To share data across threads, you need a thread-safe container. One option for that is python's queue module.
A much better option-- from an asyncio perspective--, as pointed out in the comments by user4815162342, is to use asyncio's Queue and a call_soon_threadsafe on asyncio's event_loop from your other thread. Here's an example of that:
import asyncio
import json
import websockets
from pynput import mouse
q = asyncio.Queue()
def onmove(x, y):
loop.call_soon_threadsafe(q.put_nowait, (x,y))
async def socket_handler(websocket, path):
while True:
message = await q.get()
await websocket.send(json.dumps(message))
loop = asyncio.get_event_loop()
start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
loop.run_until_complete(start_server)
listener = mouse.Listener(on_move = onmove)
listener.start()
loop.run_forever()
Old example using a standard queue.Queue.
example_server.py
import asyncio
import queue
import json
import websockets
from pynput import mouse
q = queue.SimpleQueue()
def onmove(x, y):
try:
print("Putting: {0}".format((x,y)))
q.put((x,y), block=False)
except q.Full:
print("Dropped coords: {0}".format((x,y)))
async def getCoords():
coords = None
try:
coords = q.get(block=False)
except queue.Empty:
# print("QUEUE EMPTY")
pass
return coords
async def socket_handler(websocket, path):
while True:
message = await getCoords()
if message:
await websocket.send(json.dumps(message))
listener = mouse.Listener(on_move = onmove)
listener.start()
loop = asyncio.get_event_loop()
start_server = websockets.serve(socket_handler, "127.0.0.1", 5000)
loop.run_until_complete(start_server)
loop.run_forever()
example_client.html
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script>
$(function() {
var exampleSocket = new WebSocket("ws://127.0.0.1:5000");
exampleSocket.onmessage = function (event) {
var coords = JSON.parse(event.data);
$('#x').html(coords[0]);
$('#y').html(coords[1]);
};
});
</script>
</head>
<body>
<p>X: <span id="x"></span></p>
<p>Y: <span id="y"></span></p>
</body>
</html>
Answered By - clockwatcher
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.