-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Capture Command Hangs #267
Comments
|
Same issue with vncdotool 1.2.0 and wayvnc 0.8.0. Any updates? |
Since #!/usr/bin/env python3
#
# SPDX-License-Identifier: GPL-3.0
#
# Copyright 2024 Johannes Schauer Marin Rodrigues <[email protected]>
#
# inspired by https://github.com/barneygale/pytest-vnc
# Copyright 2022 - 2023, Barney Gale <[email protected]>
import socket
from collections import namedtuple
from dataclasses import field
from PIL import Image
import numpy
import time
import sys
from keysymdef import keysymdef
Point = namedtuple("Point", "x y")
Rect = namedtuple("Rect", "x y width height")
pixel_formats = {
"rgba": b"\x20\x18\x00\x01\x00\xff\x00\xff\x00\xff\x00\x08\x10\x00\x00\x00",
}
encodings = {
6, # zlib
}
key_codes = {}
key_codes.update((name, code) for name, code, char in keysymdef)
key_codes.update((chr(char), code) for name, code, char in keysymdef if char)
def write_mouse(sock, buttons, position):
sock.sendall(
b"\x05"
+ buttons.to_bytes(1, "big")
+ position.x.to_bytes(2, "big")
+ position.y.to_bytes(2, "big")
)
time.sleep(0.05)
def slice_rect(rect, *channels):
return (
slice(rect.y, rect.y + rect.height),
slice(rect.x, rect.x + rect.width),
) + channels
def capture(sock, rect: Rect):
sock.sendall(
b"\x03\x00"
+ rect.x.to_bytes(2, "big")
+ rect.y.to_bytes(2, "big")
+ rect.width.to_bytes(2, "big")
+ rect.height.to_bytes(2, "big")
)
pixels = numpy.zeros((rect.height, rect.width, 4), "B")
while True:
update_type = read_int(sock, 1)
assert update_type == 0 # video
read(sock, 1) # padding
for _ in range(read_int(sock, 2)):
area_rect = Rect(
read_int(sock, 2),
read_int(sock, 2),
read_int(sock, 2),
read_int(sock, 2),
)
area_encoding = read_int(sock, 4)
assert area_encoding == 0 # raw not compressed
area = read(sock, area_rect.height * area_rect.width * 4)
area = numpy.ndarray((area_rect.height, area_rect.width, 4), "B", area)
pixels[slice_rect(area_rect)] = area
pixels[slice_rect(area_rect, 3)] = 255
if pixels[slice_rect(rect, 3)].all():
return pixels[slice_rect(rect)]
def read(sock: socket, length: int) -> bytes:
data = b""
while len(data) < length:
data += sock.recv(length - len(data))
return data
def read_int(sock: socket, length: int) -> int:
return int.from_bytes(read(sock, length), "big")
def move(sock, point):
write_mouse(sock, 0, point)
time.sleep(1)
def click(sock, point):
write_mouse(sock, 1, point)
time.sleep(1)
write_mouse(sock, 0, point)
time.sleep(1)
def keypress(sock, key):
data = key_codes[key].to_bytes(4, "big")
sock.sendall(b"\x04\x01\x00\x00" + data)
time.sleep(0.1)
sock.sendall(b"\x04\x00\x00\x00" + data)
time.sleep(1)
def screenshot(sock, rect, filename):
pixels = capture(sock, rect)
image = Image.fromarray(pixels)
image.save(filename)
class RecvNullExc(Exception):
pass
def connect():
for i in range(100):
try:
sock = socket.create_connection(("127.0.0.1", 5910), timeout=5)
print("connected", file=sys.stderr)
intro = sock.recv(12)
if len(intro) != 12:
raise RecvNullExc
print("received intro", file=sys.stderr)
except ConnectionRefusedError:
print("trying to connect...", file=sys.stderr)
time.sleep(2)
pass
except RecvNullExc:
print("cannot read, retrying...", file=sys.stderr)
time.sleep(2)
pass
else:
print("leaving loop", file=sys.stderr)
break
assert intro[:4] == b"RFB "
sock.sendall(b"RFB 003.008\n")
num_auth_types = read_int(sock, 1)
assert num_auth_types == 1, num_auth_types
auth_type = int.from_bytes(read(sock, num_auth_types))
assert auth_type == 1, auth_type
sock.sendall(b"\x01")
auth_result = read_int(sock, 4)
assert auth_result == 0
sock.sendall(b"\x01")
width, height = read_int(sock, 2), read_int(sock, 2)
assert (width, height) == (1920, 1080)
rect = Rect(0, 0, width, height)
read(sock, 16)
read(sock, read_int(sock, 4))
sock.sendall(
b"\x00\x00\x00\x00"
+ pixel_formats["rgba"]
+ b"\x02\x00"
+ len(encodings).to_bytes(2, "big")
+ b"".join(encoding.to_bytes(4, "big") for encoding in encodings)
)
return sock, rect
def main():
sock = None
rect = None
mousepos = Point(0, 0)
for line in sys.stdin:
if line.startswith("#"):
continue
line = line.strip()
tokens = line.split()
if len(tokens) < 1:
raise Exception("no tokens")
match tokens[0]:
case "connect":
sock, rect = connect()
case "sleep":
if len(tokens) != 2:
raise Exception(f"missing argument {line}")
time.sleep(float(tokens[1]))
case "capture":
if len(tokens) != 2:
raise Exception(f"missing argument {line}")
if sock is None or rect is None:
raise Exception("must connect first")
screenshot(sock, rect, tokens[1])
case "key":
if len(tokens) != 2:
raise Exception(f"missing argument {line}")
keypress(sock, tokens[1])
case "mousemove":
if len(tokens) != 3:
raise Exception(f"missing argument {line}")
mousepos = Point(int(tokens[1]), int(tokens[2]))
move(sock, mousepos)
case "click":
click(sock, mousepos)
case _:
raise Exception(f"unknown command: {tokens[0]}")
if sock is not None:
sock.close()
if __name__ == "__main__":
main() It can be used like this: cat << END | python3 vnc.py
connect
sleep 20
mousemove 1050 625
capture test.png
click
key p
sleep 1
key Tab The Have fun! :) |
Hello, I encounter the same problem. I'm using Windows 10, vncdotool 1.2.0, VNC server of MFP Sharp. I really need the capture screen function to do GUI test, can someone give me a hint of what's happening ? Thank you
|
great solution -- how to send username and password over the socket?
|
@gailrosen The script is inspired by https://github.com/barneygale/pytest-vnc so you can find missing implementations there ! |
Please include the following information:
vncdotool version
1.2.0
VNC server and version
WayVNC 0.6.2
Steps to reproduce:
Output:
Expected result
I expected the command to complete and produce a file.
Which erroneous result did you get instead
The command never completes. I have to interrupt it.
Additional information
Other
vncdotool
commands do work just fine, such astype
.The text was updated successfully, but these errors were encountered: