simple-rdp 0.8.2__tar.gz → 0.8.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/Cargo.lock +1 -1
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/Cargo.toml +1 -1
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/PKG-INFO +1 -1
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/pyproject.toml +1 -1
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/client.py +16 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/display.py +47 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.env.example +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.github/workflows/ci.yml +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.github/workflows/cleanup.yml +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.github/workflows/docs.yml +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.gitignore +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/.pre-commit-config.yaml +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/LICENSE +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/MS-RDPBCGR.txt +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/Makefile +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/README.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/agents/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/agents/tools/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/agents/tools/analyze_image.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/api/client.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/api/display.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/api/input.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/development/contributing.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/development/performance.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/development/protocol.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/examples/automation.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/examples/browser-viewer.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/getting-started/configuration.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/getting-started/installation.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/getting-started/quickstart.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/getting-started/testing.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/guide/keyboard-input.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/guide/mcp-server.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/guide/mouse-input.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/guide/pointer.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/guide/screen-capture.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/includes/abbreviations.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/docs/index.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/example.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/examples/browser/README.md +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/examples/browser/app.js +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/examples/browser/index.html +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/examples/browser/server.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/examples/browser/style.css +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/mkdocs.yml +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/poetry.lock +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/rust/src/lib.rs +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/capabilities.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/credssp.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/input.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/mcs.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp/pdu.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp_mcp/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/src/simple_rdp_mcp/server.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/__init__.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_basic_connection.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_display.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_fps_limits.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_graphics.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_graphics_profiled.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_performance.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_performance_mouse.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_pointer_visibility.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/e2e/test_video_recording.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_capabilities.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_client.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_credssp.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_display.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_input.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_mcs.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_pdu.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_rle.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/tests/test_screen.py +0 -0
- {simple_rdp-0.8.2 → simple_rdp-0.8.4}/uv.lock +0 -0
|
@@ -409,6 +409,22 @@ class RDPClient:
|
|
|
409
409
|
"""
|
|
410
410
|
return await self._display.screenshot()
|
|
411
411
|
|
|
412
|
+
async def pointer_area_screenshot(self) -> tuple[Image.Image, tuple[int, int], tuple[int, int]]:
|
|
413
|
+
"""
|
|
414
|
+
Capture a cropped area around the pointer position.
|
|
415
|
+
|
|
416
|
+
The crop is 1/3 width x 1/3 height of the display (1/9 of total area),
|
|
417
|
+
centered on the pointer position when possible. When the pointer is
|
|
418
|
+
near edges, the crop is clamped to stay within display bounds.
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
Tuple of (cropped_image, (top_x, top_y), (bottom_x, bottom_y)) where:
|
|
422
|
+
- cropped_image: Cropped region with pointer composited
|
|
423
|
+
- (top_x, top_y): Top-left corner position of crop relative to display
|
|
424
|
+
- (bottom_x, bottom_y): Bottom-right corner position of crop relative to display
|
|
425
|
+
"""
|
|
426
|
+
return await self._display.pointer_area_screenshot()
|
|
427
|
+
|
|
412
428
|
async def save_screenshot(self, path: str) -> None:
|
|
413
429
|
"""
|
|
414
430
|
Save a screenshot to a file.
|
|
@@ -528,6 +528,53 @@ class Display:
|
|
|
528
528
|
img.save(path)
|
|
529
529
|
logger.info(f"Screenshot saved to {path}")
|
|
530
530
|
|
|
531
|
+
async def pointer_area_screenshot(self) -> tuple[Image.Image, tuple[int, int], tuple[int, int]]:
|
|
532
|
+
"""
|
|
533
|
+
Capture a cropped area around the pointer position.
|
|
534
|
+
|
|
535
|
+
The crop is 1/3 width x 1/3 height of the display (1/9 of total area),
|
|
536
|
+
centered on the pointer position when possible. When the pointer is
|
|
537
|
+
near edges, the crop is clamped to stay within display bounds.
|
|
538
|
+
|
|
539
|
+
Returns:
|
|
540
|
+
Tuple of (cropped_image, (top_x, top_y), (bottom_x, bottom_y)) where:
|
|
541
|
+
- cropped_image: Cropped region with pointer composited
|
|
542
|
+
- (top_x, top_y): Top-left corner position of crop relative to display
|
|
543
|
+
- (bottom_x, bottom_y): Bottom-right corner position of crop relative to display
|
|
544
|
+
"""
|
|
545
|
+
async with self._screen_lock:
|
|
546
|
+
if self._raw_display_image is None:
|
|
547
|
+
crop_w = self._width // 3
|
|
548
|
+
crop_h = self._height // 3
|
|
549
|
+
return (Image.new("RGB", (crop_w, crop_h), (0, 0, 0)), (0, 0), (crop_w, crop_h))
|
|
550
|
+
|
|
551
|
+
# Update final display image if dirty
|
|
552
|
+
if self._final_display_image_dirty or self._final_display_image is None:
|
|
553
|
+
self._update_final_display_image()
|
|
554
|
+
|
|
555
|
+
assert self._final_display_image is not None
|
|
556
|
+
|
|
557
|
+
# Calculate crop dimensions (1/3 of display)
|
|
558
|
+
crop_w = self._width // 3
|
|
559
|
+
crop_h = self._height // 3
|
|
560
|
+
|
|
561
|
+
# Calculate ideal top-left to center pointer
|
|
562
|
+
top_x = self._pointer_x - crop_w // 2
|
|
563
|
+
top_y = self._pointer_y - crop_h // 2
|
|
564
|
+
|
|
565
|
+
# Clamp to display bounds
|
|
566
|
+
top_x = max(0, min(top_x, self._width - crop_w))
|
|
567
|
+
top_y = max(0, min(top_y, self._height - crop_h))
|
|
568
|
+
|
|
569
|
+
# Calculate bottom-right corner
|
|
570
|
+
bottom_x = top_x + crop_w
|
|
571
|
+
bottom_y = top_y + crop_h
|
|
572
|
+
|
|
573
|
+
# Crop the image
|
|
574
|
+
cropped = self._final_display_image.crop((top_x, top_y, bottom_x, bottom_y))
|
|
575
|
+
|
|
576
|
+
return (cropped.copy(), (top_x, top_y), (bottom_x, bottom_y))
|
|
577
|
+
|
|
531
578
|
async def apply_bitmap(
|
|
532
579
|
self,
|
|
533
580
|
x: int,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|