diff --git a/jc/parsers/xrandr.py b/jc/parsers/xrandr.py index ba2606be..283cf19b 100644 --- a/jc/parsers/xrandr.py +++ b/jc/parsers/xrandr.py @@ -50,7 +50,8 @@ Schema: "offset_height": integer, "dimension_width": integer, "dimension_height": integer, - "rotation": string + "rotation": string, + "reflection": string } ], "unassociated_devices": [ @@ -127,7 +128,8 @@ Examples: "offset_height": 0, "dimension_width": 310, "dimension_height": 170, - "rotation": "normal" + "rotation": "normal", + "reflection": "normal" } } ], @@ -185,6 +187,8 @@ try: "dimension_width": int, "dimension_height": int, "associated_modes": List[Mode], + "rotation": str, + "reflection": str, }, ) Screen = TypedDict( @@ -252,7 +256,8 @@ _device_pattern = ( + r"(?P primary)? ?" + r"((?P\d+)x(?P\d+)" + r"\+(?P\d+)\+(?P\d+))? " - + r"(?P.*?)? ?" + + r"(?P(normal|right|left|inverted)?) ?" + + r"(?P(X axis|Y axis|X and Y axis)?) ?" + r"\(normal left inverted right x axis y axis\)" + r"( ((?P\d+)mm x (?P\d+)mm)?)?" ) @@ -277,9 +282,10 @@ def _parse_device(next_lines: List[str], quiet: bool = False) -> Optional[Device and len(matches["is_primary"]) > 0, "device_name": matches["device_name"], "rotation": matches["rotation"] or "normal", + "reflection": matches["reflection"] or "normal", } for k, v in matches.items(): - if k not in {"is_connected", "is_primary", "device_name", "rotation"}: + if k not in {"is_connected", "is_primary", "device_name", "rotation", "reflection"}: try: if v: device[k] = int(v) diff --git a/tests/fixtures/generic/xrandr_simple.json b/tests/fixtures/generic/xrandr_simple.json index e03e79c8..0f1ebe49 100644 --- a/tests/fixtures/generic/xrandr_simple.json +++ b/tests/fixtures/generic/xrandr_simple.json @@ -44,6 +44,7 @@ "is_primary": true, "device_name": "eDP1", "rotation": "normal", + "reflection": "normal", "resolution_width": 1920, "resolution_height": 1080, "offset_width": 0, diff --git a/tests/test_xrandr.py b/tests/test_xrandr.py index 8fce69b7..dea94f71 100644 --- a/tests/test_xrandr.py +++ b/tests/test_xrandr.py @@ -32,6 +32,8 @@ class XrandrTests(unittest.TestCase): "eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm", "eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm", "HDMI-0 connected 2160x3840+3840+0 right (normal left inverted right x axis y axis) 609mm x 349mm", + "LVDS-1 connected primary 1366x768+0+0 normal X axis (normal left inverted right x axis y axis) 609mm x 349mm", + "VGA-1 connected 1280x1024+0+0 left X and Y axis (normal left inverted right x axis y axis) 609mm x 349mm", ] for device in devices: self.assertIsNotNone(re.match(_device_pattern, device)) @@ -118,6 +120,30 @@ class XrandrTests(unittest.TestCase): 59.94, device["associated_modes"][12]["frequencies"][4]["frequency"] ) + def test_device_with_reflect(self): + sample = "VGA-1 connected primary 1920x1080+0+0 left X and Y axis (normal left inverted right x axis y axis) 310mm x 170mm" + actual: Optional[Device] = _parse_device([sample]) + + expected = { + "device_name": "VGA-1", + "is_connected": True, + "is_primary": True, + "resolution_width": 1920, + "resolution_height": 1080, + "offset_width": 0, + "offset_height": 0, + "dimension_width": 310, + "dimension_height": 170, + "rotation": "left", + "reflection": "X and Y axis", + } + + self.assertIsNotNone(actual) + + if actual: + for k, v in expected.items(): + self.assertEqual(v, actual[k], f"Devices regex failed on {k}") + def test_mode(self): sample_1 = "1920x1080 60.03*+ 59.93" expected = {