simple-rdp 0.8.2__tar.gz → 0.8.3__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.
Files changed (76) hide show
  1. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/Cargo.lock +1 -1
  2. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/Cargo.toml +1 -1
  3. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/PKG-INFO +1 -1
  4. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/pyproject.toml +1 -1
  5. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/client.py +15 -0
  6. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/display.py +42 -0
  7. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.env.example +0 -0
  8. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.github/workflows/ci.yml +0 -0
  9. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.github/workflows/cleanup.yml +0 -0
  10. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.github/workflows/docs.yml +0 -0
  11. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.gitignore +0 -0
  12. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/.pre-commit-config.yaml +0 -0
  13. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/LICENSE +0 -0
  14. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/MS-RDPBCGR.txt +0 -0
  15. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/Makefile +0 -0
  16. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/README.md +0 -0
  17. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/agents/__init__.py +0 -0
  18. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/agents/tools/__init__.py +0 -0
  19. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/agents/tools/analyze_image.py +0 -0
  20. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/api/client.md +0 -0
  21. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/api/display.md +0 -0
  22. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/api/input.md +0 -0
  23. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/development/contributing.md +0 -0
  24. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/development/performance.md +0 -0
  25. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/development/protocol.md +0 -0
  26. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/examples/automation.md +0 -0
  27. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/examples/browser-viewer.md +0 -0
  28. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/getting-started/configuration.md +0 -0
  29. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/getting-started/installation.md +0 -0
  30. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/getting-started/quickstart.md +0 -0
  31. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/getting-started/testing.md +0 -0
  32. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/guide/keyboard-input.md +0 -0
  33. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/guide/mcp-server.md +0 -0
  34. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/guide/mouse-input.md +0 -0
  35. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/guide/pointer.md +0 -0
  36. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/guide/screen-capture.md +0 -0
  37. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/includes/abbreviations.md +0 -0
  38. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/docs/index.md +0 -0
  39. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/example.py +0 -0
  40. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/examples/browser/README.md +0 -0
  41. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/examples/browser/app.js +0 -0
  42. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/examples/browser/index.html +0 -0
  43. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/examples/browser/server.py +0 -0
  44. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/examples/browser/style.css +0 -0
  45. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/mkdocs.yml +0 -0
  46. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/poetry.lock +0 -0
  47. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/rust/src/lib.rs +0 -0
  48. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/__init__.py +0 -0
  49. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/capabilities.py +0 -0
  50. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/credssp.py +0 -0
  51. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/input.py +0 -0
  52. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/mcs.py +0 -0
  53. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp/pdu.py +0 -0
  54. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp_mcp/__init__.py +0 -0
  55. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/src/simple_rdp_mcp/server.py +0 -0
  56. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/__init__.py +0 -0
  57. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/__init__.py +0 -0
  58. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_basic_connection.py +0 -0
  59. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_display.py +0 -0
  60. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_fps_limits.py +0 -0
  61. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_graphics.py +0 -0
  62. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_graphics_profiled.py +0 -0
  63. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_performance.py +0 -0
  64. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_performance_mouse.py +0 -0
  65. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_pointer_visibility.py +0 -0
  66. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/e2e/test_video_recording.py +0 -0
  67. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_capabilities.py +0 -0
  68. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_client.py +0 -0
  69. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_credssp.py +0 -0
  70. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_display.py +0 -0
  71. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_input.py +0 -0
  72. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_mcs.py +0 -0
  73. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_pdu.py +0 -0
  74. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_rle.py +0 -0
  75. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/tests/test_screen.py +0 -0
  76. {simple_rdp-0.8.2 → simple_rdp-0.8.3}/uv.lock +0 -0
@@ -104,7 +104,7 @@ dependencies = [
104
104
 
105
105
  [[package]]
106
106
  name = "simple-rdp"
107
- version = "0.8.2"
107
+ version = "0.8.3"
108
108
  dependencies = [
109
109
  "pyo3",
110
110
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "simple-rdp"
3
- version = "0.8.2"
3
+ version = "0.8.3"
4
4
  edition = "2021"
5
5
  description = "A Python RDP client for automation - exposes screen capture and input transmission"
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simple-rdp
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple-rdp"
3
- version = "0.8.2"
3
+ version = "0.8.3"
4
4
  description = "A Python RDP client for automation - exposes screen capture and input transmission"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11, <4.0"
@@ -409,6 +409,21 @@ 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]]:
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)) where:
422
+ - cropped_image: Cropped region with pointer composited
423
+ - (top_x, top_y): Top-left corner position of crop relative to display
424
+ """
425
+ return await self._display.pointer_area_screenshot()
426
+
412
427
  async def save_screenshot(self, path: str) -> None:
413
428
  """
414
429
  Save a screenshot to a file.
@@ -528,6 +528,48 @@ 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]]:
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)) where:
541
+ - cropped_image: Cropped region with pointer composited
542
+ - (top_x, top_y): Top-left corner position of crop relative to display
543
+ """
544
+ async with self._screen_lock:
545
+ if self._raw_display_image is None:
546
+ crop_w = self._width // 3
547
+ crop_h = self._height // 3
548
+ return (Image.new("RGB", (crop_w, crop_h), (0, 0, 0)), (0, 0))
549
+
550
+ # Update final display image if dirty
551
+ if self._final_display_image_dirty or self._final_display_image is None:
552
+ self._update_final_display_image()
553
+
554
+ assert self._final_display_image is not None
555
+
556
+ # Calculate crop dimensions (1/3 of display)
557
+ crop_w = self._width // 3
558
+ crop_h = self._height // 3
559
+
560
+ # Calculate ideal top-left to center pointer
561
+ top_x = self._pointer_x - crop_w // 2
562
+ top_y = self._pointer_y - crop_h // 2
563
+
564
+ # Clamp to display bounds
565
+ top_x = max(0, min(top_x, self._width - crop_w))
566
+ top_y = max(0, min(top_y, self._height - crop_h))
567
+
568
+ # Crop the image
569
+ cropped = self._final_display_image.crop((top_x, top_y, top_x + crop_w, top_y + crop_h))
570
+
571
+ return (cropped.copy(), (top_x, top_y))
572
+
531
573
  async def apply_bitmap(
532
574
  self,
533
575
  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