From ef8b19f45adf4f88416e2a6f4031f6e6a04412ed Mon Sep 17 00:00:00 2001 From: KevinKor01 Date: Wed, 17 Sep 2025 22:12:16 +0300 Subject: [PATCH] Venv? --- .../site-packages/ArgumentParser/__init__.py | 193 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7802 bytes .../lib/python3.12/site-packages/Xlib/X.py | 424 ++ .../lib/python3.12/site-packages/Xlib/XK.py | 89 + .../python3.12/site-packages/Xlib/Xatom.py | 90 + .../site-packages/Xlib/Xcursorfont.py | 99 + .../python3.12/site-packages/Xlib/Xutil.py | 81 + .../python3.12/site-packages/Xlib/__init__.py | 39 + .../Xlib/__pycache__/X.cpython-312.pyc | Bin 0 -> 8610 bytes .../Xlib/__pycache__/XK.cpython-312.pyc | Bin 0 -> 2534 bytes .../Xlib/__pycache__/Xatom.cpython-312.pyc | Bin 0 -> 1994 bytes .../__pycache__/Xcursorfont.cpython-312.pyc | Bin 0 -> 2128 bytes .../Xlib/__pycache__/Xutil.cpython-312.pyc | Bin 0 -> 1713 bytes .../Xlib/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 445 bytes .../Xlib/__pycache__/display.cpython-312.pyc | Bin 0 -> 41895 bytes .../Xlib/__pycache__/error.cpython-312.pyc | Bin 0 -> 8994 bytes .../Xlib/__pycache__/rdb.cpython-312.pyc | Bin 0 -> 22258 bytes .../Xlib/__pycache__/threaded.cpython-312.pyc | Bin 0 -> 332 bytes .../Xlib/__pycache__/xauth.cpython-312.pyc | Bin 0 -> 4789 bytes .../python3.12/site-packages/Xlib/display.py | 951 +++ .../python3.12/site-packages/Xlib/error.py | 160 + .../site-packages/Xlib/ext/__init__.py | 46 + .../ext/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 686 bytes .../ext/__pycache__/composite.cpython-312.pyc | Bin 0 -> 10408 bytes .../ext/__pycache__/damage.cpython-312.pyc | Bin 0 -> 7517 bytes .../Xlib/ext/__pycache__/dpms.cpython-312.pyc | Bin 0 -> 9167 bytes .../Xlib/ext/__pycache__/ge.cpython-312.pyc | Bin 0 -> 3779 bytes .../ext/__pycache__/nvcontrol.cpython-312.pyc | Bin 0 -> 81854 bytes .../ext/__pycache__/randr.cpython-312.pyc | Bin 0 -> 59742 bytes .../ext/__pycache__/record.cpython-312.pyc | Bin 0 -> 13577 bytes .../Xlib/ext/__pycache__/res.cpython-312.pyc | Bin 0 -> 12926 bytes .../__pycache__/screensaver.cpython-312.pyc | Bin 0 -> 8687 bytes .../ext/__pycache__/security.cpython-312.pyc | Bin 0 -> 5250 bytes .../ext/__pycache__/shape.cpython-312.pyc | Bin 0 -> 14422 bytes .../ext/__pycache__/xfixes.cpython-312.pyc | Bin 0 -> 9997 bytes .../ext/__pycache__/xinerama.cpython-312.pyc | Bin 0 -> 10377 bytes .../ext/__pycache__/xinput.cpython-312.pyc | Bin 0 -> 32439 bytes .../ext/__pycache__/xtest.cpython-312.pyc | Bin 0 -> 5873 bytes .../site-packages/Xlib/ext/composite.py | 271 + .../site-packages/Xlib/ext/damage.py | 181 + .../python3.12/site-packages/Xlib/ext/dpms.py | 232 + .../python3.12/site-packages/Xlib/ext/ge.py | 112 + .../site-packages/Xlib/ext/nvcontrol.py | 5393 +++++++++++++++++ .../site-packages/Xlib/ext/randr.py | 1292 ++++ .../site-packages/Xlib/ext/record.py | 282 + .../python3.12/site-packages/Xlib/ext/res.py | 288 + .../site-packages/Xlib/ext/screensaver.py | 198 + .../site-packages/Xlib/ext/security.py | 139 + .../site-packages/Xlib/ext/shape.py | 297 + .../site-packages/Xlib/ext/xfixes.py | 200 + .../site-packages/Xlib/ext/xinerama.py | 222 + .../site-packages/Xlib/ext/xinput.py | 777 +++ .../site-packages/Xlib/ext/xtest.py | 122 + .../site-packages/Xlib/keysymdef/__init__.py | 42 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 369 bytes .../keysymdef/__pycache__/apl.cpython-312.pyc | Bin 0 -> 683 bytes .../__pycache__/arabic.cpython-312.pyc | Bin 0 -> 1764 bytes .../__pycache__/cyrillic.cpython-312.pyc | Bin 0 -> 3425 bytes .../__pycache__/greek.cpython-312.pyc | Bin 0 -> 2559 bytes .../__pycache__/hebrew.cpython-312.pyc | Bin 0 -> 1377 bytes .../__pycache__/katakana.cpython-312.pyc | Bin 0 -> 2054 bytes .../__pycache__/korean.cpython-312.pyc | Bin 0 -> 3845 bytes .../__pycache__/latin1.cpython-312.pyc | Bin 0 -> 4960 bytes .../__pycache__/latin2.cpython-312.pyc | Bin 0 -> 1658 bytes .../__pycache__/latin3.cpython-312.pyc | Bin 0 -> 803 bytes .../__pycache__/latin4.cpython-312.pyc | Bin 0 -> 1109 bytes .../__pycache__/miscellany.cpython-312.pyc | Bin 0 -> 4176 bytes .../__pycache__/publishing.cpython-312.pyc | Bin 0 -> 2775 bytes .../__pycache__/special.cpython-312.pyc | Bin 0 -> 852 bytes .../__pycache__/technical.cpython-312.pyc | Bin 0 -> 1756 bytes .../__pycache__/thai.cpython-312.pyc | Bin 0 -> 2799 bytes .../__pycache__/xf86.cpython-312.pyc | Bin 0 -> 6201 bytes .../__pycache__/xk3270.cpython-312.pyc | Bin 0 -> 1114 bytes .../keysymdef/__pycache__/xkb.cpython-312.pyc | Bin 0 -> 3788 bytes .../site-packages/Xlib/keysymdef/apl.py | 19 + .../site-packages/Xlib/keysymdef/arabic.py | 50 + .../site-packages/Xlib/keysymdef/cyrillic.py | 107 + .../site-packages/Xlib/keysymdef/greek.py | 74 + .../site-packages/Xlib/keysymdef/hebrew.py | 40 + .../site-packages/Xlib/keysymdef/katakana.py | 70 + .../site-packages/Xlib/keysymdef/korean.py | 107 + .../site-packages/Xlib/keysymdef/latin1.py | 195 + .../site-packages/Xlib/keysymdef/latin2.py | 57 + .../site-packages/Xlib/keysymdef/latin3.py | 22 + .../site-packages/Xlib/keysymdef/latin4.py | 36 + .../Xlib/keysymdef/miscellany.py | 169 + .../Xlib/keysymdef/publishing.py | 83 + .../site-packages/Xlib/keysymdef/special.py | 24 + .../site-packages/Xlib/keysymdef/technical.py | 49 + .../site-packages/Xlib/keysymdef/thai.py | 84 + .../site-packages/Xlib/keysymdef/xf86.py | 202 + .../site-packages/Xlib/keysymdef/xk3270.py | 30 + .../site-packages/Xlib/keysymdef/xkb.py | 100 + .../site-packages/Xlib/protocol/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 249 bytes .../__pycache__/display.cpython-312.pyc | Bin 0 -> 33545 bytes .../__pycache__/event.cpython-312.pyc | Bin 0 -> 24833 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 101853 bytes .../protocol/__pycache__/rq.cpython-312.pyc | Bin 0 -> 59622 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 8241 bytes .../site-packages/Xlib/protocol/display.py | 1075 ++++ .../site-packages/Xlib/protocol/event.py | 434 ++ .../site-packages/Xlib/protocol/request.py | 1900 ++++++ .../site-packages/Xlib/protocol/rq.py | 1463 +++++ .../site-packages/Xlib/protocol/structs.py | 161 + .../lib/python3.12/site-packages/Xlib/rdb.py | 712 +++ .../site-packages/Xlib/support/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 231 bytes .../__pycache__/connect.cpython-312.pyc | Bin 0 -> 2834 bytes .../support/__pycache__/lock.cpython-312.pyc | Bin 0 -> 903 bytes .../__pycache__/unix_connect.cpython-312.pyc | Bin 0 -> 6879 bytes .../__pycache__/vms_connect.cpython-312.pyc | Bin 0 -> 1770 bytes .../site-packages/Xlib/support/connect.py | 102 + .../site-packages/Xlib/support/lock.py | 44 + .../Xlib/support/unix_connect.py | 217 + .../site-packages/Xlib/support/vms_connect.py | 74 + .../python3.12/site-packages/Xlib/threaded.py | 28 + .../python3.12/site-packages/Xlib/xauth.py | 134 + .../site-packages/Xlib/xobject/__init__.py | 29 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 265 bytes .../__pycache__/colormap.cpython-312.pyc | Bin 0 -> 6719 bytes .../__pycache__/cursor.cpython-312.pyc | Bin 0 -> 1472 bytes .../__pycache__/drawable.cpython-312.pyc | Bin 0 -> 39540 bytes .../__pycache__/fontable.cpython-312.pyc | Bin 0 -> 4636 bytes .../xobject/__pycache__/icccm.cpython-312.pyc | Bin 0 -> 2902 bytes .../__pycache__/resource.cpython-312.pyc | Bin 0 -> 2060 bytes .../site-packages/Xlib/xobject/colormap.py | 141 + .../site-packages/Xlib/xobject/cursor.py | 47 + .../site-packages/Xlib/xobject/drawable.py | 835 +++ .../site-packages/Xlib/xobject/fontable.py | 110 + .../site-packages/Xlib/xobject/icccm.py | 75 + .../site-packages/Xlib/xobject/resource.py | 54 + .../__pycache__/six.cpython-312.pyc | Bin 0 -> 41405 bytes .../argumentparser-1.2.1.dist-info/INSTALLER | 1 + .../argumentparser-1.2.1.dist-info/METADATA | 97 + .../argumentparser-1.2.1.dist-info/RECORD | 8 + .../argumentparser-1.2.1.dist-info/REQUESTED | 0 .../argumentparser-1.2.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../evdev-1.9.2.dist-info/INSTALLER | 1 + .../evdev-1.9.2.dist-info/METADATA | 78 + .../evdev-1.9.2.dist-info/RECORD | 38 + .../site-packages/evdev-1.9.2.dist-info/WHEEL | 5 + .../evdev-1.9.2.dist-info/licenses/LICENSE | 29 + .../evdev-1.9.2.dist-info/top_level.txt | 1 + .../site-packages/evdev/__init__.py | 39 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 675 bytes .../evdev/__pycache__/device.cpython-312.pyc | Bin 0 -> 18186 bytes .../evdev/__pycache__/ecodes.cpython-312.pyc | Bin 0 -> 125099 bytes .../ecodes_runtime.cpython-312.pyc | Bin 0 -> 2922 bytes .../evdev/__pycache__/eventio.cpython-312.pyc | Bin 0 -> 6296 bytes .../__pycache__/eventio_async.cpython-312.pyc | Bin 0 -> 5979 bytes .../evdev/__pycache__/events.cpython-312.pyc | Bin 0 -> 8555 bytes .../evdev/__pycache__/evtest.cpython-312.pyc | Bin 0 -> 9616 bytes .../evdev/__pycache__/ff.cpython-312.pyc | Bin 0 -> 6595 bytes .../__pycache__/genecodes_c.cpython-312.pyc | Bin 0 -> 4306 bytes .../__pycache__/genecodes_py.cpython-312.pyc | Bin 0 -> 1881 bytes .../evdev/__pycache__/uinput.cpython-312.pyc | Bin 0 -> 16028 bytes .../evdev/__pycache__/util.cpython-312.pyc | Bin 0 -> 5697 bytes .../_ecodes.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 86304 bytes .../_input.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 51824 bytes .../_uinput.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 37352 bytes .../python3.12/site-packages/evdev/device.py | 440 ++ .../python3.12/site-packages/evdev/ecodes.py | 3885 ++++++++++++ .../site-packages/evdev/ecodes_runtime.py | 111 + .../python3.12/site-packages/evdev/eventio.py | 152 + .../site-packages/evdev/eventio_async.py | 106 + .../python3.12/site-packages/evdev/events.py | 192 + .../python3.12/site-packages/evdev/evtest.py | 181 + .../lib/python3.12/site-packages/evdev/ff.py | 198 + .../site-packages/evdev/genecodes_c.py | 147 + .../site-packages/evdev/genecodes_py.py | 54 + .../python3.12/site-packages/evdev/input.c | 579 ++ .../python3.12/site-packages/evdev/py.typed | 0 .../python3.12/site-packages/evdev/uinput.c | 417 ++ .../python3.12/site-packages/evdev/uinput.py | 375 ++ .../python3.12/site-packages/evdev/util.py | 146 + .../keyboard-0.13.5.dist-info/INSTALLER | 1 + .../keyboard-0.13.5.dist-info/LICENSE.txt | 21 + .../keyboard-0.13.5.dist-info/METADATA | 101 + .../keyboard-0.13.5.dist-info/RECORD | 39 + .../keyboard-0.13.5.dist-info/REQUESTED | 0 .../keyboard-0.13.5.dist-info/WHEEL | 5 + .../keyboard-0.13.5.dist-info/top_level.txt | 1 + .../site-packages/keyboard/__init__.py | 1157 ++++ .../site-packages/keyboard/__main__.py | 13 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 53753 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1261 bytes .../_canonical_names.cpython-312.pyc | Bin 0 -> 51763 bytes .../_darwinkeyboard.cpython-312.pyc | Bin 0 -> 20996 bytes .../__pycache__/_darwinmouse.cpython-312.pyc | Bin 0 -> 10159 bytes .../__pycache__/_generic.cpython-312.pyc | Bin 0 -> 3836 bytes .../_keyboard_event.cpython-312.pyc | Bin 0 -> 2849 bytes .../_keyboard_tests.cpython-312.pyc | Bin 0 -> 86670 bytes .../__pycache__/_mouse_event.cpython-312.pyc | Bin 0 -> 702 bytes .../__pycache__/_mouse_tests.cpython-312.pyc | Bin 0 -> 21426 bytes .../__pycache__/_nixcommon.cpython-312.pyc | Bin 0 -> 9110 bytes .../__pycache__/_nixkeyboard.cpython-312.pyc | Bin 0 -> 8005 bytes .../__pycache__/_nixmouse.cpython-312.pyc | Bin 0 -> 5546 bytes .../__pycache__/_winkeyboard.cpython-312.pyc | Bin 0 -> 23141 bytes .../__pycache__/_winmouse.cpython-312.pyc | Bin 0 -> 7782 bytes .../__pycache__/mouse.cpython-312.pyc | Bin 0 -> 11608 bytes .../keyboard/_canonical_names.py | 1246 ++++ .../site-packages/keyboard/_darwinkeyboard.py | 442 ++ .../site-packages/keyboard/_darwinmouse.py | 173 + .../site-packages/keyboard/_generic.py | 73 + .../site-packages/keyboard/_keyboard_event.py | 53 + .../site-packages/keyboard/_keyboard_tests.py | 827 +++ .../site-packages/keyboard/_mouse_event.py | 20 + .../site-packages/keyboard/_mouse_tests.py | 271 + .../site-packages/keyboard/_nixcommon.py | 174 + .../site-packages/keyboard/_nixkeyboard.py | 183 + .../site-packages/keyboard/_nixmouse.py | 130 + .../site-packages/keyboard/_winkeyboard.py | 620 ++ .../site-packages/keyboard/_winmouse.py | 201 + .../site-packages/keyboard/mouse.py | 232 + .../pynput-1.8.1.dist-info/COPYING.LGPL | 165 + .../pynput-1.8.1.dist-info/INSTALLER | 1 + .../pynput-1.8.1.dist-info/METADATA | 914 +++ .../pynput-1.8.1.dist-info/RECORD | 55 + .../pynput-1.8.1.dist-info/REQUESTED | 0 .../pynput-1.8.1.dist-info/WHEEL | 6 + .../pynput-1.8.1.dist-info/pbr.json | 1 + .../pynput-1.8.1.dist-info/top_level.txt | 1 + .../pynput-1.8.1.dist-info/zip-safe | 1 + .../site-packages/pynput/__init__.py | 41 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1113 bytes .../pynput/__pycache__/_info.cpython-312.pyc | Bin 0 -> 255 bytes .../python3.12/site-packages/pynput/_info.py | 19 + .../site-packages/pynput/_util/__init__.py | 489 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 22694 bytes .../_util/__pycache__/darwin.cpython-312.pyc | Bin 0 -> 10308 bytes .../__pycache__/darwin_vks.cpython-312.pyc | Bin 0 -> 1654 bytes .../_util/__pycache__/uinput.cpython-312.pyc | Bin 0 -> 3455 bytes .../_util/__pycache__/win32.cpython-312.pyc | Bin 0 -> 23722 bytes .../__pycache__/win32_vks.cpython-312.pyc | Bin 0 -> 3813 bytes .../_util/__pycache__/xorg.cpython-312.pyc | Bin 0 -> 18809 bytes .../__pycache__/xorg_keysyms.cpython-312.pyc | Bin 0 -> 87848 bytes .../site-packages/pynput/_util/darwin.py | 302 + .../site-packages/pynput/_util/darwin_vks.py | 79 + .../site-packages/pynput/_util/uinput.py | 99 + .../site-packages/pynput/_util/win32.py | 598 ++ .../site-packages/pynput/_util/win32_vks.py | 179 + .../site-packages/pynput/_util/xorg.py | 496 ++ .../pynput/_util/xorg_keysyms.py | 1715 ++++++ .../site-packages/pynput/keyboard/__init__.py | 249 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 10172 bytes .../__pycache__/_base.cpython-312.pyc | Bin 0 -> 28744 bytes .../__pycache__/_darwin.cpython-312.pyc | Bin 0 -> 13381 bytes .../__pycache__/_dummy.cpython-312.pyc | Bin 0 -> 421 bytes .../__pycache__/_uinput.cpython-312.pyc | Bin 0 -> 21313 bytes .../__pycache__/_win32.cpython-312.pyc | Bin 0 -> 17438 bytes .../__pycache__/_xorg.cpython-312.pyc | Bin 0 -> 29235 bytes .../site-packages/pynput/keyboard/_base.py | 754 +++ .../site-packages/pynput/keyboard/_darwin.py | 367 ++ .../site-packages/pynput/keyboard/_dummy.py | 23 + .../site-packages/pynput/keyboard/_uinput.py | 446 ++ .../site-packages/pynput/keyboard/_win32.py | 389 ++ .../site-packages/pynput/keyboard/_xorg.py | 667 ++ .../site-packages/pynput/mouse/__init__.py | 107 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2812 bytes .../mouse/__pycache__/_base.cpython-312.pyc | Bin 0 -> 11137 bytes .../mouse/__pycache__/_darwin.cpython-312.pyc | Bin 0 -> 8631 bytes .../mouse/__pycache__/_dummy.cpython-312.pyc | Bin 0 -> 403 bytes .../mouse/__pycache__/_win32.cpython-312.pyc | Bin 0 -> 9508 bytes .../mouse/__pycache__/_xorg.cpython-312.pyc | Bin 0 -> 8936 bytes .../site-packages/pynput/mouse/_base.py | 281 + .../site-packages/pynput/mouse/_darwin.py | 212 + .../site-packages/pynput/mouse/_dummy.py | 22 + .../site-packages/pynput/mouse/_win32.py | 226 + .../site-packages/pynput/mouse/_xorg.py | 184 + .../python_xlib-0.33.dist-info/INSTALLER | 1 + .../python_xlib-0.33.dist-info/LICENSE | 504 ++ .../python_xlib-0.33.dist-info/METADATA | 158 + .../python_xlib-0.33.dist-info/RECORD | 136 + .../python_xlib-0.33.dist-info/WHEEL | 6 + .../python_xlib-0.33.dist-info/top_level.txt | 1 + .../six-1.17.0.dist-info/INSTALLER | 1 + .../six-1.17.0.dist-info/LICENSE | 18 + .../six-1.17.0.dist-info/METADATA | 43 + .../site-packages/six-1.17.0.dist-info/RECORD | 8 + .../site-packages/six-1.17.0.dist-info/WHEEL | 6 + .../six-1.17.0.dist-info/top_level.txt | 1 + CLI/venv/lib/python3.12/site-packages/six.py | 1003 +++ 284 files changed, 45670 insertions(+) create mode 100644 CLI/venv/lib/python3.12/site-packages/ArgumentParser/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/ArgumentParser/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/X.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/XK.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/Xatom.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/Xcursorfont.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/Xutil.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/X.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/XK.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xatom.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xcursorfont.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xutil.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/display.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/error.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/rdb.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/threaded.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/xauth.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/display.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/error.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/composite.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/damage.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/dpms.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/ge.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/nvcontrol.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/randr.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/record.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/res.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/screensaver.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/security.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/shape.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xfixes.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinerama.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinput.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xtest.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/composite.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/damage.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/dpms.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/ge.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/nvcontrol.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/randr.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/record.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/res.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/screensaver.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/security.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/shape.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/xfixes.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinerama.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinput.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/ext/xtest.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/apl.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/arabic.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/cyrillic.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/greek.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/hebrew.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/katakana.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/korean.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin1.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin2.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin3.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin4.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/miscellany.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/publishing.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/special.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/technical.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/thai.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xf86.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xk3270.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xkb.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/apl.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/arabic.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/cyrillic.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/greek.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/hebrew.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/katakana.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/korean.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/latin1.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/latin2.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/latin3.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/latin4.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/miscellany.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/publishing.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/special.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/technical.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/thai.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/xf86.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/xk3270.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/xkb.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/display.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/event.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/request.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/rq.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/structs.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/display.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/event.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/request.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/rq.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/protocol/structs.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/rdb.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/connect.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/lock.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/unix_connect.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/vms_connect.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/connect.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/lock.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/unix_connect.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/support/vms_connect.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/threaded.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xauth.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/colormap.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/cursor.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/drawable.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/fontable.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/icccm.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/resource.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/colormap.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/cursor.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/drawable.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/fontable.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/icccm.py create mode 100644 CLI/venv/lib/python3.12/site-packages/Xlib/xobject/resource.py create mode 100644 CLI/venv/lib/python3.12/site-packages/__pycache__/six.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/REQUESTED create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/licenses/LICENSE create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/device.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes_runtime.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/eventio.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/eventio_async.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/events.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/evtest.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ff.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/genecodes_c.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/genecodes_py.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/uinput.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/util.cpython-312.pyc create mode 100755 CLI/venv/lib/python3.12/site-packages/evdev/_ecodes.cpython-312-x86_64-linux-gnu.so create mode 100755 CLI/venv/lib/python3.12/site-packages/evdev/_input.cpython-312-x86_64-linux-gnu.so create mode 100755 CLI/venv/lib/python3.12/site-packages/evdev/_uinput.cpython-312-x86_64-linux-gnu.so create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/device.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/ecodes.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/ecodes_runtime.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/eventio.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/eventio_async.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/events.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/evtest.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/ff.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/genecodes_c.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/genecodes_py.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/input.c create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/py.typed create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/uinput.c create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/uinput.py create mode 100644 CLI/venv/lib/python3.12/site-packages/evdev/util.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/LICENSE.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/REQUESTED create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__main__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__main__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_canonical_names.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_darwinkeyboard.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_darwinmouse.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_generic.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_keyboard_event.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_keyboard_tests.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_mouse_event.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_mouse_tests.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixcommon.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixkeyboard.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixmouse.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_winkeyboard.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_winmouse.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/mouse.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_canonical_names.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_darwinkeyboard.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_darwinmouse.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_generic.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_event.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_tests.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_event.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_tests.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_nixcommon.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_nixkeyboard.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_nixmouse.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_winkeyboard.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/_winmouse.py create mode 100644 CLI/venv/lib/python3.12/site-packages/keyboard/mouse.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/COPYING.LGPL create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/REQUESTED create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/pbr.json create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/zip-safe create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/_info.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_info.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/darwin.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/darwin_vks.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/uinput.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/win32.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/win32_vks.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/xorg.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/xorg_keysyms.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin_vks.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/uinput.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/win32.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/win32_vks.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg_keysyms.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_base.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_darwin.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_dummy.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_uinput.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_win32.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_xorg.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_base.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_darwin.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_dummy.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_uinput.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_win32.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_xorg.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__init__.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/__init__.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_base.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_darwin.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_dummy.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_win32.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_xorg.cpython-312.pyc create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/_base.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/_darwin.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/_dummy.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/_win32.py create mode 100644 CLI/venv/lib/python3.12/site-packages/pynput/mouse/_xorg.py create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/LICENSE create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/INSTALLER create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/LICENSE create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/METADATA create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/RECORD create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/WHEEL create mode 100644 CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/top_level.txt create mode 100644 CLI/venv/lib/python3.12/site-packages/six.py diff --git a/CLI/venv/lib/python3.12/site-packages/ArgumentParser/__init__.py b/CLI/venv/lib/python3.12/site-packages/ArgumentParser/__init__.py new file mode 100644 index 0000000..47cd1ae --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/ArgumentParser/__init__.py @@ -0,0 +1,193 @@ +# Copyright 2015 (c) Tim Savannah +# LGPL v3 (see LICENSE file). Feel free to contact me with any questions! + +import sys + +class ArgumentParser(object): + ''' + A utility class for parsing command-line arguments. + + @param names list - This is a list of "names" which should reflect each argument. + @param shortOptions list - This is a list of short (-x val) options. Length should match names. If no short option is available, use 'None'. Omit the leading - + @param longOptions list - This is a list of long (--xyz val or --xyz= val) options. If no long option is available, use 'None'. Omit the leading -- + @param staticOptions list - This is a list of static options (arguments that have meaning just being present, without taking an additional value). + Any members of this list will be present in the results of #parse, set to True is present, otherwise False. + + @param multipleStaticOptions - A dictionary for multiple static arguments that resolve to one value. Key is the "name", values are all potential values. Ex: {'cheese' : ['--cheddar', 'gouda'] } presence of either 'gouda' or '--cheddar' in results would set cheese to True, otherwise False. + @param allowOtherArguments default False - if False, consider non-specified arguments as errors. + + @example +In [1]: from ArgumentParser import ArgumentParser + +In [2]: parser = ArgumentParser(['firstName', 'lastName', 'birthday'], + ...: ['f', 'l', 'b'], + ...: ['first-name', 'last-name', 'birthday'], + ...: ['--citizen'] + ...: ) + +In [3]: parser.parse('-f Tim --last-name=savannah --birthday 6/28'.split(' ')) +Out[3]: +{'errors': [], + 'result': {'--citizen': False, + 'birthday': '6/28', + 'firstName': 'Tim', + 'lastName': 'savannah'}, + 'warnings': []} + +In [4]: parser.parse('-f Tim --last-name=savannah --citizen'.split(' ')) +Out[4]: +{'errors': [], + 'result': {'--citizen': True, 'firstName': 'Tim', 'lastName': 'savannah'}, + 'warnings': []} + +>>> import ArgumentParser +>>> parser = ArgumentParser.ArgumentParser( ('one', 'two'), ('o', 't'), ('uno', 'dos'), ('x'), {'cheese' : ['cheddar', 'gouda'], 'baby' : {'child', 'infant'}} ) +>>> parser.parse(['-o', '1', 'cheddar']) +{'errors': [], 'result': {'baby': False, 'cheese': True, 'x': False, 'one': '1'}, 'unmatched': [], 'warnings': []} + + ''' + + def __init__(self, names, shortOptions, longOptions, staticOptions=None, multipleStaticOptions=None, allowOtherArguments=False): + namesLen = len(names) + if namesLen != len(shortOptions) or namesLen != len(longOptions): + raise ValueError('names, shortOptions, longOptions must all have the same length. use None of there is no equivlant.') + + self.names = names + self.shortOptions = shortOptions + self.longOptions = longOptions + self.staticOptions = set(staticOptions or []) + self.multipleStaticOptions = multipleStaticOptions + self.allowOtherArguments = allowOtherArguments + + + def parse(self, args=None): + ''' + parse - Parses provided arguments and returns information on them. If using sys.argv, omit the first argument. + If dealing with a string of arguments (custom shell or something?), `shlex.parse('args "as expected" k')` is your friend. + + @param args list - parse these arguments. If None (default), sys.argv[1:] is used. + + @return - dict keys are + 'result' => dictionary of result name->value + 'errors' => list of strings of errors or empty list + 'warnings' => list of strings of warnings, or empty list + 'unmatched' => all unmatched params, in order + ''' + if args is None: + args = sys.argv[1:] + result = {} + errors = [] + warnings = [] + unmatched = [] + + argsLen = len(args) + i = 0 + while i < argsLen: + arg = args[i] + + if self.multipleStaticOptions is not None: + foundIt = False + for optionName, possibleValues in self.multipleStaticOptions.items(): + if arg in possibleValues: + if optionName in result: + warnings.append("Argument '%s' specified more than once (at position %d)" %(arg, i)) + else: + result[optionName] = True + foundIt = True + break + if foundIt is True: + i += 1 + continue + + if arg in self.staticOptions: + if arg in result: + warnings.append("Argument '%s' specified more than once (at position %d)" %(arg, i)) + else: + result[arg] = True + i += 1 + continue + + if arg.startswith('--'): + try: + equalSignIdx = arg.index('=') + argName = arg[2:equalSignIdx] + except ValueError: + equalSignIdx = False + argName = arg[2:] + try: + argIdx = self.longOptions.index(argName) + except ValueError: + errors.append("Unknown argument '%s' (at position %d)" %(arg, i,)) + i += 1 + continue + + name = self.names[argIdx] + if name in result: + warnings.append("Option '%s' specified more than once. Using latter value (at position %d)" %(name, i)) + + if equalSignIdx is not False: + val = arg[equalSignIdx+1:] + if len(val) == 0: + errors.append('Equal sign used and no value on \'%s\' (at position %d)' %(arg, i)) + i += 1 + continue + result[name] = val + i += 1 + continue + else: + if i+1 >= argsLen: + errors.append('No equal sign provided on assignment option, and no more arguments to try with \'%s\' (at position %d)' %(arg, i)) + i += 2 + continue + val = args[i+1] + result[name] = val + i += 2 + continue + + elif arg.startswith('-'): + argName = arg[1:] + if i+1 >= argsLen: + errors.append('No assignment on short option %s (at position %d)' %(arg, i)) + i += 2 + continue + + try: + argIdx = self.shortOptions.index(argName) + except ValueError: + errors.append("Unknown option '%s' (at position %d)" %(arg, i)) + i += 1 + continue + + name = self.names[argIdx] + if name in result: + warnings.append("Argument \'%s\' specified more than once, using latter value (at position %d)" %(name, i)) + + result[name] = args[i+1] + i += 2 + continue + + else: + if self.allowOtherArguments is False: + errors.append('Unknown argument \'%s\' (at position %d)' %(arg, i)) + + unmatched.append(arg) + + i += 1 + continue + + for staticOption in self.staticOptions: + if staticOption not in result: + result[staticOption] = False + + if self.multipleStaticOptions is not None: + foundItems = set(result.keys()) + multipleOptions = set(self.multipleStaticOptions.keys()) + + for optionName in multipleOptions.difference(foundItems): + result[optionName] = False + + return { 'result' : result, 'errors' : errors, 'warnings' : warnings, 'unmatched' : unmatched } + + + +# vim: sw=4 ts=4 noexpandtab diff --git a/CLI/venv/lib/python3.12/site-packages/ArgumentParser/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/ArgumentParser/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..364ec0922cb56c73f43e1891c15b3c11b90e80fe GIT binary patch literal 7802 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 CMMg{j literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/X.py b/CLI/venv/lib/python3.12/site-packages/Xlib/X.py new file mode 100644 index 0000000..826854f --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/X.py @@ -0,0 +1,424 @@ +# Xlib.X -- basic X constants +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Avoid overwriting None if doing "from Xlib.X import *" +NONE = 0 + +ParentRelative = 1 # background pixmap in CreateWindow + # and ChangeWindowAttributes + +CopyFromParent = 0 # border pixmap in CreateWindow + # and ChangeWindowAttributes + # special VisualID and special window + # class passed to CreateWindow + +PointerWindow = 0 # destination window in SendEvent +InputFocus = 1 # destination window in SendEvent +PointerRoot = 1 # focus window in SetInputFocus +AnyPropertyType = 0 # special Atom, passed to GetProperty +AnyKey = 0 # special Key Code, passed to GrabKey +AnyButton = 0 # special Button Code, passed to GrabButton +AllTemporary = 0 # special Resource ID passed to KillClient +CurrentTime = 0 # special Time +NoSymbol = 0 # special KeySym + + +#----------------------------------------------------------------------- +# Event masks: +# +NoEventMask = 0 +KeyPressMask = (1<<0) +KeyReleaseMask = (1<<1) +ButtonPressMask = (1<<2) +ButtonReleaseMask = (1<<3) +EnterWindowMask = (1<<4) +LeaveWindowMask = (1<<5) +PointerMotionMask = (1<<6) +PointerMotionHintMask = (1<<7) +Button1MotionMask = (1<<8) +Button2MotionMask = (1<<9) +Button3MotionMask = (1<<10) +Button4MotionMask = (1<<11) +Button5MotionMask = (1<<12) +ButtonMotionMask = (1<<13) +KeymapStateMask = (1<<14) +ExposureMask = (1<<15) +VisibilityChangeMask = (1<<16) +StructureNotifyMask = (1<<17) +ResizeRedirectMask = (1<<18) +SubstructureNotifyMask = (1<<19) +SubstructureRedirectMask = (1<<20) +FocusChangeMask = (1<<21) +PropertyChangeMask = (1<<22) +ColormapChangeMask = (1<<23) +OwnerGrabButtonMask = (1<<24) + +#----------------------------------------------------------------------- +# Event names: +# +# Used in "type" field in XEvent structures. Not to be confused with event +# masks above. They start from 2 because 0 and 1 are reserved in the +# protocol for errors and replies. +# +KeyPress = 2 +KeyRelease = 3 +ButtonPress = 4 +ButtonRelease = 5 +MotionNotify = 6 +EnterNotify = 7 +LeaveNotify = 8 +FocusIn = 9 +FocusOut = 10 +KeymapNotify = 11 +Expose = 12 +GraphicsExpose = 13 +NoExpose = 14 +VisibilityNotify = 15 +CreateNotify = 16 +DestroyNotify = 17 +UnmapNotify = 18 +MapNotify = 19 +MapRequest = 20 +ReparentNotify = 21 +ConfigureNotify = 22 +ConfigureRequest = 23 +GravityNotify = 24 +ResizeRequest = 25 +CirculateNotify = 26 +CirculateRequest = 27 +PropertyNotify = 28 +SelectionClear = 29 +SelectionRequest = 30 +SelectionNotify = 31 +ColormapNotify = 32 +ClientMessage = 33 +MappingNotify = 34 +LASTEvent = 35 # must be bigger than any event + + +#----------------------------------------------------------------------- +# Key masks: +# +# Used as modifiers to GrabButton and GrabKey, results of QueryPointer, +# state in various key-, mouse-, and button-related events. +# +ShiftMask = (1<<0) +LockMask = (1<<1) +ControlMask = (1<<2) +Mod1Mask = (1<<3) +Mod2Mask = (1<<4) +Mod3Mask = (1<<5) +Mod4Mask = (1<<6) +Mod5Mask = (1<<7) + + +#----------------------------------------------------------------------- +# Modifier names: +# +# Used to build a SetModifierMapping request or to read a +# GetModifierMapping request. These correspond to the masks defined above. +# +ShiftMapIndex = 0 +LockMapIndex = 1 +ControlMapIndex = 2 +Mod1MapIndex = 3 +Mod2MapIndex = 4 +Mod3MapIndex = 5 +Mod4MapIndex = 6 +Mod5MapIndex = 7 + +#----------------------------------------------------------------------- +# Button masks: +# +# Used in same manner as Key masks above. Not to be confused with button +# names below. Note that 0 is already defined above as "AnyButton". +# +Button1Mask = (1<<8) +Button2Mask = (1<<9) +Button3Mask = (1<<10) +Button4Mask = (1<<11) +Button5Mask = (1<<12) + +AnyModifier = (1<<15) # used in GrabButton, GrabKey + +#----------------------------------------------------------------------- +# Button names: +# +# Used as arguments to GrabButton and as detail in ButtonPress and +# ButtonRelease events. Not to be confused with button masks above. +# Note that 0 is already defined above as "AnyButton". +# +Button1 = 1 +Button2 = 2 +Button3 = 3 +Button4 = 4 +Button5 = 5 + + +#----------------------------------------------------------------------- +# XXX These still need documentation -- for now, read +# +NotifyNormal = 0 +NotifyGrab = 1 +NotifyUngrab = 2 +NotifyWhileGrabbed = 3 +NotifyHint = 1 +NotifyAncestor = 0 +NotifyVirtual = 1 +NotifyInferior = 2 +NotifyNonlinear = 3 +NotifyNonlinearVirtual = 4 +NotifyPointer = 5 +NotifyPointerRoot = 6 +NotifyDetailNone = 7 +VisibilityUnobscured = 0 +VisibilityPartiallyObscured = 1 +VisibilityFullyObscured = 2 +PlaceOnTop = 0 +PlaceOnBottom = 1 +FamilyInternet = 0 +FamilyDECnet = 1 +FamilyChaos = 2 +FamilyServerInterpreted = 5 +FamilyInternetV6 = 6 +PropertyNewValue = 0 +PropertyDelete = 1 +ColormapUninstalled = 0 +ColormapInstalled = 1 +GrabModeSync = 0 +GrabModeAsync = 1 +GrabSuccess = 0 +AlreadyGrabbed = 1 +GrabInvalidTime = 2 +GrabNotViewable = 3 +GrabFrozen = 4 +AsyncPointer = 0 +SyncPointer = 1 +ReplayPointer = 2 +AsyncKeyboard = 3 +SyncKeyboard = 4 +ReplayKeyboard = 5 +AsyncBoth = 6 +SyncBoth = 7 +RevertToNone = 0 +RevertToPointerRoot = PointerRoot +RevertToParent = 2 +Success = 0 +BadRequest = 1 +BadValue = 2 +BadWindow = 3 +BadPixmap = 4 +BadAtom = 5 +BadCursor = 6 +BadFont = 7 +BadMatch = 8 +BadDrawable = 9 +BadAccess = 10 +BadAlloc = 11 +BadColor = 12 +BadGC = 13 +BadIDChoice = 14 +BadName = 15 +BadLength = 16 +BadImplementation = 17 +FirstExtensionError = 128 +LastExtensionError = 255 +InputOutput = 1 +InputOnly = 2 +CWBackPixmap = (1<<0) +CWBackPixel = (1<<1) +CWBorderPixmap = (1<<2) +CWBorderPixel = (1<<3) +CWBitGravity = (1<<4) +CWWinGravity = (1<<5) +CWBackingStore = (1<<6) +CWBackingPlanes = (1<<7) +CWBackingPixel = (1<<8) +CWOverrideRedirect = (1<<9) +CWSaveUnder = (1<<10) +CWEventMask = (1<<11) +CWDontPropagate = (1<<12) +CWColormap = (1<<13) +CWCursor = (1<<14) +CWX = (1<<0) +CWY = (1<<1) +CWWidth = (1<<2) +CWHeight = (1<<3) +CWBorderWidth = (1<<4) +CWSibling = (1<<5) +CWStackMode = (1<<6) +ForgetGravity = 0 +NorthWestGravity = 1 +NorthGravity = 2 +NorthEastGravity = 3 +WestGravity = 4 +CenterGravity = 5 +EastGravity = 6 +SouthWestGravity = 7 +SouthGravity = 8 +SouthEastGravity = 9 +StaticGravity = 10 +UnmapGravity = 0 +NotUseful = 0 +WhenMapped = 1 +Always = 2 +IsUnmapped = 0 +IsUnviewable = 1 +IsViewable = 2 +SetModeInsert = 0 +SetModeDelete = 1 +DestroyAll = 0 +RetainPermanent = 1 +RetainTemporary = 2 +Above = 0 +Below = 1 +TopIf = 2 +BottomIf = 3 +Opposite = 4 +RaiseLowest = 0 +LowerHighest = 1 +PropModeReplace = 0 +PropModePrepend = 1 +PropModeAppend = 2 +GXclear = 0x0 +GXand = 0x1 +GXandReverse = 0x2 +GXcopy = 0x3 +GXandInverted = 0x4 +GXnoop = 0x5 +GXxor = 0x6 +GXor = 0x7 +GXnor = 0x8 +GXequiv = 0x9 +GXinvert = 0xa +GXorReverse = 0xb +GXcopyInverted = 0xc +GXorInverted = 0xd +GXnand = 0xe +GXset = 0xf +LineSolid = 0 +LineOnOffDash = 1 +LineDoubleDash = 2 +CapNotLast = 0 +CapButt = 1 +CapRound = 2 +CapProjecting = 3 +JoinMiter = 0 +JoinRound = 1 +JoinBevel = 2 +FillSolid = 0 +FillTiled = 1 +FillStippled = 2 +FillOpaqueStippled = 3 +EvenOddRule = 0 +WindingRule = 1 +ClipByChildren = 0 +IncludeInferiors = 1 +Unsorted = 0 +YSorted = 1 +YXSorted = 2 +YXBanded = 3 +CoordModeOrigin = 0 +CoordModePrevious = 1 +Complex = 0 +Nonconvex = 1 +Convex = 2 +ArcChord = 0 +ArcPieSlice = 1 +GCFunction = (1<<0) +GCPlaneMask = (1<<1) +GCForeground = (1<<2) +GCBackground = (1<<3) +GCLineWidth = (1<<4) +GCLineStyle = (1<<5) +GCCapStyle = (1<<6) +GCJoinStyle = (1<<7) +GCFillStyle = (1<<8) +GCFillRule = (1<<9) +GCTile = (1<<10) +GCStipple = (1<<11) +GCTileStipXOrigin = (1<<12) +GCTileStipYOrigin = (1<<13) +GCFont = (1<<14) +GCSubwindowMode = (1<<15) +GCGraphicsExposures = (1<<16) +GCClipXOrigin = (1<<17) +GCClipYOrigin = (1<<18) +GCClipMask = (1<<19) +GCDashOffset = (1<<20) +GCDashList = (1<<21) +GCArcMode = (1<<22) +GCLastBit = 22 +FontLeftToRight = 0 +FontRightToLeft = 1 +FontChange = 255 +XYBitmap = 0 +XYPixmap = 1 +ZPixmap = 2 +AllocNone = 0 +AllocAll = 1 +DoRed = (1<<0) +DoGreen = (1<<1) +DoBlue = (1<<2) +CursorShape = 0 +TileShape = 1 +StippleShape = 2 +AutoRepeatModeOff = 0 +AutoRepeatModeOn = 1 +AutoRepeatModeDefault = 2 +LedModeOff = 0 +LedModeOn = 1 +KBKeyClickPercent = (1<<0) +KBBellPercent = (1<<1) +KBBellPitch = (1<<2) +KBBellDuration = (1<<3) +KBLed = (1<<4) +KBLedMode = (1<<5) +KBKey = (1<<6) +KBAutoRepeatMode = (1<<7) +MappingSuccess = 0 +MappingBusy = 1 +MappingFailed = 2 +MappingModifier = 0 +MappingKeyboard = 1 +MappingPointer = 2 +DontPreferBlanking = 0 +PreferBlanking = 1 +DefaultBlanking = 2 +DisableScreenSaver = 0 +DisableScreenInterval = 0 +DontAllowExposures = 0 +AllowExposures = 1 +DefaultExposures = 2 +ScreenSaverReset = 0 +ScreenSaverActive = 1 +HostInsert = 0 +HostDelete = 1 +EnableAccess = 1 +DisableAccess = 0 +StaticGray = 0 +GrayScale = 1 +StaticColor = 2 +PseudoColor = 3 +TrueColor = 4 +DirectColor = 5 +LSBFirst = 0 +MSBFirst = 1 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/XK.py b/CLI/venv/lib/python3.12/site-packages/Xlib/XK.py new file mode 100644 index 0000000..4b8bf8c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/XK.py @@ -0,0 +1,89 @@ +# Xlib.XK -- X keysym defs +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA +# +# This module defines some functions for working with X keysyms as well +# as a modular keysym definition and loading mechanism. See the keysym +# definition modules in the Xlib/keysymdef directory. + +from Xlib.X import NoSymbol + +def string_to_keysym(keysym): + '''Return the (16 bit) numeric code of keysym. + + Given the name of a keysym as a string, return its numeric code. + Don't include the 'XK_' prefix, just use the base, i.e. 'Delete' + instead of 'XK_Delete'.''' + return globals().get('XK_' + keysym, NoSymbol) + +def load_keysym_group(group): + '''Load all the keysyms in group. + + Given a group name such as 'latin1' or 'katakana' load the keysyms + defined in module 'Xlib.keysymdef.group-name' into this XK module.''' + if '.' in group: + raise ValueError('invalid keysym group name: %s' % group) + + G = globals() #Get a reference to XK.__dict__ a.k.a. globals + + #Import just the keysyms module. + mod = __import__('Xlib.keysymdef.%s' % group, G, locals(), [group]) + + #Extract names of just the keysyms. + keysyms = [n for n in dir(mod) if n.startswith('XK_')] + + #Copy the named keysyms into XK.__dict__ + for keysym in keysyms: + ## k = mod.__dict__[keysym]; assert k == int(k) #probably too much. + G[keysym] = mod.__dict__[keysym] + + #And get rid of the keysym module. + del mod + +def _load_keysyms_into_XK(mod): + '''keysym definition modules need no longer call Xlib.XK._load_keysyms_into_XK(). + You should remove any calls to that function from your keysym modules.''' + pass + +# Always import miscellany and latin1 keysyms +load_keysym_group('miscellany') +load_keysym_group('latin1') + + +def keysym_to_string(keysym): + '''Translate a keysym (16 bit number) into a python string. + + This will pass 0 to 0xff as well as XK_BackSpace, XK_Tab, XK_Clear, + XK_Return, XK_Pause, XK_Scroll_Lock, XK_Escape, XK_Delete. For other + values it returns None.''' + + # ISO latin 1, LSB is the code + if keysym & 0xff00 == 0: + return chr(keysym & 0xff) + + if keysym in [XK_BackSpace, XK_Tab, XK_Clear, XK_Return, + XK_Pause, XK_Scroll_Lock, XK_Escape, XK_Delete]: + return chr(keysym & 0xff) + + # We should be able to do these things quite automatically + # for latin2, latin3, etc, in Python 2.0 using the Unicode, + # but that will have to wait. + + return None diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/Xatom.py b/CLI/venv/lib/python3.12/site-packages/Xlib/Xatom.py new file mode 100644 index 0000000..6fedaaf --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/Xatom.py @@ -0,0 +1,90 @@ +# Xlib.Xatom -- Standard X atoms +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +PRIMARY = 1 +SECONDARY = 2 +ARC = 3 +ATOM = 4 +BITMAP = 5 +CARDINAL = 6 +COLORMAP = 7 +CURSOR = 8 +CUT_BUFFER0 = 9 +CUT_BUFFER1 = 10 +CUT_BUFFER2 = 11 +CUT_BUFFER3 = 12 +CUT_BUFFER4 = 13 +CUT_BUFFER5 = 14 +CUT_BUFFER6 = 15 +CUT_BUFFER7 = 16 +DRAWABLE = 17 +FONT = 18 +INTEGER = 19 +PIXMAP = 20 +POINT = 21 +RECTANGLE = 22 +RESOURCE_MANAGER = 23 +RGB_COLOR_MAP = 24 +RGB_BEST_MAP = 25 +RGB_BLUE_MAP = 26 +RGB_DEFAULT_MAP = 27 +RGB_GRAY_MAP = 28 +RGB_GREEN_MAP = 29 +RGB_RED_MAP = 30 +STRING = 31 +VISUALID = 32 +WINDOW = 33 +WM_COMMAND = 34 +WM_HINTS = 35 +WM_CLIENT_MACHINE = 36 +WM_ICON_NAME = 37 +WM_ICON_SIZE = 38 +WM_NAME = 39 +WM_NORMAL_HINTS = 40 +WM_SIZE_HINTS = 41 +WM_ZOOM_HINTS = 42 +MIN_SPACE = 43 +NORM_SPACE = 44 +MAX_SPACE = 45 +END_SPACE = 46 +SUPERSCRIPT_X = 47 +SUPERSCRIPT_Y = 48 +SUBSCRIPT_X = 49 +SUBSCRIPT_Y = 50 +UNDERLINE_POSITION = 51 +UNDERLINE_THICKNESS = 52 +STRIKEOUT_ASCENT = 53 +STRIKEOUT_DESCENT = 54 +ITALIC_ANGLE = 55 +X_HEIGHT = 56 +QUAD_WIDTH = 57 +WEIGHT = 58 +POINT_SIZE = 59 +RESOLUTION = 60 +COPYRIGHT = 61 +NOTICE = 62 +FONT_NAME = 63 +FAMILY_NAME = 64 +FULL_NAME = 65 +CAP_HEIGHT = 66 +WM_CLASS = 67 +WM_TRANSIENT_FOR = 68 +LAST_PREDEFINED = 68 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/Xcursorfont.py b/CLI/venv/lib/python3.12/site-packages/Xlib/Xcursorfont.py new file mode 100644 index 0000000..e7d0815 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/Xcursorfont.py @@ -0,0 +1,99 @@ +# Xlib.Xcursorfont -- standard cursors +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +num_glyphs = 154 +X_cursor = 0 +arrow = 2 +based_arrow_down = 4 +based_arrow_up = 6 +boat = 8 +bogosity = 10 +bottom_left_corner = 12 +bottom_right_corner = 14 +bottom_side = 16 +bottom_tee = 18 +box_spiral = 20 +center_ptr = 22 +circle = 24 +clock = 26 +coffee_mug = 28 +cross = 30 +cross_reverse = 32 +crosshair = 34 +diamond_cross = 36 +dot = 38 +dotbox = 40 +double_arrow = 42 +draft_large = 44 +draft_small = 46 +draped_box = 48 +exchange = 50 +fleur = 52 +gobbler = 54 +gumby = 56 +hand1 = 58 +hand2 = 60 +heart = 62 +icon = 64 +iron_cross = 66 +left_ptr = 68 +left_side = 70 +left_tee = 72 +leftbutton = 74 +ll_angle = 76 +lr_angle = 78 +man = 80 +middlebutton = 82 +mouse = 84 +pencil = 86 +pirate = 88 +plus = 90 +question_arrow = 92 +right_ptr = 94 +right_side = 96 +right_tee = 98 +rightbutton = 100 +rtl_logo = 102 +sailboat = 104 +sb_down_arrow = 106 +sb_h_double_arrow = 108 +sb_left_arrow = 110 +sb_right_arrow = 112 +sb_up_arrow = 114 +sb_v_double_arrow = 116 +shuttle = 118 +sizing = 120 +spider = 122 +spraycan = 124 +star = 126 +target = 128 +tcross = 130 +top_left_arrow = 132 +top_left_corner = 134 +top_right_corner = 136 +top_side = 138 +top_tee = 140 +trek = 142 +ul_angle = 144 +umbrella = 146 +ur_angle = 148 +watch = 150 +xterm = 152 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/Xutil.py b/CLI/venv/lib/python3.12/site-packages/Xlib/Xutil.py new file mode 100644 index 0000000..b691561 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/Xutil.py @@ -0,0 +1,81 @@ +# Xlib.Xutil -- ICCCM definitions and similar stuff +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +NoValue = 0x0000 +XValue = 0x0001 +YValue = 0x0002 +WidthValue = 0x0004 +HeightValue = 0x0008 +AllValues = 0x000F +XNegative = 0x0010 +YNegative = 0x0020 +USPosition = (1 << 0) +USSize = (1 << 1) +PPosition = (1 << 2) +PSize = (1 << 3) +PMinSize = (1 << 4) +PMaxSize = (1 << 5) +PResizeInc = (1 << 6) +PAspect = (1 << 7) +PBaseSize = (1 << 8) +PWinGravity = (1 << 9) +PAllHints = (PPosition|PSize|PMinSize|PMaxSize|PResizeInc|PAspect) +InputHint = (1 << 0) +StateHint = (1 << 1) +IconPixmapHint = (1 << 2) +IconWindowHint = (1 << 3) +IconPositionHint = (1 << 4) +IconMaskHint = (1 << 5) +WindowGroupHint = (1 << 6) +MessageHint = (1 << 7) +UrgencyHint = (1 << 8) +AllHints = (InputHint|StateHint|IconPixmapHint|IconWindowHint| + IconPositionHint|IconMaskHint|WindowGroupHint|MessageHint| + UrgencyHint) +WithdrawnState = 0 +NormalState = 1 +IconicState = 3 +DontCareState = 0 +ZoomState = 2 +InactiveState = 4 +RectangleOut = 0 +RectangleIn = 1 +RectanglePart = 2 +VisualNoMask = 0x0 +VisualIDMask = 0x1 +VisualScreenMask = 0x2 +VisualDepthMask = 0x4 +VisualClassMask = 0x8 +VisualRedMaskMask = 0x10 +VisualGreenMaskMask = 0x20 +VisualBlueMaskMask = 0x40 +VisualColormapSizeMask = 0x80 +VisualBitsPerRGBMask = 0x100 +VisualAllMask = 0x1FF +ReleaseByFreeingColormap = 1 +BitmapSuccess = 0 +BitmapOpenFailed = 1 +BitmapFileInvalid = 2 +BitmapNoMemory = 3 +XCSUCCESS = 0 +XCNOMEM = 1 +XCNOENT = 2 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__init__.py b/CLI/venv/lib/python3.12/site-packages/Xlib/__init__.py new file mode 100644 index 0000000..f164c43 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/__init__.py @@ -0,0 +1,39 @@ +# Xlib.__init__ -- glue for Xlib package +# +# Copyright (C) 2000-2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +__version__ = (0, 33) + +__version_extra__ = '' + +__version_string__ = '.'.join(map(str, __version__)) + __version_extra__ + +__all__ = [ + 'X', + 'XK', + 'Xatom', + 'Xcursorfont', + 'Xutil', + 'display', + 'error', + 'rdb', + # Explicitly exclude threaded, so that it isn't imported by + # from Xlib import * + ] diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/X.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/X.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfd7cb7c6b88c00f9c94e05e16f2afb0aed02db9 GIT binary patch literal 8610 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/XK.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/XK.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..55bf42f1cd8dec59f064f71d61f199b3e078ef47 GIT binary patch literal 2534 zcmZuyO>7fK6rSC+H?|X;A4vEK(1}!VtOh%Tf(nJIfk289MQszI6bV_I-HpA;de@y9 zCpdE2Q1y@k5<#kzp!Pr|q!xurNaet>T-!?^v{F|bkU*8Vg@hi;rF}EI4l(UWJ3BM) z&6_v#zW2RfH*Ja`Xob~Za!=|Idcr4_rUZkv4`48l3}i?)%1dV@2^sR2=&Wog&?`m= z`jCuF#RxA-{vHX5x%z5u)PPpF6iG&(ah0UxMF!l#Qhvm>^`?4^W}9@j}QY&p7J zgd_OjiQ&FX0vCumYMt-EV@1kvk@}($jhY?UN|`B~=rL`RnF(RUaws!3gL}w#2cndx zz$B@7HCfvo(QN7|S(6d|G&dzr_3uLY+u@h}>Ab_zJp``Ql^(K)Td-KaR&?~7Nzy0! zPp9Fk6KUHTNf$~i=Q;;c`@7QAV&=YrrjKh`lctBcbhs~7D0vP3)icb^_@|IsIAte% zv=zD;^r8;cZN7B)%CWDGEi_+mxwiY(w&mKcrBK%zh*4FnRag+Qmcdg17({Ubk@%~a z8#2Tdv??(ALSpODui#-?VqtEXH$(CD%Mz>cS72{2D5I>j7~o@CX3>hgELW`epeu?l zXOS+SYe8sQDJx_AZm%^XRMDr><>s<-Rld9}gr-BFAL>Epw!qGCSssIAdcBpy+hM6J zmBUBjf4L=uK9fsf9WJlS)5;`Ds#8DqyAW&5wgp^*Fam^dmbk@26*x724GVzMqMqZ( zOxPN;oc#&x5}X*;~%XmfZ%oKwCINK@j_ef)p~ zXfYQ|SQHQU1^TI%Qfg|K=8~K!F%Xb<7+1OP{N}%kgV}yXEeKLo+QL2 zgd@R=WinR2;1ZU}c&hE{0@j8_yclH~VRX`BIWLmQ7?utyN!1IB!#t_iQ{V=k9d5!!X0@!B6Ua|w$-{iV;(9NKg7>d-+nitBC;@g(CzjOEC{q65B z$Gevz-A^O+m!dP>FH}_9ywu$O!@>K_owwWWocU?^=kVRhqk_1e5&A&euv9*}xR$>eM zWJ0VR7qH-DO@iTdZ7hNVd7attFf_wMof+_WiCe@p=N4@P=q~S0m{@a4Vn4+K z6B@&#Kqum~QR3!t$t{u!9(-ug)WA*Pe6kf>^=ZkENb~=mOm=}9&k@SA7^0%0aFp=J z@M3w3>ZWaj3xE*;_NqtWaTk!u%!c*}-6pQ0P=7YfKP-S2?q>YIG3ER|2 zhu{NP_3NY%e5gTX5~D$#xVD|?clB{GKS_11;EVifl)|TgZd~9OA`Af^6itdP7L-Sd z2VBQYS?C`K0e|9WFaQdOdWxPSUfo9LJk@v3i@;wv=S9~Y6N|zzFAj?v91}{uV`At# zMtH_dGDhA4jZ<7}5IR6w1B%4w)C-?4v^}V4eN^8xcW9yK>apeewxvkh zbLIxam&QslVwv|4=y3Soml?Er9<>gSp$(V}Du z>Jdm6P7q!~g|^6ymyx4>=DbJtfq++X+6f(;CrN+3jijBcAyqoC+R!4^t#&F>^m!eU Yn&vtlqBs6PjdSe}QR|wzS@O^S7q>l<_5c6? literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xatom.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xatom.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1ac21337c166ac26a568f20ac5acffe79d63f76 GIT binary patch literal 1994 zcmai!OH&(15XTn-l2#A&;OPhEjg1Y6H@3mpqur6%@@jXpj{tp95jSO1v4O(aRlX_r zRId39`6|hUqiU`>adX8tUy|t&M4MB#O26uV_jLEn^sfHM<bNC1z;bVA=^DvJKuz-uOh-E0_5-i~| zEaM8S;3}-*8m!?utm6i3;3jP16L^A8;VC|YXSfAhxDDI*9G>G2?BEM{fiK}DGGJJN z3L0R@pZVFG<5zS~SGNe=gdRdKAwiJ0s$HcBI)SeHDnrN;a)drYo=_kZ2_-^5VSq45 z7$OW4MhLeFcL;Y0_Xwke`-CyVIAMY?Nthx`6J`jrga?F&ggL?^!ehcbVS%tnC=-?l z%Y+reDq)SVPS_x95}pvA5}pyZ2-}3`gdM^Q!b<`pR0syalyK&_NP50iXa0fE18%sE zNoF_m4bj6ww=NPDE37k5qzvYpmcwjmxwh+*FJVM};QAtCL}8;6Rjb@zii_pASc!|( zxLAve^|;uGi%pR-eYVFcHWxir*9k?^azb9?zDRi1K5eMibEQk@J~u+<)a1f~&jUB| z4c@3Thtb-cU#m3K5v0o#S&|hVgfV4DwA>SUikZC1B0CnY`RqW2Ri&EGxuax;R{Pvk zA`yhX<>vgt&V{*s5HgiGb zaX&D8%L^O(;y?00WP+&jZ!9JbL@9Di?%VPV4bKg%&~hEo-|>aJmhsBrK_CirNw2so z-yRki^6aA6@tC~r%37hkKcmr}XKKH(%dOgODAM0W%xvsgX1FWw_S&cBug)*hG1d@K9-p6{9bedoA5UJtJvuMTVV6H0 zoqQ_4JN}`3_W9!N>B;Ki@=E!`@x{@?+2QLS58oVpDDP8r|M24U{o>i@Z>jC~r}**R z(a!lVvOfJEet0AKrMs)E>&v{B$u^U%Y_6%d63J$FE17EcwDfc{(UO5w8%p-&o0(Q$ z;eV0I$+V;{tE8#2o{^1J;$+b4VU4_<18R-x3)werPgwvEz2GvBsUKs8Z$s+O{H z`DVJM%ZPvth(x^igb3+si}Ob VuqxN-sM6ZUEDijWKmS=?_&=0vJ4yfm literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xcursorfont.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/Xcursorfont.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..295ba2b6de668b47b37e36700b92efe3d77c37bf GIT binary patch literal 2128 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc1e63024484c32577ed0722ba5a8ad298dd33c8 GIT binary patch literal 445 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/error.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/error.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0c02b0b8db0b778ecae1ae835064a6f81f65347 GIT binary patch literal 8994 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/rdb.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/rdb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39fb2516bf78af50decce4c3d0ce3d85723db738 GIT binary patch literal 22258 zcmch9dr(_fn&-WGAtZq$5buYD0UHs6-*)^+(%4`J$Hs{taYF1cGFRAO5adc2qZVn> zmD&}ydo4P%gXpBoN_9^)u4Ja2t*LFNW_prL?W1R>whCF!T2_0iygT`0Q?<3_08`uL zs(t*vb04}A!s*WJ?y1tzz2|+-_nq&2uXF#dsK~-0j4l0#i(kCVasNOsN+^~emj6b_ zadVu&3H&hEEB*7myr2{G!@3cDub$_0oR1qaD-|>Ug5e`xdh0c=S;nZAF|Ap~q?RdI zvrK_n#w>8Xg@U=)A{6#o1xv3@#~tPb>${v_^A&xhmq%30Qj3sU?6a$>4wh<1sza0N z6rAsJy(K~k;!>d$u}g3vE)&WSmkZ^HD_G46)U4FhtYoQGNUio&s=ZXP)EcDLYEr9N zY8_JRHK{c$bsbXOn$%jXL+wZMQuo%eG7TuRUQ?zXW$M*3>sXmalxfnGaife|Ez`it zG^5N0O_}vRe&|pJs>;&Rl&1QX%{ zp#ZU2C=$#lRVWnV%_3M3TWO2-+OQ_YY0C*;V02vU_jMlV>8B-C0_|StYf8Ud2&Knrzxd>rvzSJ)(PiD8fLo4I}Bv>27P^mlWFUqKj0ICeFKBTzI2iN5(tWe z{tIb`{3^=J6Yv<)hJbH)AZ=j9O>((HwLpNna3hFz>I=v<=pPLB^@U0^OWdv`?n043 zFQREKRpN>mt`|IXRo-`PNVqm6T`hPod}OsRT5D1^$9-FE!d4qQbsVTS z!d4%q# zyjT;~2|60~l%AfR!_Eot*NZdYA5uZDw4vQyB7eOp48lV#2!=~7n7%u#6YWSd3i@j7 zW2yC!rU$=C$(_>s3v+7o*WE#)~0cK?i(l%xxta3bPo7NhklRLKut((IIVKZCDLQVNXWwiw}Tbrt& zQ>w*r!BXWZ43eyjR4Grb?MH#@n~`gwx|r!sfmhS_8MttPwC+P?N=uo4WwTKkYDcgR z5u)aV%zUOy*vd5goDeo*Rb)~?R9OVhT(6!qP8vP7&|5MdOWUV~wwh-1b~Bnvn=#K8 z9`v&esiwQL<5b5}wr*w{KH)7QjppnBjqrp&+anSbL_*Q8>FH}?iPOA4&3TH_#=zL{ zU@&dz9~~J1>F5)&b4R?v{)=gcLR0zzW4?ZtaX}m%A4}UWdxyt;eZD}ycg)AqMX&#Y zFRcfyNbCDAifKJ4Oxh&Uz{k>tq0vEq+9WN5$HKOM+Cb}&HVzN^iAK<0njcB)(Pi4m znopb9zyfK0FwF-7gp)+ISHr)B8jQC0QLiusDTGv4uj-OQ25!Dt!AQQmyNtTj>Ay09}@wl#9- ztFr3Y)(`sQ8{WUPur*oMw!|5WnxlNmh2+`pDF3juJo?sqyJD~Wc;7>J3g=ue>}%?cGqgUO320ND(xeptJv|_ON^%IKsEEz z5*;`Yb>CdCGH}FrdW!)xdDAE;7-&(SR&O4#DQj<@;lV)AeWL5+@zW;`cAb36{&Bmz zy!{v5zF{Bj0~FNM3S1l=9~Pt|F*rUp?Ax2!ZEm+ZwoPt^x|$K50mJK48*&c@++O({ zWry;s9Y;@hsi&=f()}`HhoxpT2WyXq7oWw#dJNLxS&L`!If|Y~l+8+sl}HNJtlk#t z3SOf+&4{owD!H1bC5|s_lF$x}kpk>5ZH?dPks-mFV5)u69=W%?;Y(5f^e7&0eQhQ}3*n$rl2H)Ra# z!$!dn0&SsDg$1(W`dM2Z)95U-TsrQ&ee8)s(DM05|GAm1M}#(eL$#=S{r%MxcP^h7#v_~3wg1!vXi znQ(kt0w+?_h6P>x*{CkMGv=ikLCxjW^8u=52|x z=D0Ue)-tPmlt1}#8G3qLt&Vf%g;Z^QY&?EqesccU!uo}+i?waH%WfAYYWGAAM8=~h zW+ty5dsMeBUJ^eYJFXn-92?|YN*FUj zc34&KY0^}6-lg5Z2WLiB6TsrX&kG<<@AE%ZYyObe)KycbOc%JR0&F&w`NoXokdM92 zY_>vdWPyB6!X`xhU#|`SM%smc@R%pKEBe>D3Eoo}nitN$LHd|Y z?*3tKAaE|jhMw>R$3;nAWK5`=331TPWyzNAK>^I|;J}~{-0Y;gr{h=`F{0{Geeh_< z$&=6mbq~1xqf!%emJf`M`-M&Jmwb~<8%#-}cQD`++SQs*`1a7Y&cT5JFuY)&{o^C& zeWH7Gz|BroVyBhU)=d-G%*Mah{e<7l&h#hz3zC%j4Ax#G5P3?ZBb^=HmRCvSWSz4! zUOYs_2oKYi^Miiq4oNkcHuW82qN{}_)_1Jq)WH|iRyHU3#d4lK9=q&lK2P9CEsMAkI4gR15FCT?=a+7dW6`E z=dpAFXx0+HA;*$x)Y{i~!54&bd<5E2 zt%6LG{sq;46QUGYdIwjwZl*9|i1a^lxR}(t{XKicn6j7Ln4Fo6m0o*0Vpy?oHhW|o zTC~#GsrReyTG#)5N$uUDWC- z&m((jv}0x>)^u~@{Kka6K`H;z!V7mgKRf*C;mARa;(rPS1S*_eBbsjwe(YmaBu4lF<>1vAdkD6N-wto29$Dzfh zy{Tr;Lc@n=KEA}BTRv`GY})zQsB7B2#FaR=&%PAxj5VYCy84@k=MQ5{&B@v=(XIy- zwU27tH}}o&i%;CE*_>)@`Nh5u_x|iAtXv=8z0mb#<+jJo=yIt6GgvvobEP%0&Uj;NU$SK5qHW{vP%~$po&+`k z&%Su}V0HIi?%%c@*nz*_>|clYZ)+VCw-r&mxAsW6KFc~nY&m26cHm)-12Y8X4^j-% zsh;E-H8Nxq6jdO``hMN(I7(I0$A|7=6SQb(pZkqXZoxO;9Ul&!(@5O^Kj>g**P)Kn zM^7;_$jGh_#1VS&o>9NgJvgA!#7sH=#-N+DXpHh|1bfK!r?Di8T+c-MUL>Rojf=L%-#xTfkc5x)>Z?7EA=1}8 z36Qz(ho(Yq##*8O6TSkgjRYmA(E1oDVAHuFB}en0Pu5qM37*Ta*ZB`T=-u-igPOxQ zf1gh=n7~j1-BCy!AA>yVYZ1>qfK)gXE(;S z-P}39^PagOr4=hx*$Zu`K?N#_tN&D>LdBk!k5K@~Y+h>DnTMy#NMZgY2M`_~9S@F; z2U|1%)NE=6C>cPKmfUwG2>xOWnP5J=WVX(5CQOZx4I`G;A&mPY8Q&l~tDAdO4MYAKDxo)eH(@zI)<(w^a_J8 z_}s6#$!ExC>S$G75E_lTak7ST z3R40bi;9_^kR;V}4-9)RxLX*dgyu}3M%z5njA<<-L4*4A(~1YZ{(e-=oPU8)SdNb~ zn79Mu=OvauBeL|2c8C{R)Zr-F^S$nXk9M=iCoRt7KlAqYrk zlss-~ZtYf%0^wH;Ms5Wo3KIC0Ib?uK{r6x1ftG&AbivHpt2?wsd0y zUtt4N__EiLnKqz_%jC}x4CHWSCW%~Soe)ye89E{U6t$g~LF~74{_yP7{fgE^MeD+j+pgQeWX1ld;TvP#x=GY^a1K|* z`nwe?=c)ypS9E}XSl+O>e%Bq>9q*?ViS^%0mUk>VIv$qRQErcvd*Jg^ziIg5Ok(}f zWcjg0$1!k)$a)g6Vx)gu1!?FD-Hwi3dXK)Rr$;0cJVahnTZvRaB<4{h9T)T2U}jim zbYdnd@jPYtD7r||Fhv21NW5j|on*Zw8^1`=PW%F-TYr~Z))gAtmddThmZjP~#-^n! zd=cXMW@GJA4?oHq-OK0oHe=0FtpzESg+|wMd81LXMzW^*(TW-r?q~S`k~Dr`JiNK| z@C73;F!BY1789|F`GOTNUobQC1%s<5(&4O$*g9$PSVg#^a{Y8TD}kQrx9mqm3hn$} zUm0(#pnBB9VaQHwRG-=&l!aWMnm@@wF`b(WwYe1FtEKN@h|jbp@Y;ep0jdf&veQOc zB|#bsaSKuyC+g8lw!;Z3q8H8w0@O1$kpvEcXUHz;PgK9Fw+Veo0Rz7)S0(vbePy*r z_1E@%U`)WXssq(P2ra0N0c^>61~V~*!ud0$&;)|oejOtU@pt#1cJHPOPMNU=gqzIdtp*p zG&ld>9c`yNS}}|s#VJI&L%fhZM0&lBA&S#ffjk?tWU_zC+QBbIUc0qN<9jP>!RYk{ z0Y7`ex^5nsKa#L-STt{thKM3+AkZ@KZo)&BzZ^G2!_NsH$#vzSK}I4(lVHm;R1HuG z89iUcW2jUHs8&1oV;ZFcxzpT3dr5T1+@9Gz*WO+<*GU7U0V#oY4;x?zb=DGr#9g$D z^9>kE`i?SsC*g6)`XYCnoFFmc=&|(==yA<>~Q7eT|{Sl>l5oHr9Qk8~mT1@zt zgaQjl#?H3dZ|u3c2OB&ZoST@PnEAoOin^F^b8voeVdsJ;QNR86sb8J>2a$PI=ua#GU!2b+IL=Dpc~Le8v?}1+*&JVZG&$h0xp(u?IOpLT6YS|M33S zY)#wiEuG{h;3>!uksSO=TbMbZ@8nC}FEccg4-oMj#;T>w;u$1_oHBxCwEjOMEc-t4 zrn#@I#gQPLAlIIcb>JY3SKPI>K<$Pj5dJd~{@s|kI-%mk$9osr6ZOyDY5HvAryG+M z2NoR%fCkVS7nj`Vo#~D7SI<2xt%63}Gw=C%DDF>G@3<}eYUq=p&z+x)BuhINZJj9W zs$7jYD$#u#BU_861-5F8*?Cb!A;w`|_P|u>W`5LB$_xA@oOM7w9lS{lJQ64WittTK0KvD=U=AJ$hVKR6k8{i5o_s`uYqn7CWF>#w%o z34Rv(H1wA*{N|Or`+A`1e^e^FrJ<@C)ML|)q_vhu!p@UmDWnO2!(d#~KSLeu8AQHT z>M)s{_t!K`>F^<*A~X|#KdaP zV*^@Z$6`C$r8NrBbph=vq5y@AD;FtS1>KZRi&iR1=*gjq9HqnhOVyamc6y@20GthL1*fLr2*2xgdq39U*FDhnTs`RwG?wu z*<~8N6rd?nJ@aW6np)If`C7FwLNt(F7Yb)%=w8PB*g|sYCdGqL)>X;wQ(Z^9j&=3G zWI(R>N4rm+f*Oea+#}-<)uA~GjEX@rBaqOq6eg{bg~VLsOByXnu@t=M4NA2o2|OUz zmJGM7Sr|5kv$#u`0*&s>`_7eBHUO?N%C+2QKn9ph(?O?N%A*rPkIwx>!eV$HK{@s5PE zIbup#VWx|1m_2*f+CZ+bugo5q=}Hy3AZQ<&4c{$l)F$Gpz^n7NyG2cK#CmM!td8i; zYwfVqne9gDzG>sO6HZJW8^E zO-Xe(Xj~%oM84tGaFDdaq&pTkb|C?m6$GxDV>pi-ay`6$I;dVp%CtcBSgru)UG5f+ z03t0JhjUV}km))gUZ8Y33CP!cY_gB}lG8OI0m`bhJ|OnPWDa9FqrKS*7O5^ZK)2)q zKf(jfg^KFA$=S*GzQ4pdjnB+jVes~`130>4Wd$#t6 zwz52_u!h5VZs)a7tmE3-sk(-E(|qrOZowIQbHR7J;T-I-{FG%F=?y&U_$a&Pp;dtXx)0d>rTU+ z^|!kd*5?)t&#j(;0reRc)A2+X+L%p8J4d8b&|q?D29q^-sa`Szt(9=444yKu^+=i} zoj8wH*ucRrkckW)6ut>e@TZhcCvgro+@y4haKV=gkopMNU@M;PN>xK^V0kz%v;4lEQoexl zP@Y}7QD}iw{`#AM0_;1U!XEJ%lwyQFq}%Hjo9XQ(ir8N6q$iphz{5brHgS<`Lz8ZS zh@`Z^)h`naAOnL}B(d%}s+a*{&OtymST$UO<^tF81}Iu=(+4$BG#j6jposk}`Ky3c zem+%FcFXjy41Y25c^9;pFMhe}*kWZ*qNFEs5RkQ({Bd_|ARe3_S?EvHZ@s6x`c_k2vmA z24>U*hzoFk7Yde*=qIE*d)A|S!gC?R*)3bPAeF$4R6m1uNarqO<(LQd*Z&JQh;S8H z4;Suq0c=~t-hLnCbK-ejPChHffV&t>{@@FWEyx|uuGGJt^2 zg{sYwVX~rd`q!w%60-4`!LFE%P6gdQS_E0}t6C4mcyX$%I%4>dWi=EDq6~^};sNYn zURQS-cRrn?w4d|ckx}Rd`AP}6v|mj+-Wha(*${g!sRZ+K%sWW0))74rxe~EU2z1MogFxwmzCK~Jzpqa+ z5aq+9zo5}kw1@h%Kh}x%A^NDUG6o zTBvU#64JPAQlU;IzBANKl4(CwlLhuH6Z#(xZ}HbOauQTmgV`>1sKU7ia}z(K@*;;F@y*MMgYCom!@)5|t zr3{KrQx9}N6M@{e3<4?BM#}sSi*1v=Po&ju?*2VoPTI4On3kC>HJ$%h>deXWFOVQ@ z`Lz(QMBBNvf_*eU(sE)2b59oW@6;A)FG)t~|42_1ozt$&=4B8Od1WZ`JFH9*4URl& zq@}5omqziU(R!Z*vX_MLi7g4Kedf3es;QOcwI()|X7wkn#sJN!0JUf}oRLE5gw4AS zi_|tnf_5D?(mIr|YAiGVI{Y52SRsv$c?pHKtbru7B5Y3{JboH#O~tzgi-QrVfu7mo zJoP+H8zo;P`O6^x36)lpT82JsOe(bRQ|v_0C4H0S^+!g44otZXixe!$pZ- z;(bl<+0_M-KsQDsA@U(3a?EhkGH;pfi5_3HH!Yf_JJk8fYm)k*=n}P|a6@~Eyw(tF zEqNxe5?M=2=*A{yMm^G12)bcz1fu2$uG{nUt{;X@0-yabqhwAPvgRbQXfZ)yR`k|dQAaF0>aei#K4 z1D0N`VFpu8jtV&;Y*t2w+iivU?we(9m=2Kum=lI-auV>0d#JR5aspE8bCU3?Fk(}d zuth8iTZY`L%S>7Q_+Z_XHM3@6>&NN`ROqhU({H8W94o{s+QJ0`1_=6QFFuvV34{1{ zhIbNPdF-l~a2{p_NQds{-0({4lXLsP4hLE!o;a|{{RVlrDHkbTmYr+iQ`&vJ=cM#4 zA?CH(0(U&c0hOHf$bz5l z28Cp;fHx<*RiQK^-Su$4rZ&hte+ZI;tcgnB zMUu;~D|RR@mw^=}%YE40LQ90tED@;4Ws?T*#uflV?&5&-FIVq}RR?Ao3`t%x#ame} zj@l=w0*ZU_ISJK4Gee+RL8j_~AY34WAZ>ij8yp>xn8+t)1u`LXd#8j-;ErfBcuLX+ z`Y@aL054)1QCc?|V6Gc!Gy7f(oLBl`0#L_0;IGf7k+8e$x|n~dk#yM(Tg;eqI7|bz2aLm9Cb|M-_z^s)T0q4g!5_h zux}tp2%a_yG_W);qzmDMDv5&P9x6|o=e4fjIdb=n_}@@^oGA7`;9;8kA8yXr^jkyG zBWux(-7~xITWb>5n%Dul!garPQ=)d$!l~O0x6UMMcP6d7ZoieV?wRiV%2s~uD3sQA z*NyN@7`~rP@weh)yk+5V(!OK*#YZ-FNe$+T-b6V>@Y|MzXYZZPq^$#W%=R1h8GFo_ zG}ljeJaRba%(Ld0^F8Z*hZ`RQxbN7OaBRE1^Zxek#P;sg_Gf>!|C9a8dfwT=Pj~<4 z0%+hWZ~S292QvnEzC;XP72*!yy~6d=2T}&pKkt60JL0=%a6PixB0}^)%)DrIFB;s8 zs|ZRs7;_ zv0V5llD_Tyg^;yP)0)0*fKoI~BE=svB8A#*liF>Q+ilad8#1(A5l2GiHW`^ix;DYH zA+5ugjPxK?>4E?ZlCZAIABP|t6TWIDwqYdVW{S2_)J4%N6rG^xBt=&dr3<^R^!u3R zKynW@N!we(ZIacQHB&NC{e)i0GQkwvObN=AVoaIAq+cdUG3GvPk|YYo&!!8Aqv#MX zFvcxyR@g&!?n~%R7>Bt81)|$I()APbe(8gZ&x^l9G2%%BKSvC62hT4*%kh@qa+ZHI zaXj5rEUt{4U|uKYWKqMkB~@A%-8Q#(cJE?+XR@?wk#nR-Hu~_D$PU zuKMVKxg)bjVxgp~b&+#YD|S>xWK9(ni-R%U%d9=Ys*|S-|)=|+={G<)!|0u1AHl|4wpk8 zlvJ*IuXu0s1K6H-zjs{uE31jUm@I34P~(o*-*zQycBM+I9>5cAC|Tio;H-#QlFr6& NDs0xGcM90f`acLfoIL;l literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/threaded.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/__pycache__/threaded.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..781df4c50ad36eb5223de79906dcba6c37475789 GIT binary patch literal 332 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 PSFZNo@ZS(@ZOVTEL=0Uf literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/display.py b/CLI/venv/lib/python3.12/site-packages/Xlib/display.py new file mode 100644 index 0000000..bbda44b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/display.py @@ -0,0 +1,951 @@ +# Xlib.display -- high level display object +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Python modules +import types + +# Python 2/3 compatibility. +from six import create_unbound_method + +# Xlib modules +from . import error +from . import ext +from . import X + +# Xlib.protocol modules +from .protocol import display as protocol_display +from .protocol import request, event, rq + +# Xlib.xobjects modules +from .xobject import resource +from .xobject import drawable +from .xobject import fontable +from .xobject import colormap +from .xobject import cursor + +_resource_baseclasses = { + 'resource': resource.Resource, + 'drawable': drawable.Drawable, + 'window': drawable.Window, + 'pixmap': drawable.Pixmap, + 'fontable': fontable.Fontable, + 'font': fontable.Font, + 'gc': fontable.GC, + 'colormap': colormap.Colormap, + 'cursor': cursor.Cursor, + } + +_resource_hierarchy = { + 'resource': ('drawable', 'window', 'pixmap', + 'fontable', 'font', 'gc', + 'colormap', 'cursor'), + 'drawable': ('window', 'pixmap'), + 'fontable': ('font', 'gc') + } + +class _BaseDisplay(protocol_display.Display): + + # Implement a cache of atom names, used by Window objects when + # dealing with some ICCCM properties not defined in Xlib.Xatom + + def __init__(self, *args, **keys): + self.resource_classes = _resource_baseclasses.copy() + protocol_display.Display.__init__(self, *args, **keys) + self._atom_cache = {} + + def get_atom(self, atomname, only_if_exists=False): + if atomname in self._atom_cache: + return self._atom_cache[atomname] + + r = request.InternAtom(display = self, name = atomname, only_if_exists = only_if_exists) + + # don't cache NONE responses in case someone creates this later + if r.atom != X.NONE: + self._atom_cache[atomname] = r.atom + + return r.atom + + +class Display(object): + def __init__(self, display = None): + self.display = _BaseDisplay(display) + + # Create the keymap cache + self._keymap_codes = [()] * 256 + self._keymap_syms = {} + self._update_keymap(self.display.info.min_keycode, + (self.display.info.max_keycode + - self.display.info.min_keycode + 1)) + + # Translations for keysyms to strings. + self.keysym_translations = {} + + # Find all supported extensions + self.extensions = [] + self.class_extension_dicts = {} + self.display_extension_methods = {} + + # a dict that maps the event name to the code + # or, when it's an event with a subcode, to a tuple of (event,subcode) + # note this wraps the dict so you address it as + # extension_event.EXTENSION_EVENT_NAME rather than + # extension_event["EXTENSION_EVENT_NAME"] + self.extension_event = rq.DictWrapper({}) + + exts = self.list_extensions() + + # Go through all extension modules + for extname, modname in ext.__extensions__: + if extname in exts: + + # Import the module and fetch it + __import__('Xlib.ext.' + modname) + mod = getattr(ext, modname) + + info = self.query_extension(extname) + self.display.set_extension_major(extname, info.major_opcode) + + # Call initialiasation function + mod.init(self, info) + + self.extensions.append(extname) + + + # Finalize extensions by creating new classes + for class_name, dictionary in self.class_extension_dicts.items(): + origcls = self.display.resource_classes[class_name] + self.display.resource_classes[class_name] = type(origcls.__name__, + (origcls,), + dictionary) + + # Problem: we have already created some objects without the + # extensions: the screen roots and default colormaps. + # Fix that by reinstantiating them. + for screen in self.display.info.roots: + screen.root = self.display.resource_classes['window'](self.display, screen.root.id) + screen.default_colormap = self.display.resource_classes['colormap'](self.display, screen.default_colormap.id) + + + def get_display_name(self): + """Returns the name used to connect to the server, either + provided when creating the Display object, or fetched from the + environmental variable $DISPLAY.""" + return self.display.get_display_name() + + def fileno(self): + """Returns the file descriptor number of the underlying socket. + This method is provided to allow Display objects to be passed + select.select().""" + return self.display.fileno() + + def close(self): + """Close the display, freeing the resources that it holds.""" + self.display.close() + + def set_error_handler(self, handler): + """Set the default error handler which will be called for all + unhandled errors. handler should take two arguments as a normal + request error handler, but the second argument (the request) will + be None. See section Error Handling.""" + self.display.set_error_handler(handler) + + def flush(self): + """Flush the request queue, building and sending the queued + requests. This can be necessary in applications that never wait + for events, and in threaded applications.""" + self.display.flush() + + def sync(self): + """Flush the queue and wait until the server has processed all + the queued requests. Use this e.g. when it is important that + errors caused by a certain request is trapped.""" + # Do a light-weight replyrequest to sync. There must + # be a better way to do it... + self.get_pointer_control() + + def next_event(self): + """Return the next event. If there are no events queued, it will + block until the next event is fetched from the server.""" + return self.display.next_event() + + def pending_events(self): + """Return the number of events queued, i.e. the number of times + that Display.next_event() can be called without blocking.""" + return self.display.pending_events() + + def has_extension(self, extension): + """Check if both the server and the client library support the X + extension named extension.""" + return extension in self.extensions + + def create_resource_object(self, type, id): + """Create a resource object of type for the integer id. type + should be one of the following strings: + + resource + drawable + window + pixmap + fontable + font + gc + colormap + cursor + + This function can be used when a resource ID has been fetched + e.g. from an resource or a command line argument. Resource + objects should never be created by instantiating the appropriate + class directly, since any X extensions dynamically added by the + library will not be available. + """ + return self.display.resource_classes[type](self.display, id) + + # We need this to handle display extension methods + def __getattr__(self, attr): + try: + function = self.display_extension_methods[attr] + return types.MethodType(function, self) + except KeyError: + raise AttributeError(attr) + + ### + ### display information retrieval + ### + + def screen(self, sno = None): + if sno is None: + return self.display.info.roots[self.display.default_screen] + else: + return self.display.info.roots[sno] + + def screen_count(self): + """Return the total number of screens on the display.""" + return len(self.display.info.roots) + + def get_default_screen(self): + """Return the number of the default screen, extracted from the + display name.""" + return self.display.get_default_screen() + + ### + ### Extension module interface + ### + + def extension_add_method(self, object, name, function): + """extension_add_method(object, name, function) + + Add an X extension module method. OBJECT is the type of + object to add the function to, a string from this list: + + display + resource + drawable + window + pixmap + fontable + font + gc + colormap + cursor + + NAME is the name of the method, a string. FUNCTION is a + normal function whose first argument is a 'self'. + """ + + if object == 'display': + if hasattr(self, name): + raise AssertionError('attempting to replace display method: %s' % name) + + self.display_extension_methods[name] = function + + else: + class_list = (object, ) + _resource_hierarchy.get(object, ()) + for class_name in class_list: + cls = _resource_baseclasses[class_name] + if hasattr(cls, name): + raise AssertionError('attempting to replace %s method: %s' % (class_name, name)) + + method = create_unbound_method(function, cls) + + # Maybe should check extension overrides too + try: + self.class_extension_dicts[class_name][name] = method + except KeyError: + self.class_extension_dicts[class_name] = { name: method } + + def extension_add_event(self, code, evt, name = None): + """extension_add_event(code, evt, [name]) + + Add an extension event. CODE is the numeric code, and EVT is + the event class. EVT will be cloned, and the attribute _code + of the new event class will be set to CODE. + + If NAME is omitted, it will be set to the name of EVT. This + name is used to insert an entry in the DictWrapper + extension_event. + """ + + newevt = type(evt.__name__, evt.__bases__, + evt.__dict__.copy()) + newevt._code = code + + self.display.add_extension_event(code, newevt) + + if name is None: + name = evt.__name__ + + setattr(self.extension_event, name, code) + + def extension_add_subevent(self, code, subcode, evt, name = None): + """extension_add_subevent(code, evt, [name]) + + Add an extension subevent. CODE is the numeric code, subcode + is the sub-ID of this event that shares the code ID with other + sub-events and EVT is the event class. EVT will be cloned, and + the attribute _code of the new event class will be set to CODE. + + If NAME is omitted, it will be set to the name of EVT. This + name is used to insert an entry in the DictWrapper + extension_event. + """ + + newevt = type(evt.__name__, evt.__bases__, + evt.__dict__.copy()) + newevt._code = code + + self.display.add_extension_event(code, newevt, subcode) + + if name is None: + name = evt.__name__ + + # store subcodes as a tuple of (event code, subcode) in the + # extension dict maintained in the display object + setattr(self.extension_event, name, (code,subcode)) + + def extension_add_error(self, code, err): + """extension_add_error(code, err) + + Add an extension error. CODE is the numeric code, and ERR is + the error class. + """ + + self.display.add_extension_error(code, err) + + ### + ### keymap cache implementation + ### + + # The keycode->keysym map is stored in a list with 256 elements. + # Each element represents a keycode, and the tuple elements are + # the keysyms bound to the key. + + # The keysym->keycode map is stored in a mapping, where the keys + # are keysyms. The values are a sorted list of tuples with two + # elements each: (index, keycode) + # keycode is the code for a key to which this keysym is bound, and + # index is the keysyms index in the map for that keycode. + + def keycode_to_keysym(self, keycode, index): + """Convert a keycode to a keysym, looking in entry index. + Normally index 0 is unshifted, 1 is shifted, 2 is alt grid, and 3 + is shift+alt grid. If that key entry is not bound, X.NoSymbol is + returned.""" + try: + return self._keymap_codes[keycode][index] + except IndexError: + return X.NoSymbol + + def keysym_to_keycode(self, keysym): + """Look up the primary keycode that is bound to keysym. If + several keycodes are found, the one with the lowest index and + lowest code is returned. If keysym is not bound to any key, 0 is + returned.""" + try: + return self._keymap_syms[keysym][0][1] + except (KeyError, IndexError): + return 0 + + def keysym_to_keycodes(self, keysym): + """Look up all the keycodes that is bound to keysym. A list of + tuples (keycode, index) is returned, sorted primarily on the + lowest index and secondarily on the lowest keycode.""" + try: + # Copy the map list, reversing the arguments + return map(lambda x: (x[1], x[0]), self._keymap_syms[keysym]) + except KeyError: + return [] + + def refresh_keyboard_mapping(self, evt): + """This method should be called once when a MappingNotify event + is received, to update the keymap cache. evt should be the event + object.""" + if isinstance(evt, event.MappingNotify): + if evt.request == X.MappingKeyboard: + self._update_keymap(evt.first_keycode, evt.count) + else: + raise TypeError('expected a MappingNotify event') + + def _update_keymap(self, first_keycode, count): + """Internal function, called to refresh the keymap cache. + """ + + # Delete all sym->code maps for the changed codes + + lastcode = first_keycode + count + for keysym, codes in self._keymap_syms.items(): + i = 0 + while i < len(codes): + code = codes[i][1] + if code >= first_keycode and code < lastcode: + del codes[i] + else: + i = i + 1 + + # Get the new keyboard mapping + keysyms = self.get_keyboard_mapping(first_keycode, count) + + # Replace code->sym map with the new map + self._keymap_codes[first_keycode:lastcode] = keysyms + + # Update sym->code map + code = first_keycode + for syms in keysyms: + index = 0 + for sym in syms: + if sym != X.NoSymbol: + if sym in self._keymap_syms: + symcodes = self._keymap_syms[sym] + symcodes.append((index, code)) + symcodes.sort() + else: + self._keymap_syms[sym] = [(index, code)] + + index = index + 1 + code = code + 1 + + ### + ### client-internal keysym to string translations + ### + + def lookup_string(self, keysym): + """Return a string corresponding to KEYSYM, or None if no + reasonable translation is found. + """ + s = self.keysym_translations.get(keysym) + if s is not None: + return s + + import Xlib.XK + return Xlib.XK.keysym_to_string(keysym) + + def rebind_string(self, keysym, newstring): + """Change the translation of KEYSYM to NEWSTRING. + If NEWSTRING is None, remove old translation if any. + """ + if newstring is None: + try: + del self.keysym_translations[keysym] + except KeyError: + pass + else: + self.keysym_translations[keysym] = newstring + + + ### + ### X requests + ### + + def intern_atom(self, name, only_if_exists = False): + """Intern the string name, returning its atom number. If + only_if_exists is true and the atom does not already exist, it + will not be created and X.NONE is returned.""" + r = request.InternAtom(display = self.display, + name = name, + only_if_exists = only_if_exists) + return r.atom + + def get_atom(self, atom, only_if_exists = False): + """Alias for intern_atom, using internal cache""" + return self.display.get_atom(atom, only_if_exists) + + + def get_atom_name(self, atom): + """Look up the name of atom, returning it as a string. Will raise + BadAtom if atom does not exist.""" + r = request.GetAtomName(display = self.display, + atom = atom) + return r.name + + def get_selection_owner(self, selection): + """Return the window that owns selection (an atom), or X.NONE if + there is no owner for the selection. Can raise BadAtom.""" + r = request.GetSelectionOwner(display = self.display, + selection = selection) + return r.owner + + def send_event(self, destination, event, event_mask = 0, propagate = False, + onerror = None): + """Send a synthetic event to the window destination which can be + a window object, or X.PointerWindow or X.InputFocus. event is the + event object to send, instantiated from one of the classes in + protocol.events. See XSendEvent(3X11) for details. + + There is also a Window.send_event() method.""" + request.SendEvent(display = self.display, + onerror = onerror, + propagate = propagate, + destination = destination, + event_mask = event_mask, + event = event) + + def ungrab_pointer(self, time, onerror = None): + """Release a grabbed pointer and any queued events. See + XUngrabPointer(3X11).""" + request.UngrabPointer(display = self.display, + onerror = onerror, + time = time) + + def change_active_pointer_grab(self, event_mask, cursor, time, onerror = None): + """Change the dynamic parameters of a pointer grab. See + XChangeActivePointerGrab(3X11).""" + request.ChangeActivePointerGrab(display = self.display, + onerror = onerror, + cursor = cursor, + time = time, + event_mask = event_mask) + + def ungrab_keyboard(self, time, onerror = None): + """Ungrab a grabbed keyboard and any queued events. See + XUngrabKeyboard(3X11).""" + request.UngrabKeyboard(display = self.display, + onerror = onerror, + time = time) + + def allow_events(self, mode, time, onerror = None): + """Release some queued events. mode should be one of + X.AsyncPointer, X.SyncPointer, X.AsyncKeyboard, X.SyncKeyboard, + X.ReplayPointer, X.ReplayKeyboard, X.AsyncBoth, or X.SyncBoth. + time should be a timestamp or X.CurrentTime.""" + request.AllowEvents(display = self.display, + onerror = onerror, + mode = mode, + time = time) + + def grab_server(self, onerror = None): + """Disable processing of requests on all other client connections + until the server is ungrabbed. Server grabbing should be avoided + as much as possible.""" + request.GrabServer(display = self.display, + onerror = onerror) + + def ungrab_server(self, onerror = None): + """Release the server if it was previously grabbed by this client.""" + request.UngrabServer(display = self.display, + onerror = onerror) + + def warp_pointer(self, x, y, src_window = X.NONE, src_x = 0, src_y = 0, + src_width = 0, src_height = 0, onerror = None): + """Move the pointer relative its current position by the offsets + (x, y). However, if src_window is a window the pointer is only + moved if the specified rectangle in src_window contains it. If + src_width is 0 it will be replaced with the width of src_window - + src_x. src_height is treated in a similar way. + + To move the pointer to absolute coordinates, use Window.warp_pointer().""" + request.WarpPointer(display = self.display, + onerror = onerror, + src_window = src_window, + dst_window = X.NONE, + src_x = src_x, + src_y = src_y, + src_width = src_width, + src_height = src_height, + dst_x = x, + dst_y = y) + + def set_input_focus(self, focus, revert_to, time, onerror = None): + """Set input focus to focus, which should be a window, + X.PointerRoot or X.NONE. revert_to specifies where the focus + reverts to if the focused window becomes not visible, and should + be X.RevertToParent, RevertToPointerRoot, or RevertToNone. See + XSetInputFocus(3X11) for details. + + There is also a Window.set_input_focus().""" + request.SetInputFocus(display = self.display, + onerror = onerror, + revert_to = revert_to, + focus = focus, + time = time) + + def get_input_focus(self): + """Return an object with the following attributes: + + focus + The window which currently holds the input + focus, X.NONE or X.PointerRoot. + revert_to + Where the focus will revert, one of X.RevertToParent, + RevertToPointerRoot, or RevertToNone. """ + return request.GetInputFocus(display = self.display) + + def query_keymap(self): + """Return a bit vector for the logical state of the keyboard, + where each bit set to 1 indicates that the corresponding key is + currently pressed down. The vector is represented as a list of 32 + integers. List item N contains the bits for keys 8N to 8N + 7 + with the least significant bit in the byte representing key 8N.""" + r = request.QueryKeymap(display = self.display) + return r.map + + def open_font(self, name): + """Open the font identifed by the pattern name and return its + font object. If name does not match any font, None is returned.""" + fid = self.display.allocate_resource_id() + ec = error.CatchError(error.BadName) + + request.OpenFont(display = self.display, + onerror = ec, + fid = fid, + name = name) + self.sync() + + if ec.get_error(): + self.display.free_resource_id(fid) + return None + else: + cls = self.display.get_resource_class('font', fontable.Font) + return cls(self.display, fid, owner = 1) + + def list_fonts(self, pattern, max_names): + """Return a list of font names matching pattern. No more than + max_names will be returned.""" + r = request.ListFonts(display = self.display, + max_names = max_names, + pattern = pattern) + return r.fonts + + def list_fonts_with_info(self, pattern, max_names): + """Return a list of fonts matching pattern. No more than + max_names will be returned. Each list item represents one font + and has the following properties: + + name + The name of the font. + min_bounds + max_bounds + min_char_or_byte2 + max_char_or_byte2 + default_char + draw_direction + min_byte1 + max_byte1 + all_chars_exist + font_ascent + font_descent + replies_hint + See the description of XFontStruct in XGetFontProperty(3X11) + for details on these values. + properties + A list of properties. Each entry has two attributes: + + name + The atom identifying this property. + value + A 32-bit unsigned value. + """ + return request.ListFontsWithInfo(display = self.display, + max_names = max_names, + pattern = pattern) + + def set_font_path(self, path, onerror = None): + """Set the font path to path, which should be a list of strings. + If path is empty, the default font path of the server will be + restored.""" + request.SetFontPath(display = self.display, + onerror = onerror, + path = path) + + def get_font_path(self): + """Return the current font path as a list of strings.""" + r = request.GetFontPath(display = self.display) + return r.paths + + def query_extension(self, name): + """Ask the server if it supports the extension name. If it is + supported an object with the following attributes is returned: + + major_opcode + The major opcode that the requests of this extension uses. + first_event + The base event code if the extension have additional events, or 0. + first_error + The base error code if the extension have additional errors, or 0. + + If the extension is not supported, None is returned.""" + r = request.QueryExtension(display = self.display, + name = name) + if r.present: + return r + else: + return None + + def list_extensions(self): + """Return a list of all the extensions provided by the server.""" + r = request.ListExtensions(display = self.display) + return r.names + + def change_keyboard_mapping(self, first_keycode, keysyms, onerror = None): + """Modify the keyboard mapping, starting with first_keycode. + keysyms is a list of tuples of keysyms. keysyms[n][i] will be + assigned to keycode first_keycode+n at index i.""" + request.ChangeKeyboardMapping(display = self.display, + onerror = onerror, + first_keycode = first_keycode, + keysyms = keysyms) + + def get_keyboard_mapping(self, first_keycode, count): + """Return the current keyboard mapping as a list of tuples, + starting at first_keycount and no more than count.""" + r = request.GetKeyboardMapping(display = self.display, + first_keycode = first_keycode, + count = count) + return r.keysyms + + def change_keyboard_control(self, onerror = None, **keys): + """Change the parameters provided as keyword arguments: + + key_click_percent + The volume of key clicks between 0 (off) and 100 (load). + -1 will restore default setting. + bell_percent + The base volume of the bell, coded as above. + bell_pitch + The pitch of the bell in Hz, -1 restores the default. + bell_duration + The duration of the bell in milliseconds, -1 restores + the default. + led + + led_mode + led_mode should be X.LedModeOff or X.LedModeOn. If led is + provided, it should be a 32-bit mask listing the LEDs that + should change. If led is not provided, all LEDs are changed. + key + + auto_repeat_mode + auto_repeat_mode should be one of X.AutoRepeatModeOff, + X.AutoRepeatModeOn, or X.AutoRepeatModeDefault. If key is + provided, that key will be modified, otherwise the global + state for the entire keyboard will be modified.""" + request.ChangeKeyboardControl(display = self.display, + onerror = onerror, + attrs = keys) + + def get_keyboard_control(self): + """Return an object with the following attributes: + + global_auto_repeat + X.AutoRepeatModeOn or X.AutoRepeatModeOff. + + auto_repeats + A list of 32 integers. List item N contains the bits for keys + 8N to 8N + 7 with the least significant bit in the byte + representing key 8N. If a bit is on, autorepeat is enabled + for the corresponding key. + + led_mask + A 32-bit mask indicating which LEDs are on. + + key_click_percent + The volume of key click, from 0 to 100. + + bell_percent + + bell_pitch + + bell_duration + The volume, pitch and duration of the bell. """ + return request.GetKeyboardControl(display = self.display) + + def bell(self, percent = 0, onerror = None): + """Ring the bell at the volume percent which is relative the base + volume. See XBell(3X11).""" + request.Bell(display = self.display, + onerror = onerror, + percent = percent) + + def change_pointer_control(self, accel = None, threshold = None, onerror = None): + """To change the pointer acceleration, set accel to a tuple (num, + denum). The pointer will then move num/denum times the normal + speed if it moves beyond the threshold number of pixels at once. + To change the threshold, set it to the number of pixels. -1 + restores the default.""" + if accel is None: + do_accel = 0 + accel_num = 0 + accel_denum = 0 + else: + do_accel = 1 + accel_num, accel_denum = accel + + if threshold is None: + do_threshold = 0 + else: + do_threshold = 1 + + request.ChangePointerControl(display = self.display, + onerror = onerror, + do_accel = do_accel, + do_thresh = do_threshold, + accel_num = accel_num, + accel_denum = accel_denum, + threshold = threshold) + + def get_pointer_control(self): + """Return an object with the following attributes: + + accel_num + + accel_denom + The acceleration as numerator/denumerator. + + threshold + The number of pixels the pointer must move before the + acceleration kicks in.""" + return request.GetPointerControl(display = self.display) + + def set_screen_saver(self, timeout, interval, prefer_blank, allow_exposures, onerror = None): + """See XSetScreenSaver(3X11).""" + request.SetScreenSaver(display = self.display, + onerror = onerror, + timeout = timeout, + interval = interval, + prefer_blank = prefer_blank, + allow_exposures = allow_exposures) + + def get_screen_saver(self): + """Return an object with the attributes timeout, interval, + prefer_blanking, allow_exposures. See XGetScreenSaver(3X11) for + details.""" + return request.GetScreenSaver(display = self.display) + + def change_hosts(self, mode, host_family, host, onerror = None): + """mode is either X.HostInsert or X.HostDelete. host_family is + one of X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, + X.FamilyServerInterpreted or X.FamilyInternetV6. + + host is a list of bytes. For the Internet family, it should be the + four bytes of an IPv4 address.""" + request.ChangeHosts(display = self.display, + onerror = onerror, + mode = mode, + host_family = host_family, + host = host) + + def list_hosts(self): + """Return an object with the following attributes: + +mode + X.EnableAccess if the access control list is used, X.DisableAccess otherwise. +hosts + The hosts on the access list. Each entry has the following attributes: + + family + X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, X.FamilyServerInterpreted or X.FamilyInternetV6. + name + A list of byte values, the coding depends on family. For the Internet family, it is the 4 bytes of an IPv4 address. + +""" + return request.ListHosts(display = self.display) + + def set_access_control(self, mode, onerror = None): + """Enable use of access control lists at connection setup if mode + is X.EnableAccess, disable if it is X.DisableAccess.""" + request.SetAccessControl(display = self.display, + onerror = onerror, + mode = mode) + + def set_close_down_mode(self, mode, onerror = None): + """Control what will happen with the client's resources at + connection close. The default is X.DestroyAll, the other values + are X.RetainPermanent and X.RetainTemporary.""" + request.SetCloseDownMode(display = self.display, + onerror = onerror, + mode = mode) + + def force_screen_saver(self, mode, onerror = None): + """If mode is X.ScreenSaverActive the screen saver is activated. + If it is X.ScreenSaverReset, the screen saver is deactivated as + if device input had been received.""" + request.ForceScreenSaver(display = self.display, + onerror = onerror, + mode = mode) + + def set_pointer_mapping(self, map): + """Set the mapping of the pointer buttons. map is a list of + logical button numbers. map must be of the same length as the + list returned by Display.get_pointer_mapping(). + + map[n] sets the + logical number for the physical button n+1. Logical number 0 + disables the button. Two physical buttons cannot be mapped to the + same logical number. + + If one of the buttons to be altered are + logically in the down state, X.MappingBusy is returned and the + mapping is not changed. Otherwise the mapping is changed and + X.MappingSuccess is returned.""" + r = request.SetPointerMapping(display = self.display, + map = map) + return r.status + + def get_pointer_mapping(self): + """Return a list of the pointer button mappings. Entry N in the + list sets the logical button number for the physical button N+1.""" + r = request.GetPointerMapping(display = self.display) + return r.map + + def set_modifier_mapping(self, keycodes): + """Set the keycodes for the eight modifiers X.Shift, X.Lock, + X.Control, X.Mod1, X.Mod2, X.Mod3, X.Mod4 and X.Mod5. keycodes + should be a eight-element list where each entry is a list of the + keycodes that should be bound to that modifier. + + If any changed + key is logically in the down state, X.MappingBusy is returned and + the mapping is not changed. If the mapping violates some server + restriction, X.MappingFailed is returned. Otherwise the mapping + is changed and X.MappingSuccess is returned.""" + r = request.SetModifierMapping(display = self.display, + keycodes = keycodes) + return r.status + + def get_modifier_mapping(self): + """Return a list of eight lists, one for each modifier. The list + can be indexed using X.ShiftMapIndex, X.Mod1MapIndex, and so on. + The sublists list the keycodes bound to that modifier.""" + r = request.GetModifierMapping(display = self.display) + return r.keycodes + + def no_operation(self, onerror = None): + """Do nothing but send a request to the server.""" + request.NoOperation(display = self.display, + onerror = onerror) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/error.py b/CLI/venv/lib/python3.12/site-packages/Xlib/error.py new file mode 100644 index 0000000..2d27722 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/error.py @@ -0,0 +1,160 @@ +# Xlib.error -- basic error classes +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Xlib modules +from . import X + +# Xlib.protocol modules +from .protocol import rq + + +class DisplayError(Exception): + def __init__(self, display): + self.display = display + + def __str__(self): + return 'Display error "%s"' % self.display + +class DisplayNameError(DisplayError): + def __str__(self): + return 'Bad display name "%s"' % self.display + +class DisplayConnectionError(DisplayError): + def __init__(self, display, msg): + self.display = display + self.msg = msg + + def __str__(self): + return 'Can\'t connect to display "%s": %s' % (self.display, self.msg) + +class ConnectionClosedError(Exception): + def __init__(self, whom): + self.whom = whom + + def __str__(self): + return 'Display connection closed by %s' % self.whom + + +class XauthError(Exception): pass +class XNoAuthError(Exception): pass + +class ResourceIDError(Exception): pass + + +class XError(rq.GetAttrData, Exception): + _fields = rq.Struct( rq.Card8('type'), # Always 0 + rq.Card8('code'), + rq.Card16('sequence_number'), + rq.Card32('resource_id'), + rq.Card16('minor_opcode'), + rq.Card8('major_opcode'), + rq.Pad(21) + ) + + def __init__(self, display, data): + self._data, _ = self._fields.parse_binary(data, display, rawdict = True) + + def __str__(self): + s = [] + for f in ('code', 'resource_id', 'sequence_number', + 'major_opcode', 'minor_opcode'): + s.append('{0} = {1}'.format(f, self._data[f])) + + return '{0}: {1}'.format(self.__class__, ', '.join(s)) + +class XResourceError(XError): + _fields = rq.Struct( rq.Card8('type'), # Always 0 + rq.Card8('code'), + rq.Card16('sequence_number'), + rq.Resource('resource_id'), + rq.Card16('minor_opcode'), + rq.Card8('major_opcode'), + rq.Pad(21) + ) + +class BadRequest(XError): pass +class BadValue(XError): pass +class BadWindow(XResourceError): pass +class BadPixmap(XResourceError): pass +class BadAtom(XError): pass +class BadCursor(XResourceError): pass +class BadFont(XResourceError): pass +class BadMatch(XError): pass +class BadDrawable(XResourceError): pass +class BadAccess(XError): pass +class BadAlloc(XError): pass +class BadColor(XResourceError): pass +class BadGC(XResourceError): pass +class BadIDChoice(XResourceError): pass +class BadName(XError): pass +class BadLength(XError): pass +class BadImplementation(XError): pass + +xerror_class = { + X.BadRequest: BadRequest, + X.BadValue: BadValue, + X.BadWindow: BadWindow, + X.BadPixmap: BadPixmap, + X.BadAtom: BadAtom, + X.BadCursor: BadCursor, + X.BadFont: BadFont, + X.BadMatch: BadMatch, + X.BadDrawable: BadDrawable, + X.BadAccess: BadAccess, + X.BadAlloc: BadAlloc, + X.BadColor: BadColor, + X.BadGC: BadGC, + X.BadIDChoice: BadIDChoice, + X.BadName: BadName, + X.BadLength: BadLength, + X.BadImplementation: BadImplementation, + } + + +class CatchError(object): + def __init__(self, *errors): + self.error_types = errors + self.error = None + self.request = None + + def __call__(self, error, request): + if self.error_types: + for etype in self.error_types: + if isinstance(error, etype): + self.error = error + self.request = request + return 1 + + return 0 + else: + self.error = error + self.request = request + return 1 + + def get_error(self): + return self.error + + def get_request(self): + return self.request + + def reset(self): + self.error = None + self.request = None diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__init__.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__init__.py new file mode 100644 index 0000000..394c92c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__init__.py @@ -0,0 +1,46 @@ +# Xlib.ext.__init__ -- X extension modules +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# __extensions__ is a list of tuples: (extname, extmod) +# extname is the name of the extension according to the X +# protocol. extmod is the name of the module in this package. + +__extensions__ = [ + # We load this first so other extensions can register generic event data + # structures. + ('Generic Event Extension', 'ge'), + ('XTEST', 'xtest'), + ('SHAPE', 'shape'), + ('XINERAMA', 'xinerama'), + ('RECORD', 'record'), + ('Composite', 'composite'), + ('RANDR', 'randr'), + ('XFIXES', 'xfixes'), + ('SECURITY', 'security'), + ('XInputExtension', 'xinput'), + ('NV-CONTROL', 'nvcontrol'), + ('DAMAGE', 'damage'), + ('DPMS', 'dpms'), + ('X-Resource', 'res'), + ('MIT-SCREEN-SAVER', 'screensaver'), + ] + +__all__ = map(lambda x: x[1], __extensions__) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd33468b474cc5c03ed4a019a901b5f030ed1b25 GIT binary patch literal 686 zcmYLHy>HV%6hGUEo20ZwT@VZ?Wk7gHED9s46gj3?N}S3zk?CT&_O-FF&(@t2IT1sU zSeO_aRyM?c0wde4Ol;6>op{#|anil}z2Cj>yB}LyEd;B$_&)ihBJ@irx2tvo)@=ai z=nTc^i*$@+gr!*efH3+dUt1i@b6Hcg9Zg=`JH!OjBx;*8Ov<)dm6)(3CtNog=W6`uY}%Qs!FR;NjY888jkG+sNF_l7qZj;1sz=fLjx7AdCX z|8iAG4+M17vd0}`WP8qNz?)+8wtyHXXjnB8p)|;SAGAx*51Q#Ap@R>pLLM(K{4N_W`*` zlkMNa@GH_JE>%q6_T^a5NU8T}GQ<12m(aXO%0W0K(F9Z77+5+y$4pO?6TO(1lbk&3 zKHb;F{5nM#y@m3b?u%Pom3j~)Bq@WSTg)#TFVZkOiNgcB2YI@%nfNeEw31ePpKD9B z1`XMo!ncC}oUdP-1p!yGu;3d(5Tb&2$^8E+fb;&jW literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/composite.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/composite.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4239b14c569acfadb58e31576502a90643e62031 GIT binary patch literal 10408 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/damage.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/damage.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2a1d2a10d01793da6ccec7c54ebd8837aecab16 GIT binary patch literal 7517 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/dpms.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/dpms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ff278d33127db0cd22d089b78d9edb973fe4c29 GIT binary patch literal 9167 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 Y{oDQd{NBo7t-t2Y=jXq)p8x*)2OnXmP5=M^ literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/randr.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/randr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d12258f9436d2cb44da66c0ddeee4ab2ca9d4c24 GIT binary patch literal 59742 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 Io@$i;1+S8y{Qv*} literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/res.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/res.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cef269cea67d44c75718b514e0663f580fd9bb9c GIT binary patch literal 12926 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/screensaver.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/screensaver.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d15440df42c0040f4fefd7ab3386fb86fbf22869 GIT binary patch literal 8687 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 NAe;BQ`2B2W{|RD4W6%Hq literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/security.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/security.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a8845eefeec4ef5a35ce00126f163f08a7890bcc GIT binary patch literal 5250 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 JGdvT=e*)AyHAMgb literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinerama.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinerama.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ee750d3f65ac3b0e336a9e851f7ee0967886cc6 GIT binary patch literal 10377 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 KAb*Bu#{Dl?y%bvj literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinput.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xinput.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0634e4d26fd1e95ec4204b80faa796bc446d2b73 GIT binary patch literal 32439 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xtest.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/__pycache__/xtest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1132dfff24f833e99590dfc16aa194af83ad111c GIT binary patch literal 5873 zcmd5=U2GHC6~1GS|DAt=GbC9DcKI1d;u6{bUAh#q{B4O@0o}4zE6aGs;NU;*j6+oT`1wZyKq;m+b~0aVf6bB;w}!ZqWB^q3=<=pzr1SKG64r z{`R_EldIYHD?}Bhc9`<|8>9pEn#n0Jn}kDYyDdaIcpvT1N5>X@bSj-NrY@xmXm_Do z?pZ@~vcQBZKy36Tb6mN6>eA&kSUM6nyTUhLZ+KV!%~w?=5kVmln~gw^?nXs}=W_F# zhGs=rM$=HZhQ)d-wkC~sL%WeKS1X(LVQ;d~+4!x&D`Jxdcu;Fm9Hz#y(`dt;e9c_9 z?!{^~nn!9i4yQQ|-n&&Vt|kpD8@0J?YQt^XsLj?_@W@`~J)`QMs8ma4Gt8OI#j}b^ zZLl7!EghT6(&)6&MsbZmmdw;;tV2_8=G9DGjb`%ct14X+L1_&mAT0ZtI~vWz(rPry zywPYntK?J2`=imD`B=(mq4)uFUeakkt~19(j4DT%^8z0QYrBZnHT}Grxu#!d_K#x< zbE3+@aj;E|M&<-Amnu9W6);7IlWuBQ&{L*=zh?**tfK=BpoPAyPzg5N=pat50oW&q5Fj-Ka*tMw6m%hDoJBy zDG0Ugi`$ok`%?X@<0a`(#pmqopFO+YN!kOSU%dP2oloyg-=p)>bJGj4FAC*A5Gpfs zGfN$%z>ms-A*dDR3Qu>Al>&##fx$-2YTHt<6gXIKy86X$p^J9uv(vQSoLIaHflwy| zw;Jn}43K%ESHqc*BAG(hXerjxDHEg{wDoGB5n?)HQ7GE}BrKyFK)FO@TUZvEOG#?E zRIETfAfy;o)CWWsjh%Q0c-C`G)uXUWY6e|5%AJ+DK!Bbl+nK1TsRVNvatHTY4JS1; zG(-_=nGX$^-u)g(M&Z#$fXtGA_^aLp%y z6@E4&8*Y6|QJV47s+SsmnvNFfEVyM4Yn#ZXb1|w;N7)+M56fM&1Kt#uly)IO52lFBv75s)_mA`_#Il%(N0_8fT_`zrA$@i_f-ZjLoy0`mi74Y5jNib5TKerGG%rYxMW zic1u|&+wAH$n66nJB>}@O+l0n0b#bJLS<~W)14?pRVL781Zs~P?iV$@jE;fQ1U%YN zAOJ${%|QrY>DJ<{a&R{Qk!SDhiFG&ex7{7TGd?@{Dj=DGUkSs?&y%+%u`|a7vo(ui zS47n_h2hguKx&a%gA~K2rGV5b$@W+!*$Ic4o^$ZB*!_B<$Th4Ws2RqFT80DF7LeLy zq2Yp2<1y4y5`qb{oAzEy?YIVpSW8hn=6SoRhPO$>YL2yDma8d!WLv=pX`bhF?1p+S zlgsNoG}bV>nOB88OONV>oN8o_PDRyY$rKayWLjk+&1UsAOskkM!-PUu?)~0?YQLoF zl%uHo7i!^Ss%jeZ0(VhOsWDAuzLR-f&t{B*Ehke0BQK>4!fpN#iYP zrhQ_W=WHUO=rVJS25$;W<0YIjc z*}N8(ecu}*#FJStvmF-9GK$Y)1Ck^>+Ao2;Q4|kBAO;o#O9Lfov?;E5=41v8_G6v# z{6B725GJ^gP|Pr~H-rhI7(@eKkCte#8PULT4iVk-cmFlmsA#;pQ zj)nIg3@<`bIrv~;ao~k?^qF*Yb#F;JSsvW`t;6P!4F^YyX2Ht?2ar`@=JAeMyKkB* zaDEDkO|N}bpVKDVkVWXC`Sq6Cg5qennby{86WfB~)ZMSz1`u+E`P#BB{>MSI@qUT< zBHL!jo3lRFX-Mlh!n&*9H>@;-$hP`rH>N1jv{X!gkCJrtnpUTHpZ#)-2s*A2a-S@%Q?a##vbrER2 zzZ!Wio^2BSY_<3|@jTz&u-wB${1?SIrrVGm&C#r$jYC-CzVIZO;)R>}FXG=f)xUa- z`#ql%rZIeC%w;wrYBOK;(sUW}2!3806X!mRv*)vGxi@|1K4$#?^a1@fsGxsozX!5z z7X;zI!$j!$CmHz0+coR@rn76dZA0u3q +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +"""Composite extension, allowing windows to be rendered to off-screen +storage. + +For detailed description, see the protocol specification at +http://freedesktop.org/wiki/Software/CompositeExt + +By itself this extension is not very useful, it is intended to be used +together with the DAMAGE and XFIXES extensions. Typically you would +also need RENDER or glX or some similar method of creating fancy +graphics. +""" + +from Xlib.protocol import rq +from Xlib.xobject import drawable + +extname = 'Composite' + +RedirectAutomatic = 0 +RedirectManual = 1 + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card32('major_version'), + rq.Card32('minor_version') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + rq.Pad(16), + ) + +def query_version(self): + return QueryVersion( + display = self.display, + opcode = self.display.get_extension_major(extname), + major_version=0, + minor_version=4 + ) + + +class RedirectWindow(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.Window('window'), + rq.Set('update', 1, (RedirectAutomatic, RedirectManual)), + rq.Pad(3), + ) + +def redirect_window(self, update, onerror = None): + """Redirect the hierarchy starting at this window to off-screen + storage. + """ + RedirectWindow(display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + window = self, + update = update, + ) + + +class RedirectSubwindows(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Window('window'), + rq.Set('update', 1, (RedirectAutomatic, RedirectManual)), + rq.Pad(3), + ) + +def redirect_subwindows(self, update, onerror = None): + """Redirect the hierarchies starting at all current and future + children to this window to off-screen storage. + """ + RedirectSubwindows(display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + window = self, + update = update, + ) + + +class UnredirectWindow(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Window('window'), + rq.Set('update', 1, (RedirectAutomatic, RedirectManual)), + rq.Pad(3), + ) + +def unredirect_window(self, update, onerror = None): + """Stop redirecting this window hierarchy. + """ + UnredirectWindow(display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + window = self, + update = update, + ) + + +class UnredirectSubindows(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Window('window'), + rq.Set('update', 1, (RedirectAutomatic, RedirectManual)), + rq.Pad(3), + ) + +def unredirect_subwindows(self, update, onerror = None): + """Stop redirecting the hierarchies of children to this window. + """ + RedirectWindow(display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + window = self, + update = update, + ) + + +class CreateRegionFromBorderClip(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + rq.Card32('region'), # FIXME: this should be a Region from XFIXES extension + rq.Window('window'), + ) + +def create_region_from_border_clip(self, onerror = None): + """Create a region of the border clip of the window, i.e. the area + that is not clipped by the parent and any sibling windows. + """ + + rid = self.display.allocate_resource_id() + CreateRegionFromBorderClip( + display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + region = rid, + window = self, + ) + + # FIXME: create Region object and return it + return rid + + +class NameWindowPixmap(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(6), + rq.RequestLength(), + rq.Window('window'), + rq.Pixmap('pixmap'), + ) + +def name_window_pixmap(self, onerror = None): + """Create a new pixmap that refers to the off-screen storage of + the window, including its border. + + This pixmap will remain allocated until freed whatever happens + with the window. However, the window will get a new off-screen + pixmap every time it is mapped or resized, so to keep track of the + contents you must listen for these events and get a new pixmap + after them. + """ + + pid = self.display.allocate_resource_id() + NameWindowPixmap(display = self.display, + onerror = onerror, + opcode = self.display.get_extension_major(extname), + window = self, + pixmap = pid, + ) + + cls = self.display.get_resource_class('pixmap', drawable.Pixmap) + return cls(self.display, pid, owner = 1) + +class GetOverlayWindow(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(7), + rq.RequestLength(), + rq.Window('window') + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('overlay_window'), + rq.Pad(20), + ) + +def get_overlay_window(self): + """Return the overlay window of the root window. + """ + + return GetOverlayWindow(display = self.display, + opcode = self.display.get_extension_major(extname), + window = self) + +def init(disp, info): + disp.extension_add_method('display', + 'composite_query_version', + query_version) + + disp.extension_add_method('window', + 'composite_redirect_window', + redirect_window) + + disp.extension_add_method('window', + 'composite_redirect_subwindows', + redirect_subwindows) + + disp.extension_add_method('window', + 'composite_unredirect_window', + unredirect_window) + + disp.extension_add_method('window', + 'composite_unredirect_subwindows', + unredirect_subwindows) + + disp.extension_add_method('window', + 'composite_create_region_from_border_clip', + create_region_from_border_clip) + + disp.extension_add_method('window', + 'composite_name_window_pixmap', + name_window_pixmap) + + disp.extension_add_method('window', + 'composite_get_overlay_window', + get_overlay_window) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/damage.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/damage.py new file mode 100644 index 0000000..614c808 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/damage.py @@ -0,0 +1,181 @@ +# Xlib.ext.damage -- DAMAGE extension module +# +# Copyright (C) 2018 Joseph Kogut +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +from Xlib import X +from Xlib.protocol import rq, structs +from Xlib.error import XError + +extname = 'DAMAGE' + +# Event codes # +DamageNotifyCode = 0 + +# Error codes # +BadDamageCode = 0 + +class BadDamageError(XError): + pass + +# DamageReportLevel options +DamageReportRawRectangles = 0 +DamageReportDeltaRectangles = 1 +DamageReportBoundingBox = 2 +DamageReportNonEmpty = 3 + +DamageReportLevel = ( + DamageReportRawRectangles, + DamageReportDeltaRectangles, + DamageReportBoundingBox, + DamageReportNonEmpty, +) + +DAMAGE = rq.Card32 + +# Methods + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + ) + + _reply = rq.Struct(rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + rq.Pad(16), + ) + +def query_version(self): + return QueryVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + +class DamageCreate(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + DAMAGE('damage'), + rq.Drawable('drawable'), + rq.Set('level', 1, DamageReportLevel), + rq.Pad(3), + ) + +def damage_create(self, level): + did = self.display.allocate_resource_id() + DamageCreate(display=self.display, + opcode=self.display.get_extension_major(extname), + damage=did, + drawable=self.id, + level=level, + ) + return did + +class DamageDestroy(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + DAMAGE('damage') + ) + +def damage_destroy(self, damage): + DamageDestroy(display=self.display, + opcode=self.display.get_extension_major(extname), + damage=damage, + ) + + self.display.free_resource_id(damage) + +class DamageSubtract(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + DAMAGE('damage'), + rq.Card32('repair'), + rq.Card32('parts') + ) + +def damage_subtract(self, damage, repair=X.NONE, parts=X.NONE): + DamageSubtract(display=self.display, + opcode=self.display.get_extension_major(extname), + damage=damage, + repair=repair, + parts=parts) + +class DamageAdd(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Card32('repair'), + rq.Card32('parts'), + ) + +def damage_add(self, repair, parts): + DamageAdd(display=self.display, + opcode=self.display.get_extension_major(extname), + repair=repair, + parts=parts) + +# Events # + +class DamageNotify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('level'), + rq.Card16('sequence_number'), + rq.Drawable('drawable'), + DAMAGE('damage'), + rq.Card32('timestamp'), + rq.Object('area', structs.Rectangle), + rq.Object('drawable_geometry', structs.Rectangle) + ) + +def init(disp, info): + disp.extension_add_method('display', + 'damage_query_version', + query_version) + + disp.extension_add_method('drawable', + 'damage_create', + damage_create) + + disp.extension_add_method('display', + 'damage_destroy', + damage_destroy) + + disp.extension_add_method('display', + 'damage_subtract', + damage_subtract) + + disp.extension_add_method('drawable', + 'damage_add', + damage_add) + + disp.extension_add_event(info.first_event + DamageNotifyCode, DamageNotify) + + disp.extension_add_error(code=BadDamageCode, err=BadDamageError) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/dpms.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/dpms.py new file mode 100644 index 0000000..5804169 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/dpms.py @@ -0,0 +1,232 @@ +# Xlib.ext.dpms -- X Display Power Management Signaling +# +# Copyright (C) 2020 Thiago Kenji Okada +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +''' +This extension provides X Protocol control over the VESA Display +Power Management Signaling (DPMS) characteristics of video boards +under control of the X Window System. + +Documentation: https://www.x.org/releases/X11R7.7/doc/xextproto/dpms.html +''' + +from Xlib.protocol import rq + +extname = 'DPMS' + + +# DPMS Extension Power Levels +# 0 DPMSModeOn In use +# 1 DPMSModeStandby Blanked, low power +# 2 DPMSModeSuspend Blanked, lower power +# 3 DPMSModeOff Shut off, awaiting activity +DPMSModeOn = 0 +DPMSModeStandby = 1 +DPMSModeSuspend = 2 +DPMSModeOff = 3 + +DPMSPowerLevel = ( + DPMSModeOn, + DPMSModeStandby, + DPMSModeSuspend, + DPMSModeOff, +) + + +class DPMSGetVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20), + ) + + +def get_version(self): + return DPMSGetVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class DPMSCapable(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Bool('capable'), + rq.Pad(23), + ) + + +def capable(self): + return DPMSCapable(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class DPMSGetTimeouts(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('standby_timeout'), + rq.Card16('suspend_timeout'), + rq.Card16('off_timeout'), + rq.Pad(18), + ) + + +def get_timeouts(self): + return DPMSGetTimeouts(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class DPMSSetTimeouts(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Card16('standby_timeout'), + rq.Card16('suspend_timeout'), + rq.Card16('off_timeout'), + rq.Pad(2) + ) + + +def set_timeouts(self, standby_timeout, suspend_timeout, off_timeout): + return DPMSSetTimeouts(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1, + standby_timeout=standby_timeout, + suspend_timeout=suspend_timeout, + off_timeout=off_timeout) + + +class DPMSEnable(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + ) + + +def enable(self): + return DPMSEnable(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class DPMSDisable(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + ) + + +def disable(self): + return DPMSDisable(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class DPMSForceLevel(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(6), + rq.RequestLength(), + rq.Resource('power_level', DPMSPowerLevel), + ) + + +def force_level(self, power_level): + return DPMSForceLevel(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1, + power_level=power_level) + + +class DPMSInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(7), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('power_level'), + rq.Bool('state'), + rq.Pad(21), + ) + + +def info(self): + return DPMSInfo(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +def init(disp, _info): + disp.extension_add_method('display', 'dpms_get_version', get_version) + disp.extension_add_method('display', 'dpms_capable', capable) + disp.extension_add_method('display', 'dpms_get_timeouts', get_timeouts) + disp.extension_add_method('display', 'dpms_set_timeouts', set_timeouts) + disp.extension_add_method('display', 'dpms_enable', enable) + disp.extension_add_method('display', 'dpms_disable', disable) + disp.extension_add_method('display', 'dpms_force_level', force_level) + disp.extension_add_method('display', 'dpms_info', info) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/ge.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/ge.py new file mode 100644 index 0000000..85d2d01 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/ge.py @@ -0,0 +1,112 @@ +# Xlib.ext.ge -- Generic Event extension module +# +# Copyright (C) 2012 Outpost Embedded, LLC +# Forest Bond +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +''' +ge - Generic Event Extension +''' + +from Xlib.protocol import rq + +extname = 'Generic Event Extension' + + +GenericEventCode = 35 + + +class GEQueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + rq.Pad(16), + ) + + +def query_version(self): + return GEQueryVersion( + display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=0, + ) + + +class GenericEvent(rq.Event): + _code = GenericEventCode + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('extension'), + rq.Card16('sequence_number'), + rq.Card32('length'), + rq.Card16('evtype'), + # Some generic events make use of this space, but with + # others the data is simply discarded. In any case we + # don't need to explicitly pad this out as we are + # always given at least 32 bytes and we save + # everything after the first ten as the "data" field. + #rq.Pad(22), + ) + + def __init__(self, binarydata = None, display = None, **keys): + if binarydata: + data = binarydata[10:] + binarydata = binarydata[:10] + else: + data = '' + + rq.Event.__init__( + self, + binarydata=binarydata, + display=display, + **keys + ) + + if display: + ge_event_data = getattr(display, 'ge_event_data', None) + if ge_event_data: + estruct = ge_event_data.get((self.extension, self.evtype), None) + if estruct: + data, _ = estruct.parse_binary(data, display) + + self._data['data'] = data + + +def add_event_data(self, extension, evtype, estruct): + if not hasattr(self.display, 'ge_event_data'): + self.display.ge_event_data = {} + self.display.ge_event_data[(extension, evtype)] = estruct + + +def init(disp, info): + disp.extension_add_method('display', 'ge_query_version', query_version) + disp.extension_add_method('display', 'ge_add_event_data', add_event_data) + disp.extension_add_event(GenericEventCode, GenericEvent) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/nvcontrol.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/nvcontrol.py new file mode 100644 index 0000000..3b0bfb6 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/nvcontrol.py @@ -0,0 +1,5393 @@ +# Xlib.ext.nvcontrol -- NV-CONTROL extension module +# +# Copyright (C) 2019 Roberto Leinardi +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +"""NV-CONTROL - provide access to the NV-CONTROL extension information.""" + +from Xlib.protocol import rq + +extname = 'NV-CONTROL' + + +def query_target_count(self, target): + """Return the target count""" + reply = NVCtrlQueryTargetCountReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_type=target.type()) + return int(reply._data.get('count')) + + +def query_int_attribute(self, target, display_mask, attr): + """Return the value of an integer attribute""" + reply = NVCtrlQueryAttributeReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=display_mask, + attr=attr) + if not reply._data.get('flags'): + return None + return int(reply._data.get('value')) + + +def set_int_attribute(self, target, display_mask, attr, value): + """Set the value of an integer attribute""" + reply = NVCtrlSetAttributeAndGetStatusReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=display_mask, + attr=attr, + value=value) + return reply._data.get('flags') != 0 + + +def query_string_attribute(self, target, display_mask, attr): + """Return the value of a string attribute""" + reply = NVCtrlQueryStringAttributeReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=display_mask, + attr=attr) + if not reply._data.get('flags'): + return None + return str(reply._data.get('string')).strip('\0') + + +def query_valid_attr_values(self, target, display_mask, attr): + """Return the value of an integer attribute""" + reply = NVCtrlQueryValidAttributeValuesReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=display_mask, + attr=attr) + if not reply._data.get('flags'): + return None + return int(reply._data.get('min')), int(reply._data.get('max')) + + +def query_binary_data(self, target, display_mask, attr): + """Return binary data""" + reply = NVCtrlQueryBinaryDataReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=display_mask, + attr=attr) + if not reply._data.get('flags'): + return None + return reply._data.get('data') + + +def get_coolers_used_by_gpu(self, target): + reply = NVCtrlQueryListCard32ReplyRequest(display=self.display, + opcode=self.display.get_extension_major(extname), + target_id=target.id(), + target_type=target.type(), + display_mask=0, + attr=NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU) + if not reply._data.get('flags'): + return None + fans = reply._data.get('list') + if len(fans) > 1: + return fans[1:] + else: + return None + + +def get_gpu_count(self): + """Return the number of GPU's present in the system.""" + return int(query_target_count(self, Gpu())) + + +def get_name(self, target): + """Return the GPU product name on which the specified X screen is running""" + return query_string_attribute(self, target, 0, NV_CTRL_STRING_PRODUCT_NAME) + + +def get_driver_version(self, target): + """Return the NVIDIA (kernel level) driver version for the specified screen or GPU""" + return query_string_attribute(self, target, 0, NV_CTRL_STRING_NVIDIA_DRIVER_VERSION) + + +def get_vbios_version(self, target): + """Return the version of the VBIOS for the specified screen or GPU""" + return query_string_attribute(self, target, 0, NV_CTRL_STRING_VBIOS_VERSION) + + +def get_gpu_uuid(self, target): + return query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_UUID) + + +def get_utilization_rates(self, target): + string = query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_UTILIZATION) + result = {} + if string is not None and string != '': + for line in string.split(','): + [key, value] = line.split('=')[:2] + result[key.strip()] = int(value) if value.isdigit() else value + return result + + +def get_performance_modes(self, target): + string = query_string_attribute(self, target, 0, NV_CTRL_STRING_PERFORMANCE_MODES) + result = [] + if string is not None and string != '': + for perf in string.split(';'): + perf_dict = {} + for line in perf.split(','): + [key, value] = line.split('=')[:2] + perf_dict[key.strip()] = int(value) if value.isdigit() else value + result.append(perf_dict) + return result + + +def get_clock_info(self, target): + string = query_string_attribute(self, target, 0, NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS) + result = {} + if string is not None and string != '': + for line in string.split(','): + [key, value] = line.split('=')[:2] + result[key.strip()] = int(value) if value.isdigit() else value + return result + + +def get_vram(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_RAM) + + +def get_irq(self, target): + """Return the interrupt request line used by the GPU driving the screen""" + return query_int_attribute(self, target, 0, NV_CTRL_IRQ) + + +def supports_framelock(self, target): + """Return whether the underlying GPU supports Frame Lock. + + All of the other frame lock attributes are only applicable if this returns True. + """ + return query_int_attribute(self, target, 0, NV_CTRL_FRAMELOCK) == 1 + + +def gvo_supported(self, screen): + """Return whether this X screen supports GVO + + If this screen does not support GVO output, then all other GVO attributes are unavailable. + """ + return query_int_attribute(self, screen, [], NV_CTRL_GVO_SUPPORTED) + + +def get_core_temp(self, target): + """Return the current core temperature of the GPU driving the X screen.""" + return query_int_attribute(self, target, 0, NV_CTRL_GPU_CORE_TEMPERATURE) + + +def get_core_threshold(self, target): + """Return the current GPU core slowdown threshold temperature. + + It reflects the temperature at which the GPU is throttled to prevent overheating. + """ + return query_int_attribute(self, target, 0, NV_CTRL_GPU_CORE_THRESHOLD) + + +def get_default_core_threshold(self, target): + """Return the default core threshold temperature.""" + return query_int_attribute(self, target, 0, NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD) + + +def get_max_core_threshold(self, target): + """Return the maximum core threshold temperature.""" + return query_int_attribute(self, target, 0, NV_CTRL_GPU_MAX_CORE_THRESHOLD) + + +def get_ambient_temp(self, target): + """Return the current temperature in the immediate neighbourhood of the GPU driving the X screen.""" + return query_int_attribute(self, target, 0, NV_CTRL_AMBIENT_TEMPERATURE) + + +def get_cuda_cores(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_CORES) + + +def get_memory_bus_width(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_MEMORY_BUS_WIDTH) + + +def get_total_dedicated_gpu_memory(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY) + + +def get_used_dedicated_gpu_memory(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_USED_DEDICATED_GPU_MEMORY) + + +def get_curr_pcie_link_width(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH) + + +def get_max_pcie_link_width(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH) + + +def get_curr_pcie_link_generation(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_PCIE_GENERATION) + + +def get_encoder_utilization(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_ENCODER_UTILIZATION) + + +def get_decoder_utilization(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_VIDEO_DECODER_UTILIZATION) + + +def get_current_performance_level(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL) + + +def get_gpu_nvclock_offset(self, target, perf_level): + return query_int_attribute(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET) + + +def set_gpu_nvclock_offset(self, target, perf_level, offset): + return set_int_attribute(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET, offset) + + +def set_gpu_nvclock_offset_all_levels(self, target, offset): + return set_int_attribute(self, target, 0, NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS, offset) + + +def get_gpu_nvclock_offset_range(self, target, perf_level): + return query_valid_attr_values(self, target, perf_level, NV_CTRL_GPU_NVCLOCK_OFFSET) + + +def get_mem_transfer_rate_offset(self, target, perf_level): + return query_int_attribute(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET) + + +def set_mem_transfer_rate_offset(self, target, perf_level, offset): + return set_int_attribute(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET, offset) + + +def set_mem_transfer_rate_offset_all_levels(self, target, offset): + return set_int_attribute(self, target, 0, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS, offset) + + +def get_mem_transfer_rate_offset_range(self, target, perf_level): + return query_valid_attr_values(self, target, perf_level, NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET) + + +def get_cooler_manual_control_enabled(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL) + + +def set_cooler_manual_control_enabled(self, target, enabled): + return set_int_attribute(self, target, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL, 1 if enabled else 0) == 1 + + +def get_fan_duty(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL) + + +def set_fan_duty(self, cooler, speed): + return set_int_attribute(self, cooler, 0, NV_CTRL_THERMAL_COOLER_LEVEL, speed) + + +def get_fan_rpm(self, target): + return query_int_attribute(self, target, 0, NV_CTRL_THERMAL_COOLER_SPEED) + + +def get_max_displays(self, target): + """Return the maximum number of display devices that can be driven simultaneously on a GPU. + + Note that this does not indicate the maximum number of bits that can be set in + NV_CTRL_CONNECTED_DISPLAYS, because more display devices can be connected than are actively + in use. + """ + return query_int_attribute(self, target, 0, NV_CTRL_MAX_DISPLAYS) + + +def _displaystr2num(st): + """Return a display number from a string""" + num = None + for s, n in [('DFP-', 16), ('TV-', 8), ('CRT-', 0)]: + if st.startswith(s): + try: + curnum = int(st[len(s):]) + if 0 <= curnum <= 7: + num = n + curnum + break + except Exception: + pass + if num is not None: + return num + else: + raise ValueError('Unrecognised display name: ' + st) + + +def _displays2mask(displays): + """Return a display mask from an array of display numbers.""" + mask = 0 + for d in displays: + mask += (1 << _displaystr2num(d)) + return mask + + +def init(disp, info): + disp.extension_add_method('display', 'nvcontrol_query_target_count', query_target_count) + disp.extension_add_method('display', 'nvcontrol_query_int_attribute', query_int_attribute) + disp.extension_add_method('display', 'nvcontrol_query_string_attribute', query_string_attribute) + disp.extension_add_method('display', 'nvcontrol_query_valid_attr_values', query_valid_attr_values) + disp.extension_add_method('display', 'nvcontrol_query_binary_data', query_binary_data) + disp.extension_add_method('display', 'nvcontrol_get_gpu_count', get_gpu_count) + disp.extension_add_method('display', 'nvcontrol_get_vram', get_vram) + disp.extension_add_method('display', 'nvcontrol_get_irq', get_irq) + disp.extension_add_method('display', 'nvcontrol_supports_framelock', supports_framelock) + disp.extension_add_method('display', 'nvcontrol_get_core_temp', get_core_temp) + disp.extension_add_method('display', 'nvcontrol_get_core_threshold', get_core_threshold) + disp.extension_add_method('display', 'nvcontrol_get_default_core_threshold', get_default_core_threshold) + disp.extension_add_method('display', 'nvcontrol_get_max_core_threshold', get_max_core_threshold) + disp.extension_add_method('display', 'nvcontrol_get_ambient_temp', get_ambient_temp) + disp.extension_add_method('display', 'nvcontrol_get_cuda_cores', get_cuda_cores) + disp.extension_add_method('display', 'nvcontrol_get_memory_bus_width', get_memory_bus_width) + disp.extension_add_method('display', 'nvcontrol_get_total_dedicated_gpu_memory', get_total_dedicated_gpu_memory) + disp.extension_add_method('display', 'nvcontrol_get_used_dedicated_gpu_memory', get_used_dedicated_gpu_memory) + disp.extension_add_method('display', 'nvcontrol_get_curr_pcie_link_width', get_curr_pcie_link_width) + disp.extension_add_method('display', 'nvcontrol_get_max_pcie_link_width', get_max_pcie_link_width) + disp.extension_add_method('display', 'nvcontrol_get_curr_pcie_link_generation', get_curr_pcie_link_generation) + disp.extension_add_method('display', 'nvcontrol_get_encoder_utilization', get_encoder_utilization) + disp.extension_add_method('display', 'nvcontrol_get_decoder_utilization', get_decoder_utilization) + disp.extension_add_method('display', 'nvcontrol_get_current_performance_level', get_current_performance_level) + disp.extension_add_method('display', 'nvcontrol_get_gpu_nvclock_offset', get_gpu_nvclock_offset) + disp.extension_add_method('display', 'nvcontrol_set_gpu_nvclock_offset', set_gpu_nvclock_offset) + disp.extension_add_method('display', 'nvcontrol_set_gpu_nvclock_offset_all_levels', set_gpu_nvclock_offset_all_levels) + disp.extension_add_method('display', 'nvcontrol_get_mem_transfer_rate_offset', get_mem_transfer_rate_offset) + disp.extension_add_method('display', 'nvcontrol_set_mem_transfer_rate_offset', set_mem_transfer_rate_offset) + disp.extension_add_method('display', 'nvcontrol_set_mem_transfer_rate_offset_all_levels', set_mem_transfer_rate_offset_all_levels) + disp.extension_add_method('display', 'nvcontrol_get_cooler_manual_control_enabled', + get_cooler_manual_control_enabled) + disp.extension_add_method('display', 'nvcontrol_get_fan_duty', get_fan_duty) + disp.extension_add_method('display', 'nvcontrol_set_fan_duty', set_fan_duty) + disp.extension_add_method('display', 'nvcontrol_get_fan_rpm', get_fan_rpm) + disp.extension_add_method('display', 'nvcontrol_get_coolers_used_by_gpu', get_coolers_used_by_gpu) + disp.extension_add_method('display', 'nvcontrol_get_max_displays', get_max_displays) + disp.extension_add_method('display', 'nvcontrol_get_name', get_name) + disp.extension_add_method('display', 'nvcontrol_get_driver_version', get_driver_version) + disp.extension_add_method('display', 'nvcontrol_get_vbios_version', get_vbios_version) + disp.extension_add_method('display', 'nvcontrol_get_gpu_uuid', get_gpu_uuid) + disp.extension_add_method('display', 'nvcontrol_get_utilization_rates', get_utilization_rates) + disp.extension_add_method('display', 'nvcontrol_get_performance_modes', get_performance_modes) + disp.extension_add_method('display', 'nvcontrol_get_clock_info', get_clock_info) + disp.extension_add_method('display', 'nvcontrol_set_cooler_manual_control_enabled', + set_cooler_manual_control_enabled) + disp.extension_add_method('display', 'nvcontrol_get_gpu_nvclock_offset_range', + get_gpu_nvclock_offset_range) + disp.extension_add_method('display', 'nvcontrol_get_mem_transfer_rate_offset_range', + get_mem_transfer_rate_offset_range) + + +############################################################################ +# +# Attributes +# +# Some attributes may only be read; some may require a display_mask +# argument and others may be valid only for specific target types. +# This information is encoded in the "permission" comment after each +# attribute #define, and can be queried at run time with +# XNVCTRLQueryValidAttributeValues() and/or +# XNVCTRLQueryValidTargetAttributeValues() +# +# Key to Integer Attribute "Permissions": +# +# R: The attribute is readable (in general, all attributes will be +# readable) +# +# W: The attribute is writable (attributes may not be writable for +# various reasons: they represent static system information, they +# can only be changed by changing an XF86Config option, etc). +# +# D: The attribute requires the display mask argument. The +# attributes NV_CTRL_CONNECTED_DISPLAYS and NV_CTRL_ENABLED_DISPLAYS +# will be a bitmask of what display devices are connected and what +# display devices are enabled for use in X, respectively. Each bit +# in the bitmask represents a display device; it is these bits which +# should be used as the display_mask when dealing with attributes +# designated with "D" below. For attributes that do not require the +# display mask, the argument is ignored. +# +# Alternatively, NV-CONTROL versions 1.27 and greater allow these +# attributes to be accessed via display target types, in which case +# the display_mask is ignored. +# +# G: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GPU +# target type via XNVCTRLQueryTargetAttribute(). +# +# F: The attribute may be queried using an NV_CTRL_TARGET_TYPE_FRAMELOCK +# target type via XNVCTRLQueryTargetAttribute(). +# +# X: When Xinerama is enabled, this attribute is kept consistent across +# all Physical X Screens; assignment of this attribute will be +# broadcast by the NVIDIA X Driver to all X Screens. +# +# V: The attribute may be queried using an NV_CTRL_TARGET_TYPE_VCSC +# target type via XNVCTRLQueryTargetAttribute(). +# +# I: The attribute may be queried using an NV_CTRL_TARGET_TYPE_GVI target type +# via XNVCTRLQueryTargetAttribute(). +# +# Q: The attribute is a 64-bit integer attribute; use the 64-bit versions +# of the appropriate query interfaces. +# +# C: The attribute may be queried using an NV_CTRL_TARGET_TYPE_COOLER target +# type via XNVCTRLQueryTargetAttribute(). +# +# S: The attribute may be queried using an NV_CTRL_TARGET_TYPE_THERMAL_SENSOR +# target type via XNVCTRLQueryTargetAttribute(). +# +# T: The attribute may be queried using an +# NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER target type +# via XNVCTRLQueryTargetAttribute(). +# +# NOTE: Unless mentioned otherwise, all attributes may be queried using +# an NV_CTRL_TARGET_TYPE_X_SCREEN target type via +# XNVCTRLQueryTargetAttribute(). +# + + +############################################################################ + +# +# Integer attributes: +# +# Integer attributes can be queried through the XNVCTRLQueryAttribute() and +# XNVCTRLQueryTargetAttribute() function calls. +# +# Integer attributes can be set through the XNVCTRLSetAttribute() and +# XNVCTRLSetTargetAttribute() function calls. +# +# Unless otherwise noted, all integer attributes can be queried/set +# using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot +# take an NV_CTRL_TARGET_TYPE_X_SCREEN also cannot be queried/set through +# XNVCTRLQueryAttribute()/XNVCTRLSetAttribute() (Since these assume +# an X Screen target). +# + + +# +# NV_CTRL_FLATPANEL_SCALING - not supported +# + +NV_CTRL_FLATPANEL_SCALING = 2 # not supported +NV_CTRL_FLATPANEL_SCALING_DEFAULT = 0 # not supported +NV_CTRL_FLATPANEL_SCALING_NATIVE = 1 # not supported +NV_CTRL_FLATPANEL_SCALING_SCALED = 2 # not supported +NV_CTRL_FLATPANEL_SCALING_CENTERED = 3 # not supported +NV_CTRL_FLATPANEL_SCALING_ASPECT_SCALED = 4 # not supported + +# +# NV_CTRL_FLATPANEL_DITHERING - not supported +# +# NV_CTRL_DITHERING should be used instead. +# + +NV_CTRL_FLATPANEL_DITHERING = 3 # not supported +NV_CTRL_FLATPANEL_DITHERING_DEFAULT = 0 # not supported +NV_CTRL_FLATPANEL_DITHERING_ENABLED = 1 # not supported +NV_CTRL_FLATPANEL_DITHERING_DISABLED = 2 # not supported + +# +# NV_CTRL_DITHERING - the requested dithering configuration; +# possible values are: +# +# 0: auto (the driver will decide when to dither) +# 1: enabled (the driver will always dither when possible) +# 2: disabled (the driver will never dither) +# + +NV_CTRL_DITHERING = 3 # RWDG +NV_CTRL_DITHERING_AUTO = 0 +NV_CTRL_DITHERING_ENABLED = 1 +NV_CTRL_DITHERING_DISABLED = 2 + +# +# NV_CTRL_DIGITAL_VIBRANCE - sets the digital vibrance level for the +# specified display device. +# + +NV_CTRL_DIGITAL_VIBRANCE = 4 # RWDG + +# +# NV_CTRL_BUS_TYPE - returns the bus type through which the specified device +# is connected to the computer. +# When this attribute is queried on an X screen target, the bus type of the +# GPU driving the X screen is returned. +# + +NV_CTRL_BUS_TYPE = 5 # R--GI +NV_CTRL_BUS_TYPE_AGP = 0 +NV_CTRL_BUS_TYPE_PCI = 1 +NV_CTRL_BUS_TYPE_PCI_EXPRESS = 2 +NV_CTRL_BUS_TYPE_INTEGRATED = 3 + +# +# NV_CTRL_TOTAL_GPU_MEMORY - returns the total amount of memory available +# to the specified GPU (or the GPU driving the specified X +# screen). Note: if the GPU supports TurboCache(TM), the value +# reported may exceed the amount of video memory installed on the +# GPU. The value reported for integrated GPUs may likewise exceed +# the amount of dedicated system memory set aside by the system +# BIOS for use by the integrated GPU. +# + +NV_CTRL_TOTAL_GPU_MEMORY = 6 # R--G +NV_CTRL_VIDEO_RAM = NV_CTRL_TOTAL_GPU_MEMORY + +# +# NV_CTRL_IRQ - returns the interrupt request line used by the specified +# device. +# When this attribute is queried on an X screen target, the IRQ of the GPU +# driving the X screen is returned. +# + +NV_CTRL_IRQ = 7 # R--GI + +# +# NV_CTRL_OPERATING_SYSTEM - returns the operating system on which +# the X server is running. +# + +NV_CTRL_OPERATING_SYSTEM = 8 # R--G +NV_CTRL_OPERATING_SYSTEM_LINUX = 0 +NV_CTRL_OPERATING_SYSTEM_FREEBSD = 1 +NV_CTRL_OPERATING_SYSTEM_SUNOS = 2 + +# +# NV_CTRL_SYNC_TO_VBLANK - enables sync to vblank for OpenGL clients. +# This setting is only applied to OpenGL clients that are started +# after this setting is applied. +# + +NV_CTRL_SYNC_TO_VBLANK = 9 # RW-X +NV_CTRL_SYNC_TO_VBLANK_OFF = 0 +NV_CTRL_SYNC_TO_VBLANK_ON = 1 + +# +# NV_CTRL_LOG_ANISO - enables anisotropic filtering for OpenGL +# clients; on some NVIDIA hardware, this can only be enabled or +# disabled; on other hardware different levels of anisotropic +# filtering can be specified. This setting is only applied to OpenGL +# clients that are started after this setting is applied. +# + +NV_CTRL_LOG_ANISO = 10 # RW-X + +# +# NV_CTRL_FSAA_MODE - the FSAA setting for OpenGL clients; possible +# FSAA modes: +# +# NV_CTRL_FSAA_MODE_2x "2x Bilinear Multisampling" +# NV_CTRL_FSAA_MODE_2x_5t "2x Quincunx Multisampling" +# NV_CTRL_FSAA_MODE_15x15 "1.5 x 1.5 Supersampling" +# NV_CTRL_FSAA_MODE_2x2 "2 x 2 Supersampling" +# NV_CTRL_FSAA_MODE_4x "4x Bilinear Multisampling" +# NV_CTRL_FSAA_MODE_4x_9t "4x Gaussian Multisampling" +# NV_CTRL_FSAA_MODE_8x "2x Bilinear Multisampling by 4x Supersampling" +# NV_CTRL_FSAA_MODE_16x "4x Bilinear Multisampling by 4x Supersampling" +# NV_CTRL_FSAA_MODE_8xS "4x Multisampling by 2x Supersampling" +# +# This setting is only applied to OpenGL clients that are started +# after this setting is applied. +# + +NV_CTRL_FSAA_MODE = 11 # RW-X +NV_CTRL_FSAA_MODE_NONE = 0 +NV_CTRL_FSAA_MODE_2x = 1 +NV_CTRL_FSAA_MODE_2x_5t = 2 +NV_CTRL_FSAA_MODE_15x15 = 3 +NV_CTRL_FSAA_MODE_2x2 = 4 +NV_CTRL_FSAA_MODE_4x = 5 +NV_CTRL_FSAA_MODE_4x_9t = 6 +NV_CTRL_FSAA_MODE_8x = 7 +NV_CTRL_FSAA_MODE_16x = 8 +NV_CTRL_FSAA_MODE_8xS = 9 +NV_CTRL_FSAA_MODE_8xQ = 10 +NV_CTRL_FSAA_MODE_16xS = 11 +NV_CTRL_FSAA_MODE_16xQ = 12 +NV_CTRL_FSAA_MODE_32xS = 13 +NV_CTRL_FSAA_MODE_32x = 14 +NV_CTRL_FSAA_MODE_64xS = 15 +NV_CTRL_FSAA_MODE_MAX = NV_CTRL_FSAA_MODE_64xS + +# +# NV_CTRL_UBB - returns whether UBB is enabled for the specified X +# screen. +# + +NV_CTRL_UBB = 13 # R-- +NV_CTRL_UBB_OFF = 0 +NV_CTRL_UBB_ON = 1 + +# +# NV_CTRL_OVERLAY - returns whether the RGB overlay is enabled for +# the specified X screen. +# + +NV_CTRL_OVERLAY = 14 # R-- +NV_CTRL_OVERLAY_OFF = 0 +NV_CTRL_OVERLAY_ON = 1 + +# +# NV_CTRL_STEREO - returns whether stereo (and what type) is enabled +# for the specified X screen. +# + +NV_CTRL_STEREO = 16 # R-- +NV_CTRL_STEREO_OFF = 0 +NV_CTRL_STEREO_DDC = 1 +NV_CTRL_STEREO_BLUELINE = 2 +NV_CTRL_STEREO_DIN = 3 +NV_CTRL_STEREO_PASSIVE_EYE_PER_DPY = 4 +NV_CTRL_STEREO_VERTICAL_INTERLACED = 5 +NV_CTRL_STEREO_COLOR_INTERLACED = 6 +NV_CTRL_STEREO_HORIZONTAL_INTERLACED = 7 +NV_CTRL_STEREO_CHECKERBOARD_PATTERN = 8 +NV_CTRL_STEREO_INVERSE_CHECKERBOARD_PATTERN = 9 +NV_CTRL_STEREO_3D_VISION = 10 +NV_CTRL_STEREO_3D_VISION_PRO = 11 +NV_CTRL_STEREO_HDMI_3D = 12 +NV_CTRL_STEREO_TRIDELITY_SL = 13 +NV_CTRL_STEREO_INBAND_STEREO_SIGNALING = 14 +NV_CTRL_STEREO_MAX = NV_CTRL_STEREO_INBAND_STEREO_SIGNALING + +# +# NV_CTRL_EMULATE - not supported +# + +NV_CTRL_EMULATE = 17 # not supported +NV_CTRL_EMULATE_NONE = 0 # not supported + +# +# NV_CTRL_TWINVIEW - returns whether TwinView is enabled for the +# specified X screen. +# + +NV_CTRL_TWINVIEW = 18 # R-- +NV_CTRL_TWINVIEW_NOT_ENABLED = 0 +NV_CTRL_TWINVIEW_ENABLED = 1 + +# +# NV_CTRL_CONNECTED_DISPLAYS - deprecated +# +# NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU and +# NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN should be used instead. +# + +NV_CTRL_CONNECTED_DISPLAYS = 19 # deprecated + +# +# NV_CTRL_ENABLED_DISPLAYS - Event that notifies when one or more display +# devices are enabled or disabled on a GPU and/or X screen. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# +# Note: Querying this value has been deprecated. +# NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU, +# NV_CTRL_DISPLAY_ENABLED, and +# NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN should be used +# instead to obtain the list of enabled displays. +# + +NV_CTRL_ENABLED_DISPLAYS = 20 # ---G + +############################################################################ +# +# Integer attributes specific to configuring Frame Lock on boards that +# support it. +# + + +# +# NV_CTRL_FRAMELOCK - returns whether the underlying GPU supports +# Frame Lock. All of the other frame lock attributes are only +# applicable if NV_CTRL_FRAMELOCK is _SUPPORTED. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_FRAMELOCK = 21 # R--G +NV_CTRL_FRAMELOCK_NOT_SUPPORTED = 0 +NV_CTRL_FRAMELOCK_SUPPORTED = 1 + +# +# NV_CTRL_FRAMELOCK_MASTER - deprecated +# +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG should be used instead. +# + +NV_CTRL_FRAMELOCK_MASTER = 22 # deprecated +NV_CTRL_FRAMELOCK_MASTER_FALSE = 0 # deprecated +NV_CTRL_FRAMELOCK_MASTER_TRUE = 1 # deprecated + +# +# NV_CTRL_FRAMELOCK_POLARITY - sync either to the rising edge of the +# frame lock pulse, the falling edge of the frame lock pulse or both. +# +# On Quadro Sync II, this attribute is ignored when +# NV_CTRL_USE_HOUSE_SYNC is OUTPUT. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_POLARITY = 23 # RW-F +NV_CTRL_FRAMELOCK_POLARITY_RISING_EDGE = 0x1 +NV_CTRL_FRAMELOCK_POLARITY_FALLING_EDGE = 0x2 +NV_CTRL_FRAMELOCK_POLARITY_BOTH_EDGES = 0x3 + +# +# NV_CTRL_FRAMELOCK_SYNC_DELAY - delay between the frame lock pulse +# and the GPU sync. This value must be multiplied by +# NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION to determine the sync delay in +# nanoseconds. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# +# USAGE NOTE: NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX and +# NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR are deprecated. +# The Sync Delay _MAX and _FACTOR are different for different +# Quadro Sync products and so, to be correct, the valid values for +# NV_CTRL_FRAMELOCK_SYNC_DELAY must be queried to get the range +# of acceptable sync delay values, and +# NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION must be queried to +# obtain the correct factor. +# + +NV_CTRL_FRAMELOCK_SYNC_DELAY = 24 # RW-F +NV_CTRL_FRAMELOCK_SYNC_DELAY_MAX = 2047 # deprecated +NV_CTRL_FRAMELOCK_SYNC_DELAY_FACTOR = 7.81 # deprecated + +# +# NV_CTRL_FRAMELOCK_SYNC_INTERVAL - how many house sync pulses +# between the frame lock sync generation (0 == sync every house sync); +# this only applies to the master when receiving house sync. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_SYNC_INTERVAL = 25 # RW-F + +# +# NV_CTRL_FRAMELOCK_PORT0_STATUS - status of the rj45 port0. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_PORT0_STATUS = 26 # R--F +NV_CTRL_FRAMELOCK_PORT0_STATUS_INPUT = 0 +NV_CTRL_FRAMELOCK_PORT0_STATUS_OUTPUT = 1 + +# +# NV_CTRL_FRAMELOCK_PORT1_STATUS - status of the rj45 port1. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_PORT1_STATUS = 27 # R--F +NV_CTRL_FRAMELOCK_PORT1_STATUS_INPUT = 0 +NV_CTRL_FRAMELOCK_PORT1_STATUS_OUTPUT = 1 + +# +# NV_CTRL_FRAMELOCK_HOUSE_STATUS - returns whether or not the house +# sync input signal was detected on the BNC connector of the frame lock +# board. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_HOUSE_STATUS = 28 # R--F +NV_CTRL_FRAMELOCK_HOUSE_STATUS_NOT_DETECTED = 0 +NV_CTRL_FRAMELOCK_HOUSE_STATUS_DETECTED = 1 + +# +# NV_CTRL_FRAMELOCK_SYNC - enable/disable the syncing of display +# devices to the frame lock pulse as specified by previous calls to +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG. +# +# This attribute can only be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. +# + +NV_CTRL_FRAMELOCK_SYNC = 29 # RW-G +NV_CTRL_FRAMELOCK_SYNC_DISABLE = 0 +NV_CTRL_FRAMELOCK_SYNC_ENABLE = 1 + +# +# NV_CTRL_FRAMELOCK_SYNC_READY - reports whether a frame lock +# board is receiving sync (regardless of whether or not any display +# devices are using the sync). +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_SYNC_READY = 30 # R--F +NV_CTRL_FRAMELOCK_SYNC_READY_FALSE = 0 +NV_CTRL_FRAMELOCK_SYNC_READY_TRUE = 1 + +# +# NV_CTRL_FRAMELOCK_STEREO_SYNC - this indicates that the GPU stereo +# signal is in sync with the frame lock stereo signal. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_STEREO_SYNC = 31 # R--G +NV_CTRL_FRAMELOCK_STEREO_SYNC_FALSE = 0 +NV_CTRL_FRAMELOCK_STEREO_SYNC_TRUE = 1 + +# +# NV_CTRL_FRAMELOCK_TEST_SIGNAL - to test the connections in the sync +# group, tell the master to enable a test signal, then query port[01] +# status and sync_ready on all slaves. When done, tell the master to +# disable the test signal. Test signal should only be manipulated +# while NV_CTRL_FRAMELOCK_SYNC is enabled. +# +# The TEST_SIGNAL is also used to reset the Universal Frame Count (as +# returned by the glXQueryFrameCountNV() function in the +# GLX_NV_swap_group extension). Note: for best accuracy of the +# Universal Frame Count, it is recommended to toggle the TEST_SIGNAL +# on and off after enabling frame lock. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_FRAMELOCK_TEST_SIGNAL = 32 # RW-G +NV_CTRL_FRAMELOCK_TEST_SIGNAL_DISABLE = 0 +NV_CTRL_FRAMELOCK_TEST_SIGNAL_ENABLE = 1 + +# +# NV_CTRL_FRAMELOCK_ETHERNET_DETECTED - The frame lock boards are +# cabled together using regular cat5 cable, connecting to rj45 ports +# on the backplane of the card. There is some concern that users may +# think these are ethernet ports and connect them to a +# router/hub/etc. The hardware can detect this and will shut off to +# prevent damage (either to itself or to the router). +# NV_CTRL_FRAMELOCK_ETHERNET_DETECTED may be called to find out if +# ethernet is connected to one of the rj45 ports. An appropriate +# error message should then be displayed. The _PORT0 and _PORT1 +# values may be or'ed together. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_ETHERNET_DETECTED = 33 # R--F +NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_NONE = 0 +NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT0 = 0x1 +NV_CTRL_FRAMELOCK_ETHERNET_DETECTED_PORT1 = 0x2 + +# +# NV_CTRL_FRAMELOCK_VIDEO_MODE - get/set what video mode is used +# to interperate the house sync signal. This should only be set +# on the master. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_VIDEO_MODE = 34 # RW-F +NV_CTRL_FRAMELOCK_VIDEO_MODE_NONE = 0 +NV_CTRL_FRAMELOCK_VIDEO_MODE_TTL = 1 +NV_CTRL_FRAMELOCK_VIDEO_MODE_NTSCPALSECAM = 2 +NV_CTRL_FRAMELOCK_VIDEO_MODE_HDTV = 3 + +# +# During FRAMELOCK bring-up, the above values were redefined to +# these: +# + +NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_AUTO = 0 +NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_BI_LEVEL = 2 +NV_CTRL_FRAMELOCK_VIDEO_MODE_COMPOSITE_TRI_LEVEL = 3 + +# +# NV_CTRL_FRAMELOCK_SYNC_RATE - this is the refresh rate that the +# frame lock board is sending to the GPU, in milliHz. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_FRAMELOCK_SYNC_RATE = 35 # R--F + +############################################################################ + +# +# NV_CTRL_FORCE_GENERIC_CPU - not supported +# + +NV_CTRL_FORCE_GENERIC_CPU = 37 # not supported +NV_CTRL_FORCE_GENERIC_CPU_DISABLE = 0 # not supported +NV_CTRL_FORCE_GENERIC_CPU_ENABLE = 1 # not supported + +# +# NV_CTRL_OPENGL_AA_LINE_GAMMA - for OpenGL clients, allow +# Gamma-corrected antialiased lines to consider variances in the +# color display capabilities of output devices when rendering smooth +# lines. Only available on recent Quadro GPUs. This setting is only +# applied to OpenGL clients that are started after this setting is +# applied. +# + +NV_CTRL_OPENGL_AA_LINE_GAMMA = 38 # RW-X +NV_CTRL_OPENGL_AA_LINE_GAMMA_DISABLE = 0 +NV_CTRL_OPENGL_AA_LINE_GAMMA_ENABLE = 1 + +# +# NV_CTRL_FRAMELOCK_TIMING - this is TRUE when the gpu is both receiving +# and locked to an input timing signal. Timing information may come from +# the following places: Another frame lock device that is set to master, +# the house sync signal, or the GPU's internal timing from a display +# device. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_FRAMELOCK_TIMING = 39 # R--G +NV_CTRL_FRAMELOCK_TIMING_FALSE = 0 +NV_CTRL_FRAMELOCK_TIMING_TRUE = 1 + +# +# NV_CTRL_FLIPPING_ALLOWED - when TRUE, OpenGL will swap by flipping +# when possible; when FALSE, OpenGL will always swap by blitting. +# + +NV_CTRL_FLIPPING_ALLOWED = 40 # RW-X +NV_CTRL_FLIPPING_ALLOWED_FALSE = 0 +NV_CTRL_FLIPPING_ALLOWED_TRUE = 1 + +# +# NV_CTRL_ARCHITECTURE - returns the architecture on which the X server is +# running. +# + +NV_CTRL_ARCHITECTURE = 41 # R-- +NV_CTRL_ARCHITECTURE_X86 = 0 +NV_CTRL_ARCHITECTURE_X86_64 = 1 +NV_CTRL_ARCHITECTURE_IA64 = 2 +NV_CTRL_ARCHITECTURE_ARM = 3 +NV_CTRL_ARCHITECTURE_AARCH64 = 4 +NV_CTRL_ARCHITECTURE_PPC64LE = 5 + +# +# NV_CTRL_TEXTURE_CLAMPING - texture clamping mode in OpenGL. By +# default, _SPEC is used, which forces OpenGL texture clamping to +# conform with the OpenGL specification. _EDGE forces NVIDIA's +# OpenGL implementation to remap GL_CLAMP to GL_CLAMP_TO_EDGE, +# which is not strictly conformant, but some applications rely on +# the non-conformant behavior. +# + +NV_CTRL_TEXTURE_CLAMPING = 42 # RW-X +NV_CTRL_TEXTURE_CLAMPING_EDGE = 0 +NV_CTRL_TEXTURE_CLAMPING_SPEC = 1 + +# +# The NV_CTRL_CURSOR_SHADOW - not supported +# +# use an ARGB cursor instead. +# + +NV_CTRL_CURSOR_SHADOW = 43 # not supported +NV_CTRL_CURSOR_SHADOW_DISABLE = 0 # not supported +NV_CTRL_CURSOR_SHADOW_ENABLE = 1 # not supported + +NV_CTRL_CURSOR_SHADOW_ALPHA = 44 # not supported +NV_CTRL_CURSOR_SHADOW_RED = 45 # not supported +NV_CTRL_CURSOR_SHADOW_GREEN = 46 # not supported +NV_CTRL_CURSOR_SHADOW_BLUE = 47 # not supported + +NV_CTRL_CURSOR_SHADOW_X_OFFSET = 48 # not supported +NV_CTRL_CURSOR_SHADOW_Y_OFFSET = 49 # not supported + +# +# When Application Control for FSAA is enabled, then what the +# application requests is used, and NV_CTRL_FSAA_MODE is ignored. If +# this is disabled, then any application setting is overridden with +# NV_CTRL_FSAA_MODE +# + +NV_CTRL_FSAA_APPLICATION_CONTROLLED = 50 # RW-X +NV_CTRL_FSAA_APPLICATION_CONTROLLED_ENABLED = 1 +NV_CTRL_FSAA_APPLICATION_CONTROLLED_DISABLED = 0 + +# +# When Application Control for LogAniso is enabled, then what the +# application requests is used, and NV_CTRL_LOG_ANISO is ignored. If +# this is disabled, then any application setting is overridden with +# NV_CTRL_LOG_ANISO +# + +NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED = 51 # RW-X +NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_ENABLED = 1 +NV_CTRL_LOG_ANISO_APPLICATION_CONTROLLED_DISABLED = 0 + +# +# IMAGE_SHARPENING adjusts the sharpness of the display's image +# quality by amplifying high frequency content. Valid values will +# normally be in the range [0,32). Only available on GeForceFX or +# newer. +# + +NV_CTRL_IMAGE_SHARPENING = 52 # RWDG + +# +# NV_CTRL_TV_OVERSCAN - not supported +# + +NV_CTRL_TV_OVERSCAN = 53 # not supported + +# +# NV_CTRL_TV_FLICKER_FILTER - not supported +# + +NV_CTRL_TV_FLICKER_FILTER = 54 # not supported + +# +# NV_CTRL_TV_BRIGHTNESS - not supported +# + +NV_CTRL_TV_BRIGHTNESS = 55 # not supported + +# +# NV_CTRL_TV_HUE - not supported +# + +NV_CTRL_TV_HUE = 56 # not supported + +# +# NV_CTRL_TV_CONTRAST - not suppoerted +# + +NV_CTRL_TV_CONTRAST = 57 # not supported + +# +# NV_CTRL_TV_SATURATION - not supported +# + +NV_CTRL_TV_SATURATION = 58 # not supported + +# +# NV_CTRL_TV_RESET_SETTINGS - not supported +# + +NV_CTRL_TV_RESET_SETTINGS = 59 # not supported + +# +# NV_CTRL_GPU_CORE_TEMPERATURE reports the current core temperature +# of the GPU driving the X screen. +# + +NV_CTRL_GPU_CORE_TEMPERATURE = 60 # R--G + +# +# NV_CTRL_GPU_CORE_THRESHOLD reports the current GPU core slowdown +# threshold temperature, NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD and +# NV_CTRL_GPU_MAX_CORE_THRESHOLD report the default and MAX core +# slowdown threshold temperatures. +# +# NV_CTRL_GPU_CORE_THRESHOLD reflects the temperature at which the +# GPU is throttled to prevent overheating. +# + +NV_CTRL_GPU_CORE_THRESHOLD = 61 # R--G +NV_CTRL_GPU_DEFAULT_CORE_THRESHOLD = 62 # R--G +NV_CTRL_GPU_MAX_CORE_THRESHOLD = 63 # R--G + +# +# NV_CTRL_AMBIENT_TEMPERATURE reports the current temperature in the +# immediate neighbourhood of the GPU driving the X screen. +# + +NV_CTRL_AMBIENT_TEMPERATURE = 64 # R--G + +# +# NV_CTRL_PBUFFER_SCANOUT_SUPPORTED - returns whether this X screen +# supports scanout of FP pbuffers; +# +# if this screen does not support PBUFFER_SCANOUT, then all other +# PBUFFER_SCANOUT attributes are unavailable. +# +# PBUFFER_SCANOUT is supported if and only if: +# - Twinview is configured with clone mode. The secondary screen is used to +# scanout the pbuffer. +# - The desktop is running in with 16 bits per pixel. +# +NV_CTRL_PBUFFER_SCANOUT_SUPPORTED = 65 # not supported +NV_CTRL_PBUFFER_SCANOUT_FALSE = 0 +NV_CTRL_PBUFFER_SCANOUT_TRUE = 1 + +# +# NV_CTRL_PBUFFER_SCANOUT_XID indicates the XID of the pbuffer used for +# scanout. +# +NV_CTRL_PBUFFER_SCANOUT_XID = 66 # not supported + +############################################################################ +# +# The NV_CTRL_GVO_* integer attributes are used to configure GVO +# (Graphics to Video Out). This functionality is available, for +# example, on the Quadro SDI Output card. +# +# The following is a typical usage pattern for the GVO attributes: +# +# - query NV_CTRL_GVO_SUPPORTED to determine if the X screen supports GV0. +# +# - specify NV_CTRL_GVO_SYNC_MODE (one of FREE_RUNNING, GENLOCK, or +# FRAMELOCK); if you specify GENLOCK or FRAMELOCK, you should also +# specify NV_CTRL_GVO_SYNC_SOURCE. +# +# - Use NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED and +# NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED to detect what input syncs are +# present. +# +# (If no analog sync is detected but it is known that a valid +# bi-level or tri-level sync is connected set +# NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE appropriately and +# retest with NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED). +# +# - if syncing to input sync, query the +# NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT attribute; note that Input video +# format can only be queried after SYNC_SOURCE is specified. +# +# - specify the NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT +# +# - specify the NV_CTRL_GVO_DATA_FORMAT +# +# - specify any custom Color Space Conversion (CSC) matrix, offset, +# and scale with XNVCTRLSetGvoColorConversion(). +# +# - if using the GLX_NV_video_out extension to display one or more +# pbuffers, call glXGetVideoDeviceNV() to lock the GVO output for use +# by the GLX client; then bind the pbuffer(s) to the GVO output with +# glXBindVideoImageNV() and send pbuffers to the GVO output with +# glXSendPbufferToVideoNV(); see the GLX_NV_video_out spec for more +# details. +# +# - if using the GLX_NV_present_video extension, call +# glXBindVideoDeviceNV() to bind the GVO video device to current +# OpenGL context. +# +# Note that setting most GVO attributes only causes the value to be +# cached in the X server. The values will be flushed to the hardware +# either when the next MetaMode is set that uses the GVO display +# device, or when a GLX pbuffer is bound to the GVO output (with +# glXBindVideoImageNV()). +# +# Note that GLX_NV_video_out/GLX_NV_present_video and X screen use +# are mutually exclusive. If a MetaMode is currently using the GVO +# device, then glXGetVideoDeviceNV and glXBindVideoImageNV() will +# fail. Similarly, if a GLX client has locked the GVO output (via +# glXGetVideoDeviceNV or glXBindVideoImageNV), then setting a +# MetaMode that uses the GVO device will fail. The +# NV_CTRL_GVO_GLX_LOCKED event will be sent when a GLX client locks +# the GVO output. +# +# + + +# +# NV_CTRL_GVO_SUPPORTED - returns whether this X screen supports GVO; +# if this screen does not support GVO output, then all other GVO +# attributes are unavailable. +# + +NV_CTRL_GVO_SUPPORTED = 67 # R-- +NV_CTRL_GVO_SUPPORTED_FALSE = 0 +NV_CTRL_GVO_SUPPORTED_TRUE = 1 + +# +# NV_CTRL_GVO_SYNC_MODE - selects the GVO sync mode; possible values +# are: +# +# FREE_RUNNING - GVO does not sync to any external signal +# +# GENLOCK - the GVO output is genlocked to an incoming sync signal; +# genlocking locks at hsync. This requires that the output video +# format exactly match the incoming sync video format. +# +# FRAMELOCK - the GVO output is frame locked to an incoming sync +# signal; frame locking locks at vsync. This requires that the output +# video format have the same refresh rate as the incoming sync video +# format. +# + +NV_CTRL_GVO_SYNC_MODE = 68 # RW- +NV_CTRL_GVO_SYNC_MODE_FREE_RUNNING = 0 +NV_CTRL_GVO_SYNC_MODE_GENLOCK = 1 +NV_CTRL_GVO_SYNC_MODE_FRAMELOCK = 2 + +# +# NV_CTRL_GVO_SYNC_SOURCE - if NV_CTRL_GVO_SYNC_MODE is set to either +# GENLOCK or FRAMELOCK, this controls which sync source is used as +# the incoming sync signal (either Composite or SDI). If +# NV_CTRL_GVO_SYNC_MODE is FREE_RUNNING, this attribute has no +# effect. +# + +NV_CTRL_GVO_SYNC_SOURCE = 69 # RW- +NV_CTRL_GVO_SYNC_SOURCE_COMPOSITE = 0 +NV_CTRL_GVO_SYNC_SOURCE_SDI = 1 + +# +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT - specifies the desired output video +# format for GVO devices or the desired input video format for GVI devices. +# +# Note that for GVO, the valid video formats may vary depending on +# the NV_CTRL_GVO_SYNC_MODE and the incoming sync video format. See +# the definition of NV_CTRL_GVO_SYNC_MODE. +# +# Note that when querying the ValidValues for this data type, the +# values are reported as bits within a bitmask +# (ATTRIBUTE_TYPE_INT_BITS); unfortunately, there are more valid +# value bits than will fit in a single 32-bit value. To solve this, +# query the ValidValues for NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT to +# check which of the first 31 VIDEO_FORMATS are valid, query the +# ValidValues for NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 to check which +# of the 32-63 VIDEO_FORMATS are valid, and query the ValidValues of +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 to check which of the 64-95 +# VIDEO_FORMATS are valid. +# +# Note: Setting this attribute on a GVI device may also result in the +# following NV-CONTROL attributes being reset on that device (to +# ensure the configuration remains valid): +# NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT +# NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING +# + +NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT = 70 # RW--I + +NV_CTRL_GVIO_VIDEO_FORMAT_NONE = 0 +NV_CTRL_GVIO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC = 1 +NV_CTRL_GVIO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL = 2 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_59_94_SMPTE296 = 3 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296 = 4 +NV_CTRL_GVIO_VIDEO_FORMAT_1035I_59_94_SMPTE260 = 5 +NV_CTRL_GVIO_VIDEO_FORMAT_1035I_60_00_SMPTE260 = 6 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_SMPTE295 = 7 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_SMPTE274 = 8 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_59_94_SMPTE274 = 9 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_60_00_SMPTE274 = 10 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_23_976_SMPTE274 = 11 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_24_00_SMPTE274 = 12 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_25_00_SMPTE274 = 13 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_29_97_SMPTE274 = 14 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_30_00_SMPTE274 = 15 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_50_00_SMPTE296 = 16 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_48_00_SMPTE274 = 17 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_47_96_SMPTE274 = 18 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_30_00_SMPTE296 = 19 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_29_97_SMPTE296 = 20 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_25_00_SMPTE296 = 21 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_24_00_SMPTE296 = 22 +NV_CTRL_GVIO_VIDEO_FORMAT_720P_23_98_SMPTE296 = 23 +NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274 = 24 +NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274 = 25 +NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274 = 26 +NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274 = 27 +NV_CTRL_GVIO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274 = 28 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_30_00_SMPTE372 = 29 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_29_97_SMPTE372 = 30 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_60_00_SMPTE372 = 31 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_59_94_SMPTE372 = 32 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_25_00_SMPTE372 = 33 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_50_00_SMPTE372 = 34 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_24_00_SMPTE372 = 35 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_23_98_SMPTE372 = 36 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_48_00_SMPTE372 = 37 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_47_96_SMPTE372 = 38 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_50_00_3G_LEVEL_A_SMPTE274 = 39 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_59_94_3G_LEVEL_A_SMPTE274 = 40 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_60_00_3G_LEVEL_A_SMPTE274 = 41 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_60_00_3G_LEVEL_B_SMPTE274 = 42 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_60_00_3G_LEVEL_B_SMPTE274 = 43 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_60_00_3G_LEVEL_B_SMPTE372 = 44 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_50_00_3G_LEVEL_B_SMPTE274 = 45 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_50_00_3G_LEVEL_B_SMPTE274 = 46 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_50_00_3G_LEVEL_B_SMPTE372 = 47 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_30_00_3G_LEVEL_B_SMPTE274 = 48 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_30_00_3G_LEVEL_B_SMPTE372 = 49 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_25_00_3G_LEVEL_B_SMPTE274 = 50 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_25_00_3G_LEVEL_B_SMPTE372 = 51 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_24_00_3G_LEVEL_B_SMPTE274 = 52 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_24_00_3G_LEVEL_B_SMPTE372 = 53 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_48_00_3G_LEVEL_B_SMPTE274 = 54 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_48_00_3G_LEVEL_B_SMPTE372 = 55 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_59_94_3G_LEVEL_B_SMPTE274 = 56 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_59_94_3G_LEVEL_B_SMPTE274 = 57 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_59_94_3G_LEVEL_B_SMPTE372 = 58 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_29_97_3G_LEVEL_B_SMPTE274 = 59 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_29_97_3G_LEVEL_B_SMPTE372 = 60 +NV_CTRL_GVIO_VIDEO_FORMAT_1080P_23_98_3G_LEVEL_B_SMPTE274 = 61 +NV_CTRL_GVIO_VIDEO_FORMAT_2048P_23_98_3G_LEVEL_B_SMPTE372 = 62 +NV_CTRL_GVIO_VIDEO_FORMAT_1080I_47_96_3G_LEVEL_B_SMPTE274 = 63 +NV_CTRL_GVIO_VIDEO_FORMAT_2048I_47_96_3G_LEVEL_B_SMPTE372 = 64 + +# +# The following have been renamed; NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT and the +# corresponding NV_CTRL_GVIO_* formats should be used instead. +# +NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT = 70 # renamed + +NV_CTRL_GVO_VIDEO_FORMAT_NONE = 0 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC = 1 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_576I_50_00_SMPTE259_PAL = 2 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_59_94_SMPTE296 = 3 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_60_00_SMPTE296 = 4 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1035I_59_94_SMPTE260 = 5 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1035I_60_00_SMPTE260 = 6 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE295 = 7 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_50_00_SMPTE274 = 8 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_59_94_SMPTE274 = 9 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_60_00_SMPTE274 = 10 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080P_23_976_SMPTE274 = 11 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080P_24_00_SMPTE274 = 12 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080P_25_00_SMPTE274 = 13 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080P_29_97_SMPTE274 = 14 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080P_30_00_SMPTE274 = 15 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_50_00_SMPTE296 = 16 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_48_00_SMPTE274 = 17 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080I_47_96_SMPTE274 = 18 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_30_00_SMPTE296 = 19 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_29_97_SMPTE296 = 20 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_25_00_SMPTE296 = 21 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_24_00_SMPTE296 = 22 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_720P_23_98_SMPTE296 = 23 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_25_00_SMPTE274 = 24 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_29_97_SMPTE274 = 25 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_30_00_SMPTE274 = 26 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_24_00_SMPTE274 = 27 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_1080PSF_23_98_SMPTE274 = 28 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048P_30_00_SMPTE372 = 29 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048P_29_97_SMPTE372 = 30 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048I_60_00_SMPTE372 = 31 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048I_59_94_SMPTE372 = 32 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048P_25_00_SMPTE372 = 33 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048I_50_00_SMPTE372 = 34 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048P_24_00_SMPTE372 = 35 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048P_23_98_SMPTE372 = 36 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048I_48_00_SMPTE372 = 37 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_2048I_47_96_SMPTE372 = 38 # renamed + +# +# NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT - indicates the input video format +# detected for GVO or GVI devices; the possible values are the +# NV_CTRL_GVIO_VIDEO_FORMAT constants. +# +# For GVI devices, the jack number should be specified in the lower +# 16 bits of the "display_mask" parameter, while the channel number should be +# specified in the upper 16 bits. +# + +NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT = 71 # R--I + +# +# NV_CTRL_GVO_INPUT_VIDEO_FORMAT - renamed +# +# NV_CTRL_GVIO_DETECTED_VIDEO_FORMAT should be used instead. +# + +NV_CTRL_GVO_INPUT_VIDEO_FORMAT = 71 # renamed + +# +# NV_CTRL_GVO_DATA_FORMAT - This controls how the data in the source +# (either the X screen or the GLX pbuffer) is interpretted and +# displayed. +# +# Note: some of the below DATA_FORMATS have been renamed. For +# example, R8G8B8_TO_RGB444 has been renamed to X8X8X8_444_PASSTHRU. +# This is to more accurately reflect DATA_FORMATS where the +# per-channel data could be either RGB or YCrCb -- the point is that +# the driver and GVO hardware do not perform any implicit color space +# conversion on the data; it is passed through to the SDI out. +# + +NV_CTRL_GVO_DATA_FORMAT = 72 # RW- +NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB444 = 0 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_YCRCBA4444 = 1 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_YCRCBZ4444 = 2 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_YCRCB422 = 3 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_YCRCBA4224 = 4 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_YCRCBZ4224 = 5 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8_TO_RGB444 = 6 # renamed +NV_CTRL_GVO_DATA_FORMAT_X8X8X8_444_PASSTHRU = 6 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8A8_TO_RGBA4444 = 7 # renamed +NV_CTRL_GVO_DATA_FORMAT_X8X8X8A8_4444_PASSTHRU = 7 +NV_CTRL_GVO_DATA_FORMAT_R8G8B8Z10_TO_RGBZ4444 = 8 # renamed +NV_CTRL_GVO_DATA_FORMAT_X8X8X8Z8_4444_PASSTHRU = 8 +NV_CTRL_GVO_DATA_FORMAT_Y10CR10CB10_TO_YCRCB444 = 9 # renamed +NV_CTRL_GVO_DATA_FORMAT_X10X10X10_444_PASSTHRU = 9 +NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8_TO_YCRCB444 = 10 # renamed +NV_CTRL_GVO_DATA_FORMAT_X10X8X8_444_PASSTHRU = 10 +NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8A10_TO_YCRCBA4444 = 11 # renamed +NV_CTRL_GVO_DATA_FORMAT_X10X8X8A10_4444_PASSTHRU = 11 +NV_CTRL_GVO_DATA_FORMAT_Y10CR8CB8Z10_TO_YCRCBZ4444 = 12 # renamed +NV_CTRL_GVO_DATA_FORMAT_X10X8X8Z10_4444_PASSTHRU = 12 +NV_CTRL_GVO_DATA_FORMAT_DUAL_R8G8B8_TO_DUAL_YCRCB422 = 13 +NV_CTRL_GVO_DATA_FORMAT_DUAL_Y8CR8CB8_TO_DUAL_YCRCB422 = 14 # renamed +NV_CTRL_GVO_DATA_FORMAT_DUAL_X8X8X8_TO_DUAL_422_PASSTHRU = 14 +NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB422 = 15 +NV_CTRL_GVO_DATA_FORMAT_R10G10B10_TO_YCRCB444 = 16 +NV_CTRL_GVO_DATA_FORMAT_Y12CR12CB12_TO_YCRCB444 = 17 # renamed +NV_CTRL_GVO_DATA_FORMAT_X12X12X12_444_PASSTHRU = 17 +NV_CTRL_GVO_DATA_FORMAT_R12G12B12_TO_YCRCB444 = 18 +NV_CTRL_GVO_DATA_FORMAT_X8X8X8_422_PASSTHRU = 19 +NV_CTRL_GVO_DATA_FORMAT_X8X8X8A8_4224_PASSTHRU = 20 +NV_CTRL_GVO_DATA_FORMAT_X8X8X8Z8_4224_PASSTHRU = 21 +NV_CTRL_GVO_DATA_FORMAT_X10X10X10_422_PASSTHRU = 22 +NV_CTRL_GVO_DATA_FORMAT_X10X8X8_422_PASSTHRU = 23 +NV_CTRL_GVO_DATA_FORMAT_X10X8X8A10_4224_PASSTHRU = 24 +NV_CTRL_GVO_DATA_FORMAT_X10X8X8Z10_4224_PASSTHRU = 25 +NV_CTRL_GVO_DATA_FORMAT_X12X12X12_422_PASSTHRU = 26 +NV_CTRL_GVO_DATA_FORMAT_R12G12B12_TO_YCRCB422 = 27 + +# +# NV_CTRL_GVO_DISPLAY_X_SCREEN - not supported +# + +NV_CTRL_GVO_DISPLAY_X_SCREEN = 73 # not supported +NV_CTRL_GVO_DISPLAY_X_SCREEN_ENABLE = 1 # not supported +NV_CTRL_GVO_DISPLAY_X_SCREEN_DISABLE = 0 # not supported + +# +# NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED - indicates whether +# Composite Sync input is detected. +# + +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED = 74 # R-- +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED_FALSE = 0 +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECTED_TRUE = 1 + +# +# NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE - get/set the +# Composite Sync input detect mode. +# + +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE = 75 # RW- +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_AUTO = 0 +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_BI_LEVEL = 1 +NV_CTRL_GVO_COMPOSITE_SYNC_INPUT_DETECT_MODE_TRI_LEVEL = 2 + +# +# NV_CTRL_GVO_SYNC_INPUT_DETECTED - indicates whether SDI Sync input +# is detected, and what type. +# + +NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED = 76 # R-- +NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_NONE = 0 +NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_HD = 1 +NV_CTRL_GVO_SDI_SYNC_INPUT_DETECTED_SD = 2 + +# +# NV_CTRL_GVO_VIDEO_OUTPUTS - indicates which GVO video output +# connectors are currently outputing data. +# + +NV_CTRL_GVO_VIDEO_OUTPUTS = 77 # R-- +NV_CTRL_GVO_VIDEO_OUTPUTS_NONE = 0 +NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO1 = 1 +NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO2 = 2 +NV_CTRL_GVO_VIDEO_OUTPUTS_VIDEO_BOTH = 3 + +# +# NV_CTRL_GVO_FIRMWARE_VERSION - deprecated +# +# NV_CTRL_STRING_GVIO_FIRMWARE_VERSION should be used instead. +# + +NV_CTRL_GVO_FIRMWARE_VERSION = 78 # deprecated + +# +# NV_CTRL_GVO_SYNC_DELAY_PIXELS - controls the delay between the +# input sync and the output sync in numbers of pixels from hsync; +# this is a 12 bit value. +# +# If the NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW bit is set, +# then setting this value will set an advance instead of a delay. +# + +NV_CTRL_GVO_SYNC_DELAY_PIXELS = 79 # RW- + +# +# NV_CTRL_GVO_SYNC_DELAY_LINES - controls the delay between the input +# sync and the output sync in numbers of lines from vsync; this is a +# 12 bit value. +# +# If the NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW bit is set, +# then setting this value will set an advance instead of a delay. +# + +NV_CTRL_GVO_SYNC_DELAY_LINES = 80 # RW- + +# +# NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE - must be set for a period +# of about 2 seconds for the new InputVideoFormat to be properly +# locked to. In nvidia-settings, we do a reacquire whenever genlock +# or frame lock mode is entered into, when the user clicks the +# "detect" button. This value can be written, but always reads back +# _FALSE. +# + +NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE = 81 # -W- +NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_FALSE = 0 +NV_CTRL_GVO_INPUT_VIDEO_FORMAT_REACQUIRE_TRUE = 1 + +# +# NV_CTRL_GVO_GLX_LOCKED - deprecated +# +# NV_CTRL_GVO_LOCK_OWNER should be used instead. +# + +NV_CTRL_GVO_GLX_LOCKED = 82 # deprecated +NV_CTRL_GVO_GLX_LOCKED_FALSE = 0 # deprecated +NV_CTRL_GVO_GLX_LOCKED_TRUE = 1 # deprecated + +# +# NV_CTRL_GVIO_VIDEO_FORMAT_{WIDTH,HEIGHT,REFRESH_RATE} - query the +# width, height, and refresh rate for the specified +# NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be queried with +# existing interfaces, XNVCTRLQueryAttribute() should be used, and +# the video format specified in the display_mask field; eg: +# +# XNVCTRLQueryAttribute (dpy, +# screen, +# NV_CTRL_GVIO_VIDEO_FORMAT_487I_59_94_SMPTE259_NTSC, +# NV_CTRL_GVIO_VIDEO_FORMAT_WIDTH, +# &value); +# +# Note that Refresh Rate is in milliHertz values +# + +NV_CTRL_GVIO_VIDEO_FORMAT_WIDTH = 83 # R--I +NV_CTRL_GVIO_VIDEO_FORMAT_HEIGHT = 84 # R--I +NV_CTRL_GVIO_VIDEO_FORMAT_REFRESH_RATE = 85 # R--I + +# The following have been renamed; use the NV_CTRL_GVIO_* versions, instead +NV_CTRL_GVO_VIDEO_FORMAT_WIDTH = 83 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_HEIGHT = 84 # renamed +NV_CTRL_GVO_VIDEO_FORMAT_REFRESH_RATE = 85 # renamed + +# +# NV_CTRL_GVO_X_SCREEN_PAN_[XY] - not supported +# + +NV_CTRL_GVO_X_SCREEN_PAN_X = 86 # not supported +NV_CTRL_GVO_X_SCREEN_PAN_Y = 87 # not supported + +# +# NV_CTRL_GPU_OVERCLOCKING_STATE - not supported +# + +NV_CTRL_GPU_OVERCLOCKING_STATE = 88 # not supported +NV_CTRL_GPU_OVERCLOCKING_STATE_NONE = 0 # not supported +NV_CTRL_GPU_OVERCLOCKING_STATE_MANUAL = 1 # not supported + +# +# NV_CTRL_GPU_{2,3}D_CLOCK_FREQS - not supported +# + +NV_CTRL_GPU_2D_CLOCK_FREQS = 89 # not supported +NV_CTRL_GPU_3D_CLOCK_FREQS = 90 # not supported + +# +# NV_CTRL_GPU_DEFAULT_{2,3}D_CLOCK_FREQS - not supported +# + +NV_CTRL_GPU_DEFAULT_2D_CLOCK_FREQS = 91 # not supported +NV_CTRL_GPU_DEFAULT_3D_CLOCK_FREQS = 92 # not supported + +# +# NV_CTRL_GPU_CURRENT_CLOCK_FREQS - query the current GPU and memory +# clocks of the graphics device driving the X screen. +# +# NV_CTRL_GPU_CURRENT_CLOCK_FREQS is a "packed" integer attribute; +# the GPU clock is stored in the upper 16 bits of the integer, and +# the memory clock is stored in the lower 16 bits of the integer. +# All clock values are in MHz. All clock values are in MHz. +# + +NV_CTRL_GPU_CURRENT_CLOCK_FREQS = 93 # R--G + +# +# NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS - not supported +# + +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS = 94 # not supported +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_INVALID = 0 # not supported + +# +# NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION - not supported +# + +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION = 95 # not supported +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_START = 0 # not supported +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_CANCEL = 1 # not supported + +# +# NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE - not supported +# + +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE = 96 # not supported +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_IDLE = 0 # not supported +NV_CTRL_GPU_OPTIMAL_CLOCK_FREQS_DETECTION_STATE_BUSY = 1 # not supported + +# +# NV_CTRL_FLATPANEL_CHIP_LOCATION - for the specified display device, +# report whether the flat panel is driven by the on-chip controller, +# or a separate controller chip elsewhere on the graphics board. +# This attribute is only available for flat panels. +# + +NV_CTRL_FLATPANEL_CHIP_LOCATION = 215 # R-DG +NV_CTRL_FLATPANEL_CHIP_LOCATION_INTERNAL = 0 +NV_CTRL_FLATPANEL_CHIP_LOCATION_EXTERNAL = 1 + +# +# NV_CTRL_FLATPANEL_LINK - report the number of links for a DVI connection, or +# the main link's active lane count for DisplayPort. +# This attribute is only available for flat panels. +# + +NV_CTRL_FLATPANEL_LINK = 216 # R-DG +NV_CTRL_FLATPANEL_LINK_SINGLE = 0 +NV_CTRL_FLATPANEL_LINK_DUAL = 1 +NV_CTRL_FLATPANEL_LINK_QUAD = 3 + +# +# NV_CTRL_FLATPANEL_SIGNAL - for the specified display device, report +# whether the flat panel is driven by an LVDS, TMDS, or DisplayPort signal. +# This attribute is only available for flat panels. +# + +NV_CTRL_FLATPANEL_SIGNAL = 217 # R-DG +NV_CTRL_FLATPANEL_SIGNAL_LVDS = 0 +NV_CTRL_FLATPANEL_SIGNAL_TMDS = 1 +NV_CTRL_FLATPANEL_SIGNAL_DISPLAYPORT = 2 + +# +# NV_CTRL_USE_HOUSE_SYNC - when INPUT, the server (master) frame lock +# device will propagate the incoming house sync signal as the outgoing +# frame lock sync signal. If the frame lock device cannot detect a +# frame lock sync signal, it will default to using the internal timings +# from the GPU connected to the primary connector. +# +# When set to OUTPUT, the server (master) frame lock device will +# generate a house sync signal from its internal timing and output +# this signal over the BNC connector on the frame lock device. This +# is only allowed on a Quadro Sync II device. If an incoming house +# sync signal is present on the BNC connector, this setting will +# have no effect. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_USE_HOUSE_SYNC = 218 # RW-F +NV_CTRL_USE_HOUSE_SYNC_DISABLED = 0 # aliases with FALSE +NV_CTRL_USE_HOUSE_SYNC_INPUT = 1 # aliases with TRUE +NV_CTRL_USE_HOUSE_SYNC_OUTPUT = 2 +NV_CTRL_USE_HOUSE_SYNC_FALSE = 0 +NV_CTRL_USE_HOUSE_SYNC_TRUE = 1 + +# +# NV_CTRL_EDID_AVAILABLE - report if an EDID is available for the +# specified display device. +# +# This attribute may also be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# + +NV_CTRL_EDID_AVAILABLE = 219 # R-DG +NV_CTRL_EDID_AVAILABLE_FALSE = 0 +NV_CTRL_EDID_AVAILABLE_TRUE = 1 + +# +# NV_CTRL_FORCE_STEREO - when TRUE, OpenGL will force stereo flipping +# even when no stereo drawables are visible (if the device is configured +# to support it, see the "Stereo" X config option). +# When false, fall back to the default behavior of only flipping when a +# stereo drawable is visible. +# + +NV_CTRL_FORCE_STEREO = 220 # RW- +NV_CTRL_FORCE_STEREO_FALSE = 0 +NV_CTRL_FORCE_STEREO_TRUE = 1 + +# +# NV_CTRL_IMAGE_SETTINGS - the image quality setting for OpenGL clients. +# +# This setting is only applied to OpenGL clients that are started +# after this setting is applied. +# + +NV_CTRL_IMAGE_SETTINGS = 221 # RW-X +NV_CTRL_IMAGE_SETTINGS_HIGH_QUALITY = 0 +NV_CTRL_IMAGE_SETTINGS_QUALITY = 1 +NV_CTRL_IMAGE_SETTINGS_PERFORMANCE = 2 +NV_CTRL_IMAGE_SETTINGS_HIGH_PERFORMANCE = 3 + +# +# NV_CTRL_XINERAMA - return whether xinerama is enabled +# + +NV_CTRL_XINERAMA = 222 # R--G +NV_CTRL_XINERAMA_OFF = 0 +NV_CTRL_XINERAMA_ON = 1 + +# +# NV_CTRL_XINERAMA_STEREO - when TRUE, OpenGL will allow stereo flipping +# on multiple X screens configured with Xinerama. +# When FALSE, flipping is allowed only on one X screen at a time. +# + +NV_CTRL_XINERAMA_STEREO = 223 # RW- +NV_CTRL_XINERAMA_STEREO_FALSE = 0 +NV_CTRL_XINERAMA_STEREO_TRUE = 1 + +# +# NV_CTRL_BUS_RATE - if the bus type of the specified device is AGP, then +# NV_CTRL_BUS_RATE returns the configured AGP transfer rate. If the bus type +# is PCI Express, then this attribute returns the maximum link width. +# When this attribute is queried on an X screen target, the bus rate of the +# GPU driving the X screen is returned. +# + +NV_CTRL_BUS_RATE = 224 # R--GI + +# +# NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH - returns the maximum +# PCIe link width, in number of lanes. +# +NV_CTRL_GPU_PCIE_MAX_LINK_WIDTH = NV_CTRL_BUS_RATE +# +# NV_CTRL_SHOW_SLI_VISUAL_INDICATOR - when TRUE, OpenGL will draw information +# about the current SLI mode. +# + +NV_CTRL_SHOW_SLI_VISUAL_INDICATOR = 225 # RW-X +NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_FALSE = 0 +NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_TRUE = 1 + +# +# NV_CTRL_SHOW_SLI_HUD - when TRUE, OpenGL will draw information about the +# current SLI mode. +# Renamed this attribute to NV_CTRL_SHOW_SLI_VISUAL_INDICATOR +# + +NV_CTRL_SHOW_SLI_HUD = NV_CTRL_SHOW_SLI_VISUAL_INDICATOR +NV_CTRL_SHOW_SLI_HUD_FALSE = NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_FALSE +NV_CTRL_SHOW_SLI_HUD_TRUE = NV_CTRL_SHOW_SLI_VISUAL_INDICATOR_TRUE + +# +# NV_CTRL_XV_SYNC_TO_DISPLAY - deprecated +# +# NV_CTRL_XV_SYNC_TO_DISPLAY_ID should be used instead. +# + +NV_CTRL_XV_SYNC_TO_DISPLAY = 226 # deprecated + +# +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 - this attribute is only +# intended to be used to query the ValidValues for +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for VIDEO_FORMAT values between +# 31 and 63. See NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for details. +# + +NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 = 227 # ---GI + +# +# NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 - renamed +# +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT2 should be used instead. +# +NV_CTRL_GVO_OUTPUT_VIDEO_FORMAT2 = 227 # renamed + +# +# NV_CTRL_GVO_OVERRIDE_HW_CSC - Override the SDI hardware's Color Space +# Conversion with the values controlled through +# XNVCTRLSetGvoColorConversion() and XNVCTRLGetGvoColorConversion(). If +# this attribute is FALSE, then the values specified through +# XNVCTRLSetGvoColorConversion() are ignored. +# + +NV_CTRL_GVO_OVERRIDE_HW_CSC = 228 # RW- +NV_CTRL_GVO_OVERRIDE_HW_CSC_FALSE = 0 +NV_CTRL_GVO_OVERRIDE_HW_CSC_TRUE = 1 + +# +# NV_CTRL_GVO_CAPABILITIES - this read-only attribute describes GVO +# capabilities that differ between NVIDIA SDI products. This value +# is a bitmask where each bit indicates whether that capability is +# available. +# +# APPLY_CSC_IMMEDIATELY - whether the CSC matrix, offset, and scale +# specified through XNVCTRLSetGvoColorConversion() will take affect +# immediately, or only after SDI output is disabled and enabled +# again. +# +# APPLY_CSC_TO_X_SCREEN - whether the CSC matrix, offset, and scale +# specified through XNVCTRLSetGvoColorConversion() will also apply +# to GVO output of an X screen, or only to OpenGL GVO output, as +# enabled through the GLX_NV_video_out extension. +# +# COMPOSITE_TERMINATION - whether the 75 ohm termination of the +# SDI composite input signal can be programmed through the +# NV_CTRL_GVO_COMPOSITE_TERMINATION attribute. +# +# SHARED_SYNC_BNC - whether the SDI device has a single BNC +# connector used for both (SDI & Composite) incoming signals. +# +# MULTIRATE_SYNC - whether the SDI device supports synchronization +# of input and output video modes that match in being odd or even +# modes (ie, AA.00 Hz modes can be synched to other BB.00 Hz modes and +# AA.XX Hz can match to BB.YY Hz where .XX and .YY are not .00) +# + +NV_CTRL_GVO_CAPABILITIES = 229 # R-- +NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_IMMEDIATELY = 0x00000001 +NV_CTRL_GVO_CAPABILITIES_APPLY_CSC_TO_X_SCREEN = 0x00000002 +NV_CTRL_GVO_CAPABILITIES_COMPOSITE_TERMINATION = 0x00000004 +NV_CTRL_GVO_CAPABILITIES_SHARED_SYNC_BNC = 0x00000008 +NV_CTRL_GVO_CAPABILITIES_MULTIRATE_SYNC = 0x00000010 +NV_CTRL_GVO_CAPABILITIES_ADVANCE_SYNC_SKEW = 0x00000020 + +# +# NV_CTRL_GVO_COMPOSITE_TERMINATION - enable or disable 75 ohm +# termination of the SDI composite input signal. +# + +NV_CTRL_GVO_COMPOSITE_TERMINATION = 230 # RW- +NV_CTRL_GVO_COMPOSITE_TERMINATION_ENABLE = 1 +NV_CTRL_GVO_COMPOSITE_TERMINATION_DISABLE = 0 + +# +# NV_CTRL_ASSOCIATED_DISPLAY_DEVICES - deprecated +# +# NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN should be used instead. +# + +NV_CTRL_ASSOCIATED_DISPLAY_DEVICES = 231 # deprecated + +# +# NV_CTRL_FRAMELOCK_SLAVES - deprecated +# +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG should be used instead. +# + +NV_CTRL_FRAMELOCK_SLAVES = 232 # deprecated + +# +# NV_CTRL_FRAMELOCK_MASTERABLE - deprecated +# +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG should be used instead. +# + +NV_CTRL_FRAMELOCK_MASTERABLE = 233 # deprecated + +# +# NV_CTRL_PROBE_DISPLAYS - re-probes the hardware to detect what +# display devices are connected to the GPU or GPU driving the +# specified X screen. The return value is deprecated and should not be used. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_PROBE_DISPLAYS = 234 # R--G + +# +# NV_CTRL_REFRESH_RATE - Returns the refresh rate of the specified +# display device in 100# Hz (ie. to get the refresh rate in Hz, divide +# the returned value by 100.) +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_REFRESH_RATE = 235 # R-DG + +# +# NV_CTRL_GVO_FLIP_QUEUE_SIZE - The Graphics to Video Out interface +# exposed through NV-CONTROL and the GLX_NV_video_out extension uses +# an internal flip queue when pbuffers are sent to the video device +# (via glXSendPbufferToVideoNV()). The NV_CTRL_GVO_FLIP_QUEUE_SIZE +# can be used to query and assign the flip queue size. This +# attribute is applied to GLX when glXGetVideoDeviceNV() is called by +# the application. +# + +NV_CTRL_GVO_FLIP_QUEUE_SIZE = 236 # RW- + +# +# NV_CTRL_CURRENT_SCANLINE - query the current scanline for the +# specified display device. +# + +NV_CTRL_CURRENT_SCANLINE = 237 # R-DG + +# +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT - Controls where X pixmaps are initially +# created. +# +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM causes pixmaps to stay in +# system memory. These pixmaps can't be accelerated by the NVIDIA driver; this +# will cause blank windows if used with an OpenGL compositing manager. +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM creates pixmaps in system memory +# initially, but allows them to migrate to video memory. +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM creates pixmaps in video memory +# when enough resources are available. +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT_RESERVED is currently reserved for future +# use. Behavior is undefined. +# NV_CTRL_INITIAL_PIXMAP_PLACEMENT_GPU_SYSMEM creates pixmaps in GPU accessible +# system memory when enough resources are available. +# + +NV_CTRL_INITIAL_PIXMAP_PLACEMENT = 238 # RW- +NV_CTRL_INITIAL_PIXMAP_PLACEMENT_FORCE_SYSMEM = 0 +NV_CTRL_INITIAL_PIXMAP_PLACEMENT_SYSMEM = 1 +NV_CTRL_INITIAL_PIXMAP_PLACEMENT_VIDMEM = 2 +NV_CTRL_INITIAL_PIXMAP_PLACEMENT_RESERVED = 3 +NV_CTRL_INITIAL_PIXMAP_PLACEMENT_GPU_SYSMEM = 4 + +# +# NV_CTRL_PCI_BUS - Returns the PCI bus number the specified device is using. +# + +NV_CTRL_PCI_BUS = 239 # R--GI + +# +# NV_CTRL_PCI_DEVICE - Returns the PCI device number the specified device is +# using. +# + +NV_CTRL_PCI_DEVICE = 240 # R--GI + +# +# NV_CTRL_PCI_FUNCTION - Returns the PCI function number the specified device +# is using. +# + +NV_CTRL_PCI_FUNCTION = 241 # R--GI + +# +# NV_CTRL_FRAMELOCK_FPGA_REVISION - Queries the FPGA revision of the +# Frame Lock device. +# +# This attribute must be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. +# + +NV_CTRL_FRAMELOCK_FPGA_REVISION = 242 # R--F + +# +# NV_CTRL_MAX_SCREEN_{WIDTH,HEIGHT} - the maximum allowable size, in +# pixels, of either the specified X screen (if the target_type of the +# query is an X screen), or any X screen on the specified GPU (if the +# target_type of the query is a GPU). +# + +NV_CTRL_MAX_SCREEN_WIDTH = 243 # R--G +NV_CTRL_MAX_SCREEN_HEIGHT = 244 # R--G + +# +# NV_CTRL_MAX_DISPLAYS - The maximum number of display devices that +# can be driven simultaneously on a GPU (e.g., that can be used in a +# MetaMode at once). Note that this does not indicate the maximum +# number of displays that are listed in NV_CTRL_BINARY_DATA_DISPLAYS_ON_GPU +# and NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU because more display +# devices can be connected than are actively in use. +# + +NV_CTRL_MAX_DISPLAYS = 245 # R--G + +# +# NV_CTRL_DYNAMIC_TWINVIEW - Returns whether or not the screen +# supports dynamic twinview. +# + +NV_CTRL_DYNAMIC_TWINVIEW = 246 # R-- + +# +# NV_CTRL_MULTIGPU_DISPLAY_OWNER - Returns the (NV-CONTROL) GPU ID of +# the GPU that has the display device(s) used for showing the X Screen. +# + +NV_CTRL_MULTIGPU_DISPLAY_OWNER = 247 # R-- + +# +# NV_CTRL_GPU_SCALING - not supported +# + +NV_CTRL_GPU_SCALING = 248 # not supported + +NV_CTRL_GPU_SCALING_TARGET_INVALID = 0 # not supported +NV_CTRL_GPU_SCALING_TARGET_FLATPANEL_BEST_FIT = 1 # not supported +NV_CTRL_GPU_SCALING_TARGET_FLATPANEL_NATIVE = 2 # not supported + +NV_CTRL_GPU_SCALING_METHOD_INVALID = 0 # not supported +NV_CTRL_GPU_SCALING_METHOD_STRETCHED = 1 # not supported +NV_CTRL_GPU_SCALING_METHOD_CENTERED = 2 # not supported +NV_CTRL_GPU_SCALING_METHOD_ASPECT_SCALED = 3 # not supported + +# +# NV_CTRL_FRONTEND_RESOLUTION - not supported +# + +NV_CTRL_FRONTEND_RESOLUTION = 249 # not supported + +# +# NV_CTRL_BACKEND_RESOLUTION - not supported +# + +NV_CTRL_BACKEND_RESOLUTION = 250 # not supported + +# +# NV_CTRL_FLATPANEL_NATIVE_RESOLUTION - not supported +# + +NV_CTRL_FLATPANEL_NATIVE_RESOLUTION = 251 # not supported + +# +# NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION - not supported +# + +NV_CTRL_FLATPANEL_BEST_FIT_RESOLUTION = 252 # not supported + +# +# NV_CTRL_GPU_SCALING_ACTIVE - not supported +# + +NV_CTRL_GPU_SCALING_ACTIVE = 253 # not supported + +# +# NV_CTRL_DFP_SCALING_ACTIVE - not supported +# + +NV_CTRL_DFP_SCALING_ACTIVE = 254 # not supported + +# +# NV_CTRL_FSAA_APPLICATION_ENHANCED - Controls how the NV_CTRL_FSAA_MODE +# is applied when NV_CTRL_FSAA_APPLICATION_CONTROLLED is set to +# NV_CTRL_APPLICATION_CONTROLLED_DISABLED. When +# NV_CTRL_FSAA_APPLICATION_ENHANCED is _DISABLED, OpenGL applications will +# be forced to use the FSAA mode specified by NV_CTRL_FSAA_MODE. when set +# to _ENABLED, only those applications that have selected a multisample +# FBConfig will be made to use the NV_CTRL_FSAA_MODE specified. +# +# This attribute is ignored when NV_CTRL_FSAA_APPLICATION_CONTROLLED is +# set to NV_CTRL_FSAA_APPLICATION_CONTROLLED_ENABLED. +# + +NV_CTRL_FSAA_APPLICATION_ENHANCED = 255 # RW-X +NV_CTRL_FSAA_APPLICATION_ENHANCED_ENABLED = 1 +NV_CTRL_FSAA_APPLICATION_ENHANCED_DISABLED = 0 + +# +# NV_CTRL_FRAMELOCK_SYNC_RATE_4 - This is the refresh rate that the +# frame lock board is sending to the GPU with 4 digits of precision. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK. +# + +NV_CTRL_FRAMELOCK_SYNC_RATE_4 = 256 # R--F + +# +# NV_CTRL_GVO_LOCK_OWNER - indicates that the GVO device is available +# or in use (by GLX or an X screen). +# +# The GVO device is locked by GLX when either glXGetVideoDeviceNV +# (part of GLX_NV_video_out) or glXBindVideoDeviceNV (part of +# GLX_NV_present_video) is called. All GVO output resources are +# locked until released by the GLX_NV_video_out/GLX_NV_present_video +# client. +# +# The GVO device is locked/unlocked by an X screen, when the GVO device is +# used in a MetaMode on an X screen. +# +# When the GVO device is locked, setting of the following GVO NV-CONTROL +# attributes will not happen immediately and will instead be cached. The +# GVO resource will need to be disabled/released and re-enabled/claimed for +# the values to be flushed. These attributes are: +# +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT +# NV_CTRL_GVO_DATA_FORMAT +# NV_CTRL_GVO_FLIP_QUEUE_SIZE +# + +NV_CTRL_GVO_LOCK_OWNER = 257 # R-- +NV_CTRL_GVO_LOCK_OWNER_NONE = 0 +NV_CTRL_GVO_LOCK_OWNER_GLX = 1 +NV_CTRL_GVO_LOCK_OWNER_CLONE = 2 # not supported +NV_CTRL_GVO_LOCK_OWNER_X_SCREEN = 3 + +# +# NV_CTRL_HWOVERLAY - when a workstation overlay is in use, reports +# whether the hardware overlay is used, or if the overlay is emulated. +# + +NV_CTRL_HWOVERLAY = 258 # R-- +NV_CTRL_HWOVERLAY_FALSE = 0 +NV_CTRL_HWOVERLAY_TRUE = 1 + +# +# NV_CTRL_NUM_GPU_ERRORS_RECOVERED - Returns the number of GPU errors +# occured. This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_NUM_GPU_ERRORS_RECOVERED = 259 # R--- + +# +# NV_CTRL_REFRESH_RATE_3 - Returns the refresh rate of the specified +# display device in 1000# Hz (ie. to get the refresh rate in Hz, divide +# the returned value by 1000.) +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_REFRESH_RATE_3 = 260 # R-DG + +# +# NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS - not supported +# + +NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS = 261 # not supported +NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS_OFF = 0 # not supported +NV_CTRL_ONDEMAND_VBLANK_INTERRUPTS_ON = 1 # not supported + +# +# NV_CTRL_GPU_POWER_SOURCE reports the type of power source +# of the GPU driving the X screen. +# + +NV_CTRL_GPU_POWER_SOURCE = 262 # R--G +NV_CTRL_GPU_POWER_SOURCE_AC = 0 +NV_CTRL_GPU_POWER_SOURCE_BATTERY = 1 + +# +# NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE - not supported +# + +NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE = 263 # not supported +NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE_DESKTOP = 0 # not supported +NV_CTRL_GPU_CURRENT_PERFORMANCE_MODE_MAXPERF = 1 # not supported + +# NV_CTRL_GLYPH_CACHE - Enables RENDER Glyph Caching to VRAM + +NV_CTRL_GLYPH_CACHE = 264 # RW- +NV_CTRL_GLYPH_CACHE_DISABLED = 0 +NV_CTRL_GLYPH_CACHE_ENABLED = 1 + +# +# NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL reports the current +# Performance level of the GPU driving the X screen. Each +# Performance level has associated NVClock and Mem Clock values. +# + +NV_CTRL_GPU_CURRENT_PERFORMANCE_LEVEL = 265 # R--G + +# +# NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE reports if Adaptive Clocking +# is Enabled on the GPU driving the X screen. +# + +NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE = 266 # R--G +NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE_DISABLED = 0 +NV_CTRL_GPU_ADAPTIVE_CLOCK_STATE_ENABLED = 1 + +# +# NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED - Returns whether or not the GVO output +# video is locked to the GPU. +# + +NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED = 267 # R--- +NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED_FALSE = 0 +NV_CTRL_GVO_OUTPUT_VIDEO_LOCKED_TRUE = 1 + +# +# NV_CTRL_GVO_SYNC_LOCK_STATUS - Returns whether or not the GVO device +# is locked to the input ref signal. If the sync mode is set to +# NV_CTRL_GVO_SYNC_MODE_GENLOCK, then this returns the genlock +# sync status, and if the sync mode is set to NV_CTRL_GVO_SYNC_MODE_FRAMELOCK, +# then this reports the frame lock status. +# + +NV_CTRL_GVO_SYNC_LOCK_STATUS = 268 # R--- +NV_CTRL_GVO_SYNC_LOCK_STATUS_UNLOCKED = 0 +NV_CTRL_GVO_SYNC_LOCK_STATUS_LOCKED = 1 + +# +# NV_CTRL_GVO_ANC_TIME_CODE_GENERATION - Allows SDI device to generate +# time codes in the ANC region of the SDI video output stream. +# + +NV_CTRL_GVO_ANC_TIME_CODE_GENERATION = 269 # RW-- +NV_CTRL_GVO_ANC_TIME_CODE_GENERATION_DISABLE = 0 +NV_CTRL_GVO_ANC_TIME_CODE_GENERATION_ENABLE = 1 + +# +# NV_CTRL_GVO_COMPOSITE - Enables/Disables SDI compositing. This attribute +# is only available when an SDI input source is detected and is in genlock +# mode. +# + +NV_CTRL_GVO_COMPOSITE = 270 # RW-- +NV_CTRL_GVO_COMPOSITE_DISABLE = 0 +NV_CTRL_GVO_COMPOSITE_ENABLE = 1 + +# +# NV_CTRL_GVO_COMPOSITE_ALPHA_KEY - When compositing is enabled, this +# enables/disables alpha blending. +# + +NV_CTRL_GVO_COMPOSITE_ALPHA_KEY = 271 # RW-- +NV_CTRL_GVO_COMPOSITE_ALPHA_KEY_DISABLE = 0 +NV_CTRL_GVO_COMPOSITE_ALPHA_KEY_ENABLE = 1 + +# +# NV_CTRL_GVO_COMPOSITE_LUMA_KEY_RANGE - Set the values of a luma +# channel range. This is a packed int that has the following format +# (in order of high-bits to low bits): +# +# Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) +# +# To query the current values, pass the range # throught the display_mask +# variable. +# + +NV_CTRL_GVO_COMPOSITE_LUMA_KEY_RANGE = 272 # RW-- + +# +# NV_CTRL_GVO_COMPOSITE_CR_KEY_RANGE - Set the values of a CR +# channel range. This is a packed int that has the following format +# (in order of high-bits to low bits): +# +# Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) +# +# To query the current values, pass the range # throught he display_mask +# variable. +# + +NV_CTRL_GVO_COMPOSITE_CR_KEY_RANGE = 273 # RW-- + +# +# NV_CTRL_GVO_COMPOSITE_CB_KEY_RANGE - Set the values of a CB +# channel range. This is a packed int that has the following format +# (in order of high-bits to low bits): +# +# Range # (11 bits), (Enabled 1 bit), min value (10 bits), max value (10 bits) +# +# To query the current values, pass the range # throught he display_mask +# variable. +# + +NV_CTRL_GVO_COMPOSITE_CB_KEY_RANGE = 274 # RW-- + +# +# NV_CTRL_GVO_COMPOSITE_NUM_KEY_RANGES - Returns the number of ranges +# available for each channel (Y/Luma, Cr, and Cb.) +# + +NV_CTRL_GVO_COMPOSITE_NUM_KEY_RANGES = 275 # R--- + +# +# NV_CTRL_SWITCH_TO_DISPLAYS - not supported +# + +NV_CTRL_SWITCH_TO_DISPLAYS = 276 # not supported + +# +# NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT - not supported +# + +NV_CTRL_NOTEBOOK_DISPLAY_CHANGE_LID_EVENT = 277 # not supported + +# +# NV_CTRL_NOTEBOOK_INTERNAL_LCD - deprecated +# + +NV_CTRL_NOTEBOOK_INTERNAL_LCD = 278 # deprecated + +# +# NV_CTRL_DEPTH_30_ALLOWED - returns whether the NVIDIA X driver supports +# depth 30 on the specified X screen or GPU. +# + +NV_CTRL_DEPTH_30_ALLOWED = 279 # R--G + +# +# NV_CTRL_MODE_SET_EVENT This attribute is sent as an event +# when hotkey, ctrl-alt-+/- or randr event occurs. Note that +# This attribute cannot be set or queried and is meant to +# be received by clients that wish to be notified of when +# mode set events occur. +# + +NV_CTRL_MODE_SET_EVENT = 280 # --- + +# +# NV_CTRL_OPENGL_AA_LINE_GAMMA_VALUE - the gamma value used by +# OpenGL when NV_CTRL_OPENGL_AA_LINE_GAMMA is enabled +# + +NV_CTRL_OPENGL_AA_LINE_GAMMA_VALUE = 281 # RW-X + +# +# NV_CTRL_VCSC_HIGH_PERF_MODE - deprecated +# +# Is used to both query High Performance Mode status on the Visual Computing +# System, and also to enable or disable High Performance Mode. +# + +NV_CTRL_VCSC_HIGH_PERF_MODE = 282 # RW-V +NV_CTRL_VCSC_HIGH_PERF_MODE_DISABLE = 0 +NV_CTRL_VCSC_HIGH_PERF_MODE_ENABLE = 1 + +# +# NV_CTRL_DISPLAYPORT_LINK_RATE - returns the negotiated lane bandwidth of the +# DisplayPort main link. The numerical value of this attribute is the link +# rate in bps divided by 27000000. +# This attribute is only available for DisplayPort flat panels. +# + +NV_CTRL_DISPLAYPORT_LINK_RATE = 291 # R-DG +NV_CTRL_DISPLAYPORT_LINK_RATE_DISABLED = 0x0 +NV_CTRL_DISPLAYPORT_LINK_RATE_1_62GBPS = 0x6 # deprecated +NV_CTRL_DISPLAYPORT_LINK_RATE_2_70GBPS = 0xA # deprecated + +# +# NV_CTRL_STEREO_EYES_EXCHANGE - Controls whether or not the left and right +# eyes of a stereo image are flipped. +# + +NV_CTRL_STEREO_EYES_EXCHANGE = 292 # RW-X +NV_CTRL_STEREO_EYES_EXCHANGE_OFF = 0 +NV_CTRL_STEREO_EYES_EXCHANGE_ON = 1 + +# +# NV_CTRL_NO_SCANOUT - returns whether the special "NoScanout" mode is +# enabled on the specified X screen or GPU; for details on this mode, +# see the description of the "none" value for the "UseDisplayDevice" +# X configuration option in the NVIDIA driver README. +# + +NV_CTRL_NO_SCANOUT = 293 # R--G +NV_CTRL_NO_SCANOUT_DISABLED = 0 +NV_CTRL_NO_SCANOUT_ENABLED = 1 + +# +# NV_CTRL_GVO_CSC_CHANGED_EVENT This attribute is sent as an event +# when the color space conversion matrix has been altered by another +# client. +# + +NV_CTRL_GVO_CSC_CHANGED_EVENT = 294 # --- + +# +# NV_CTRL_FRAMELOCK_SLAVEABLE - deprecated +# +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG should be used instead. +# + +NV_CTRL_FRAMELOCK_SLAVEABLE = 295 # deprecated + +# +# NV_CTRL_GVO_SYNC_TO_DISPLAY This attribute controls whether or not +# the non-SDI display device will be sync'ed to the SDI display device +# (when configured in TwinView, Clone Mode or when using the SDI device +# with OpenGL). +# + +NV_CTRL_GVO_SYNC_TO_DISPLAY = 296 # --- +NV_CTRL_GVO_SYNC_TO_DISPLAY_DISABLE = 0 +NV_CTRL_GVO_SYNC_TO_DISPLAY_ENABLE = 1 + +# +# NV_CTRL_X_SERVER_UNIQUE_ID - returns a pseudo-unique identifier for this +# X server. Intended for use in cases where an NV-CONTROL client communicates +# with multiple X servers, and wants some level of confidence that two +# X Display connections correspond to the same or different X servers. +# + +NV_CTRL_X_SERVER_UNIQUE_ID = 297 # R--- + +# +# NV_CTRL_PIXMAP_CACHE - This attribute controls whether the driver attempts to +# store video memory pixmaps in a cache. The cache speeds up allocation and +# deallocation of pixmaps, but could use more memory than when the cache is +# disabled. +# + +NV_CTRL_PIXMAP_CACHE = 298 # RW-X +NV_CTRL_PIXMAP_CACHE_DISABLE = 0 +NV_CTRL_PIXMAP_CACHE_ENABLE = 1 + +# +# NV_CTRL_PIXMAP_CACHE_ROUNDING_SIZE_KB - When the pixmap cache is enabled and +# there is not enough free space in the cache to fit a new pixmap, the driver +# will round up to the next multiple of this number of kilobytes when +# allocating more memory for the cache. +# + +NV_CTRL_PIXMAP_CACHE_ROUNDING_SIZE_KB = 299 # RW-X + +# +# NV_CTRL_IS_GVO_DISPLAY - returns whether or not a given display is an +# SDI device. +# + +NV_CTRL_IS_GVO_DISPLAY = 300 # R-D +NV_CTRL_IS_GVO_DISPLAY_FALSE = 0 +NV_CTRL_IS_GVO_DISPLAY_TRUE = 1 + +# +# NV_CTRL_PCI_ID - Returns the PCI vendor and device ID of the specified +# device. +# +# NV_CTRL_PCI_ID is a "packed" integer attribute; the PCI vendor ID is stored +# in the upper 16 bits of the integer, and the PCI device ID is stored in the +# lower 16 bits of the integer. +# + +NV_CTRL_PCI_ID = 301 # R--GI + +# +# NV_CTRL_GVO_FULL_RANGE_COLOR - Allow full range color data [4-1019] +# without clamping to [64-940]. +# + +NV_CTRL_GVO_FULL_RANGE_COLOR = 302 # RW- +NV_CTRL_GVO_FULL_RANGE_COLOR_DISABLED = 0 +NV_CTRL_GVO_FULL_RANGE_COLOR_ENABLED = 1 + +# +# NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE - Returns whether or not +# SLI Mosaic Mode supported. +# + +NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE = 303 # R-- +NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE_FALSE = 0 +NV_CTRL_SLI_MOSAIC_MODE_AVAILABLE_TRUE = 1 + +# +# NV_CTRL_GVO_ENABLE_RGB_DATA - Allows clients to specify when +# the GVO board should process colors as RGB when the output data +# format is one of the NV_CTRL_GVO_DATA_FORMAT_???_PASSTRHU modes. +# + +NV_CTRL_GVO_ENABLE_RGB_DATA = 304 # RW- +NV_CTRL_GVO_ENABLE_RGB_DATA_DISABLE = 0 +NV_CTRL_GVO_ENABLE_RGB_DATA_ENABLE = 1 + +# +# NV_CTRL_IMAGE_SHARPENING_DEFAULT - Returns default value of +# Image Sharpening. +# + +NV_CTRL_IMAGE_SHARPENING_DEFAULT = 305 # R-- + +# +# NV_CTRL_PCI_DOMAIN - Returns the PCI domain number the specified device is +# using. +# + +NV_CTRL_PCI_DOMAIN = 306 # R--GI + +# +# NV_CTRL_GVI_NUM_JACKS - Returns the number of input BNC jacks available +# on a GVI device. +# + +NV_CTRL_GVI_NUM_JACKS = 307 # R--I + +# +# NV_CTRL_GVI_MAX_LINKS_PER_STREAM - Returns the maximum supported number of +# links that can be tied to one stream. +# + +NV_CTRL_GVI_MAX_LINKS_PER_STREAM = 308 # R--I + +# +# NV_CTRL_GVI_DETECTED_CHANNEL_BITS_PER_COMPONENT - Returns the detected +# number of bits per component (BPC) of data on the given input jack+ +# channel. +# +# The jack number should be specified in the lower 16 bits of the +# "display_mask" parameter, while the channel number should be specified in +# the upper 16 bits. +# + +NV_CTRL_GVI_DETECTED_CHANNEL_BITS_PER_COMPONENT = 309 # R--I +NV_CTRL_GVI_BITS_PER_COMPONENT_UNKNOWN = 0 +NV_CTRL_GVI_BITS_PER_COMPONENT_8 = 1 +NV_CTRL_GVI_BITS_PER_COMPONENT_10 = 2 +NV_CTRL_GVI_BITS_PER_COMPONENT_12 = 3 + +# +# NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT - Specify the number of +# bits per component (BPC) of data for the captured stream. +# The stream number should be specified in the "display_mask" parameter. +# +# Note: Setting this attribute may also result in the following +# NV-CONTROL attributes being reset on the GVI device (to ensure +# the configuration remains valid): +# NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING +# + +NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT = 310 # RW-I + +# +# NV_CTRL_GVI_DETECTED_CHANNEL_COMPONENT_SAMPLING - Returns the detected +# sampling format for the input jack+channel. +# +# The jack number should be specified in the lower 16 bits of the +# "display_mask" parameter, while the channel number should be specified in +# the upper 16 bits. +# + +NV_CTRL_GVI_DETECTED_CHANNEL_COMPONENT_SAMPLING = 311 # R--I +NV_CTRL_GVI_COMPONENT_SAMPLING_UNKNOWN = 0 +NV_CTRL_GVI_COMPONENT_SAMPLING_4444 = 1 +NV_CTRL_GVI_COMPONENT_SAMPLING_4224 = 2 +NV_CTRL_GVI_COMPONENT_SAMPLING_444 = 3 +NV_CTRL_GVI_COMPONENT_SAMPLING_422 = 4 +NV_CTRL_GVI_COMPONENT_SAMPLING_420 = 5 + +# +# NV_CTRL_GVI_REQUESTED_COMPONENT_SAMPLING - Specify the sampling format for +# the captured stream. +# The possible values are the NV_CTRL_GVI_DETECTED_COMPONENT_SAMPLING +# constants. +# The stream number should be specified in the "display_mask" parameter. +# + +NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING = 312 # RW-I + +# +# NV_CTRL_GVI_CHROMA_EXPAND - Enable or disable 4:2:2 -> 4:4:4 chroma +# expansion for the captured stream. This value is ignored when a +# COMPONENT_SAMPLING format is selected that does not use chroma subsampling, +# or if a BITS_PER_COMPONENT value is selected that is not supported. +# The stream number should be specified in the "display_mask" parameter. +# + +NV_CTRL_GVI_REQUESTED_STREAM_CHROMA_EXPAND = 313 # RW-I +NV_CTRL_GVI_CHROMA_EXPAND_FALSE = 0 +NV_CTRL_GVI_CHROMA_EXPAND_TRUE = 1 + +# +# NV_CTRL_GVI_DETECTED_CHANNEL_COLOR_SPACE - Returns the detected color space +# of the input jack+channel. +# +# The jack number should be specified in the lower 16 bits of the +# "display_mask" parameter, while the channel number should be specified in +# the upper 16 bits. +# + +NV_CTRL_GVI_DETECTED_CHANNEL_COLOR_SPACE = 314 # R--I +NV_CTRL_GVI_COLOR_SPACE_UNKNOWN = 0 +NV_CTRL_GVI_COLOR_SPACE_GBR = 1 +NV_CTRL_GVI_COLOR_SPACE_GBRA = 2 +NV_CTRL_GVI_COLOR_SPACE_GBRD = 3 +NV_CTRL_GVI_COLOR_SPACE_YCBCR = 4 +NV_CTRL_GVI_COLOR_SPACE_YCBCRA = 5 +NV_CTRL_GVI_COLOR_SPACE_YCBCRD = 6 + +# +# NV_CTRL_GVI_DETECTED_CHANNEL_LINK_ID - Returns the detected link identifier +# for the given input jack+channel. +# +# The jack number should be specified in the lower 16 bits of the +# "display_mask" parameter, while the channel number should be specified in +# the upper 16 bits. +# + +NV_CTRL_GVI_DETECTED_CHANNEL_LINK_ID = 315 # R--I +NV_CTRL_GVI_LINK_ID_UNKNOWN = 0xFFFF + +# +# NV_CTRL_GVI_DETECTED_CHANNEL_SMPTE352_IDENTIFIER - Returns the 4-byte +# SMPTE 352 identifier from the given input jack+channel. +# +# The jack number should be specified in the lower 16 bits of the +# "display_mask" parameter, while the channel number should be specified in +# the upper 16 bits. +# + +NV_CTRL_GVI_DETECTED_CHANNEL_SMPTE352_IDENTIFIER = 316 # R--I + +# +# NV_CTRL_GVI_GLOBAL_IDENTIFIER - Returns a global identifier for the +# GVI device. This identifier can be used to relate GVI devices named +# in NV-CONTROL with those enumerated in OpenGL. +# + +NV_CTRL_GVI_GLOBAL_IDENTIFIER = 317 # R--I + +# +# NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION - Returns the number of nanoseconds +# that one unit of NV_CTRL_FRAMELOCK_SYNC_DELAY corresponds to. +# +NV_CTRL_FRAMELOCK_SYNC_DELAY_RESOLUTION = 318 # R-- + +# +# NV_CTRL_GPU_COOLER_MANUAL_CONTROL - Query the current or set a new +# cooler control state; the value of this attribute controls the +# availability of additional cooler control attributes (see below). +# +# Note: this attribute is unavailable unless cooler control support +# has been enabled in the X server (by the user). +# + +NV_CTRL_GPU_COOLER_MANUAL_CONTROL = 319 # RW-G +NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE = 0 +NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE = 1 + +# +# NV_CTRL_THERMAL_COOLER_LEVEL - The cooler's target level. +# Normally, the driver dynamically adjusts the cooler based on +# the needs of the GPU. But when NV_CTRL_GPU_COOLER_MANUAL_CONTROL=TRUE, +# the driver will attempt to make the cooler achieve the setting in +# NV_CTRL_THERMAL_COOLER_LEVEL. The actual current level of the cooler +# is reported in NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL. +# + +NV_CTRL_THERMAL_COOLER_LEVEL = 320 # RW-C + +# NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT - Sets default values of +# cooler. +# + +NV_CTRL_THERMAL_COOLER_LEVEL_SET_DEFAULT = 321 # -W-C + +# +# NV_CTRL_THERMAL_COOLER_CONTROL_TYPE - +# Returns a cooler's control signal characteristics. +# The possible types are restricted, Variable and Toggle. +# + +NV_CTRL_THERMAL_COOLER_CONTROL_TYPE = 322 # R--C +NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_NONE = 0 +NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_TOGGLE = 1 +NV_CTRL_THERMAL_COOLER_CONTROL_TYPE_VARIABLE = 2 + +# +# NV_CTRL_THERMAL_COOLER_TARGET - Returns objects that cooler cools. +# Targets may be GPU, Memory, Power Supply or All of these. +# GPU_RELATED = GPU | MEMORY | POWER_SUPPLY +# +# + +NV_CTRL_THERMAL_COOLER_TARGET = 323 # R--C +NV_CTRL_THERMAL_COOLER_TARGET_NONE = 0 +NV_CTRL_THERMAL_COOLER_TARGET_GPU = 1 +NV_CTRL_THERMAL_COOLER_TARGET_MEMORY = 2 +NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY = 4 +NV_CTRL_THERMAL_COOLER_TARGET_GPU_RELATED = NV_CTRL_THERMAL_COOLER_TARGET_GPU | NV_CTRL_THERMAL_COOLER_TARGET_MEMORY | NV_CTRL_THERMAL_COOLER_TARGET_POWER_SUPPLY + +# +# NV_CTRL_GPU_ECC_SUPPORTED - Reports whether ECC is supported by the +# targeted GPU. +# +NV_CTRL_GPU_ECC_SUPPORTED = 324 # R--G +NV_CTRL_GPU_ECC_SUPPORTED_FALSE = 0 +NV_CTRL_GPU_ECC_SUPPORTED_TRUE = 1 + +# +# NV_CTRL_GPU_ECC_STATUS - Returns the current hardware ECC setting +# for the targeted GPU. +# +NV_CTRL_GPU_ECC_STATUS = 325 # R--G +NV_CTRL_GPU_ECC_STATUS_DISABLED = 0 +NV_CTRL_GPU_ECC_STATUS_ENABLED = 1 + +# +# NV_CTRL_GPU_ECC_CONFIGURATION - Reports whether ECC can be configured +# dynamically for the GPU in question. +# +NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED = 326 # R--G +NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED_FALSE = 0 +NV_CTRL_GPU_ECC_CONFIGURATION_SUPPORTED_TRUE = 1 + +# +# NV_CTRL_GPU_ECC_CONFIGURATION_SETTING - Returns the current ECC +# configuration setting or specifies new settings. New settings do not +# take effect until the next POST. +# +NV_CTRL_GPU_ECC_CONFIGURATION = 327 # RW-G +NV_CTRL_GPU_ECC_CONFIGURATION_DISABLED = 0 +NV_CTRL_GPU_ECC_CONFIGURATION_ENABLED = 1 + +# +# NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_SETTING - Returns the default +# ECC configuration setting. +# +NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION = 328 # R--G +NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_DISABLED = 0 +NV_CTRL_GPU_ECC_DEFAULT_CONFIGURATION_ENABLED = 1 + +# +# NV_CTRL_GPU_ECC_SINGLE_BIT_ERRORS - Returns the number of single-bit +# ECC errors detected by the targeted GPU since the last POST. +# Note: this attribute is a 64-bit integer attribute. +# +NV_CTRL_GPU_ECC_SINGLE_BIT_ERRORS = 329 # R--GQ + +# +# NV_CTRL_GPU_ECC_DOUBLE_BIT_ERRORS - Returns the number of double-bit +# ECC errors detected by the targeted GPU since the last POST. +# Note: this attribute is a 64-bit integer attribute. +# +NV_CTRL_GPU_ECC_DOUBLE_BIT_ERRORS = 330 # R--GQ + +# +# NV_CTRL_GPU_ECC_AGGREGATE_SINGLE_BIT_ERRORS - Returns the number of +# single-bit ECC errors detected by the targeted GPU since the +# last counter reset. +# Note: this attribute is a 64-bit integer attribute. +# +NV_CTRL_GPU_ECC_AGGREGATE_SINGLE_BIT_ERRORS = 331 # R--GQ + +# +# NV_CTRL_GPU_ECC_AGGREGATE_DOUBLE_BIT_ERRORS - Returns the number of +# double-bit ECC errors detected by the targeted GPU since the +# last counter reset. +# Note: this attribute is a 64-bit integer attribute. +# +NV_CTRL_GPU_ECC_AGGREGATE_DOUBLE_BIT_ERRORS = 332 # R--GQ + +# +# NV_CTRL_GPU_ECC_RESET_ERROR_STATUS - Resets the volatile/aggregate +# single-bit and double-bit error counters. This attribute is a +# bitmask attribute. +# +NV_CTRL_GPU_ECC_RESET_ERROR_STATUS = 333 # -W-G +NV_CTRL_GPU_ECC_RESET_ERROR_STATUS_VOLATILE = 0x00000001 +NV_CTRL_GPU_ECC_RESET_ERROR_STATUS_AGGREGATE = 0x00000002 + +# +# NV_CTRL_GPU_POWER_MIZER_MODE - Provides a hint to the driver +# as to how to manage the performance of the GPU. +# +# ADAPTIVE - adjust GPU clocks based on GPU +# utilization +# PREFER_MAXIMUM_PERFORMANCE - raise GPU clocks to favor +# maximum performance, to the extent +# that thermal and other constraints +# allow +# AUTO - let the driver choose the performance +# policy +# PREFER_CONSISTENT_PERFORMANCE - lock to GPU base clocks +# +NV_CTRL_GPU_POWER_MIZER_MODE = 334 # RW-G +NV_CTRL_GPU_POWER_MIZER_MODE_ADAPTIVE = 0 +NV_CTRL_GPU_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE = 1 +NV_CTRL_GPU_POWER_MIZER_MODE_AUTO = 2 +NV_CTRL_GPU_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE = 3 + +# +# NV_CTRL_GVI_SYNC_OUTPUT_FORMAT - Returns the output sync signal +# from the GVI device. +# + +NV_CTRL_GVI_SYNC_OUTPUT_FORMAT = 335 # R--I + +# +# NV_CTRL_GVI_MAX_CHANNELS_PER_JACK - Returns the maximum +# supported number of (logical) channels within a single physical jack of +# a GVI device. For most SDI video formats, there is only one channel +# (channel 0). But for 3G video formats (as specified in SMPTE 425), +# as an example, there are two channels (channel 0 and channel 1) per +# physical jack. +# + +NV_CTRL_GVI_MAX_CHANNELS_PER_JACK = 336 # R--I + +# +# NV_CTRL_GVI_MAX_STREAMS - Returns the maximum number of streams +# that can be configured on the GVI device. +# + +NV_CTRL_GVI_MAX_STREAMS = 337 # R--I + +# +# NV_CTRL_GVI_NUM_CAPTURE_SURFACES - The GVI interface exposed through +# NV-CONTROL and the GLX_NV_video_input extension uses internal capture +# surfaces when frames are read from the GVI device. The +# NV_CTRL_GVI_NUM_CAPTURE_SURFACES can be used to query and assign the +# number of capture surfaces. This attribute is applied when +# glXBindVideoCaptureDeviceNV() is called by the application. +# +# A lower number of capture surfaces will mean less video memory is used, +# but can result in frames being dropped if the application cannot keep up +# with the capture device. A higher number will prevent frames from being +# dropped, making capture more reliable but will consume move video memory. +# +NV_CTRL_GVI_NUM_CAPTURE_SURFACES = 338 # RW-I + +# +# NV_CTRL_OVERSCAN_COMPENSATION - not supported +# +NV_CTRL_OVERSCAN_COMPENSATION = 339 # not supported + +# +# NV_CTRL_GPU_PCIE_GENERATION - Reports the current PCIe generation. +# +NV_CTRL_GPU_PCIE_GENERATION = 341 # R--GI +NV_CTRL_GPU_PCIE_GENERATION1 = 0x00000001 +NV_CTRL_GPU_PCIE_GENERATION2 = 0x00000002 +NV_CTRL_GPU_PCIE_GENERATION3 = 0x00000003 + +# +# NV_CTRL_GVI_BOUND_GPU - Returns the NV_CTRL_TARGET_TYPE_GPU target_id of +# the GPU currently bound to the GVI device. Returns -1 if no GPU is +# currently bound to the GVI device. +# +NV_CTRL_GVI_BOUND_GPU = 342 # R--I + +# +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 - this attribute is only +# intended to be used to query the ValidValues for +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for VIDEO_FORMAT values between +# 64 and 95. See NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT for details. +# + +NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT3 = 343 # ---GI + +# +# NV_CTRL_ACCELERATE_TRAPEZOIDS - Toggles RENDER Trapezoid acceleration +# + +NV_CTRL_ACCELERATE_TRAPEZOIDS = 344 # RW- +NV_CTRL_ACCELERATE_TRAPEZOIDS_DISABLE = 0 +NV_CTRL_ACCELERATE_TRAPEZOIDS_ENABLE = 1 + +# +# NV_CTRL_GPU_CORES - Returns number of GPU cores supported by the graphics +# pipeline. +# + +NV_CTRL_GPU_CORES = 345 # R--G + +# +# NV_CTRL_GPU_MEMORY_BUS_WIDTH - Returns memory bus bandwidth on the associated +# subdevice. +# + +NV_CTRL_GPU_MEMORY_BUS_WIDTH = 346 # R--G + +# +# NV_CTRL_GVI_TEST_MODE - This attribute controls the GVI test mode. When +# enabled, the GVI device will generate fake data as quickly as possible. All +# GVI settings are still valid when this is enabled (e.g., the requested video +# format is honored and sets the video size). +# This may be used to test the pipeline. +# + +NV_CTRL_GVI_TEST_MODE = 347 # R--I +NV_CTRL_GVI_TEST_MODE_DISABLE = 0 +NV_CTRL_GVI_TEST_MODE_ENABLE = 1 + +# +# NV_CTRL_COLOR_SPACE - This option controls the preferred color space of the +# video signal. This may not match the current color space depending on the +# current mode on this display. +# +# NV_CTRL_CURRENT_COLOR_SPACE will reflect the actual color space in use. +# +NV_CTRL_COLOR_SPACE = 348 # RWDG +NV_CTRL_COLOR_SPACE_RGB = 0 +NV_CTRL_COLOR_SPACE_YCbCr422 = 1 +NV_CTRL_COLOR_SPACE_YCbCr444 = 2 + +# +# NV_CTRL_COLOR_RANGE - This option controls the preferred color range of the +# video signal. +# +# If the current color space requires it, the actual color range will be +# limited. +# +# NV_CTRL_CURRENT_COLOR_RANGE will reflect the actual color range in use. +# +NV_CTRL_COLOR_RANGE = 349 # RWDG +NV_CTRL_COLOR_RANGE_FULL = 0 +NV_CTRL_COLOR_RANGE_LIMITED = 1 + +# +# NV_CTRL_GPU_SCALING_DEFAULT_TARGET - not supported +# + +NV_CTRL_GPU_SCALING_DEFAULT_TARGET = 350 # not supported + +# +# NV_CTRL_GPU_SCALING_DEFAULT_METHOD - not supported +# + +NV_CTRL_GPU_SCALING_DEFAULT_METHOD = 351 # not supported + +# +# NV_CTRL_DITHERING_MODE - Controls the dithering mode, when +# NV_CTRL_CURRENT_DITHERING is Enabled. +# +# AUTO: allow the driver to choose the dithering mode automatically. +# +# DYNAMIC_2X2: use a 2x2 matrix to dither from the GPU's pixel +# pipeline to the bit depth of the flat panel. The matrix values +# are changed from frame to frame. +# +# STATIC_2X2: use a 2x2 matrix to dither from the GPU's pixel +# pipeline to the bit depth of the flat panel. The matrix values +# do not change from frame to frame. +# +# TEMPORAL: use a pseudorandom value from a uniform distribution calculated at +# every pixel to achieve stochastic dithering. This method produces a better +# visual result than 2x2 matrix approaches. +# +NV_CTRL_DITHERING_MODE = 352 # RWDG +NV_CTRL_DITHERING_MODE_AUTO = 0 +NV_CTRL_DITHERING_MODE_DYNAMIC_2X2 = 1 +NV_CTRL_DITHERING_MODE_STATIC_2X2 = 2 +NV_CTRL_DITHERING_MODE_TEMPORAL = 3 + +# +# NV_CTRL_CURRENT_DITHERING - Returns the current dithering state. +# +NV_CTRL_CURRENT_DITHERING = 353 # R-DG +NV_CTRL_CURRENT_DITHERING_DISABLED = 0 +NV_CTRL_CURRENT_DITHERING_ENABLED = 1 + +# +# NV_CTRL_CURRENT_DITHERING_MODE - Returns the current dithering +# mode. +# +NV_CTRL_CURRENT_DITHERING_MODE = 354 # R-DG +NV_CTRL_CURRENT_DITHERING_MODE_NONE = 0 +NV_CTRL_CURRENT_DITHERING_MODE_DYNAMIC_2X2 = 1 +NV_CTRL_CURRENT_DITHERING_MODE_STATIC_2X2 = 2 +NV_CTRL_CURRENT_DITHERING_MODE_TEMPORAL = 3 + +# +# NV_CTRL_THERMAL_SENSOR_READING - Returns the thermal sensor's current +# reading. +# +NV_CTRL_THERMAL_SENSOR_READING = 355 # R--S + +# +# NV_CTRL_THERMAL_SENSOR_PROVIDER - Returns the hardware device that +# provides the thermal sensor. +# +NV_CTRL_THERMAL_SENSOR_PROVIDER = 356 # R--S +NV_CTRL_THERMAL_SENSOR_PROVIDER_NONE = 0 +NV_CTRL_THERMAL_SENSOR_PROVIDER_GPU_INTERNAL = 1 +NV_CTRL_THERMAL_SENSOR_PROVIDER_ADM1032 = 2 +NV_CTRL_THERMAL_SENSOR_PROVIDER_ADT7461 = 3 +NV_CTRL_THERMAL_SENSOR_PROVIDER_MAX6649 = 4 +NV_CTRL_THERMAL_SENSOR_PROVIDER_MAX1617 = 5 +NV_CTRL_THERMAL_SENSOR_PROVIDER_LM99 = 6 +NV_CTRL_THERMAL_SENSOR_PROVIDER_LM89 = 7 +NV_CTRL_THERMAL_SENSOR_PROVIDER_LM64 = 8 +NV_CTRL_THERMAL_SENSOR_PROVIDER_G781 = 9 +NV_CTRL_THERMAL_SENSOR_PROVIDER_ADT7473 = 10 +NV_CTRL_THERMAL_SENSOR_PROVIDER_SBMAX6649 = 11 +NV_CTRL_THERMAL_SENSOR_PROVIDER_VBIOSEVT = 12 +NV_CTRL_THERMAL_SENSOR_PROVIDER_OS = 13 +NV_CTRL_THERMAL_SENSOR_PROVIDER_UNKNOWN = 0xFFFFFFFF + +# +# NV_CTRL_THERMAL_SENSOR_TARGET - Returns what hardware component +# the thermal sensor is measuring. +# +NV_CTRL_THERMAL_SENSOR_TARGET = 357 # R--S +NV_CTRL_THERMAL_SENSOR_TARGET_NONE = 0 +NV_CTRL_THERMAL_SENSOR_TARGET_GPU = 1 +NV_CTRL_THERMAL_SENSOR_TARGET_MEMORY = 2 +NV_CTRL_THERMAL_SENSOR_TARGET_POWER_SUPPLY = 4 +NV_CTRL_THERMAL_SENSOR_TARGET_BOARD = 8 +NV_CTRL_THERMAL_SENSOR_TARGET_UNKNOWN = 0xFFFFFFFF + +# +# NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR - when TRUE, OpenGL will +# draw information about the current MULTIGPU mode. +# +NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR = 358 # RW-X +NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR_FALSE = 0 +NV_CTRL_SHOW_MULTIGPU_VISUAL_INDICATOR_TRUE = 1 + +# +# NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS - Returns GPU's processor +# clock freqs. +# +NV_CTRL_GPU_CURRENT_PROCESSOR_CLOCK_FREQS = 359 # RW-G + +# +# NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS - query the flags (various information +# for the specified NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be +# queried with existing interfaces, the video format should be specified +# in the display_mask field; eg: +# +# XNVCTRLQueryTargetAttribute(dpy, +# NV_CTRL_TARGET_TYPE_GVI, +# gvi, +# NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296, +# NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS, +# &flags); +# +# Note: The NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_1080P_NO_12BPC flag is set +# for those 1080P 3G modes (level A and B) that do not support +# 12 bits per component (when configuring a GVI stream.) +# + +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS = 360 # R--I +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_NONE = 0x00000000 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_INTERLACED = 0x00000001 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_PROGRESSIVE = 0x00000002 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_PSF = 0x00000004 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_A = 0x00000008 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_B = 0x00000010 +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G = NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_A | NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_LEVEL_B +NV_CTRL_GVIO_VIDEO_FORMAT_FLAGS_3G_1080P_NO_12BPC = 0x00000020 + +# +# NV_CTRL_GPU_PCIE_MAX_LINK_SPEED - returns maximum PCIe link speed, +# in gigatransfers per second (GT/s). +# + +NV_CTRL_GPU_PCIE_MAX_LINK_SPEED = 361 # R--GI + +# +# NV_CTRL_3D_VISION_PRO_RESET_TRANSCEIVER_TO_FACTORY_SETTINGS - Resets the +# 3D Vision Pro transceiver to its factory settings. +# +NV_CTRL_3D_VISION_PRO_RESET_TRANSCEIVER_TO_FACTORY_SETTINGS = 363 # -W-T + +# +# NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL - Controls the channel that is +# currently used by the 3D Vision Pro transceiver. +# +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL = 364 # RW-T + +# +# NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE - Controls the mode in which the +# 3D Vision Pro transceiver operates. +# NV_CTRL_3D_VISION_PRO_TM_LOW_RANGE is bidirectional +# NV_CTRL_3D_VISION_PRO_TM_MEDIUM_RANGE is bidirectional +# NV_CTRL_3D_VISION_PRO_TM_HIGH_RANGE may be bidirectional just up to a +# given range, and unidirectional beyond it +# NV_CTRL_3D_VISION_PRO_TM_COUNT is the total number of +# 3D Vision Pro transceiver modes +# +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE = 365 # RW-T +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_INVALID = 0 +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_LOW_RANGE = 1 +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_MEDIUM_RANGE = 2 +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_HIGH_RANGE = 3 +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_MODE_COUNT = 4 + +# +# NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES - controls whether updates to the color +# lookup table (LUT) are synchronous with respect to X rendering. For example, +# if an X client sends XStoreColors followed by XFillRectangle, the driver will +# guarantee that the FillRectangle request is not processed until after the +# updated LUT colors are actually visible on the screen if +# NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES is enabled. Otherwise, the rendering may +# occur first. +# +# This makes a difference for applications that use the LUT to animate, such as +# XPilot. If you experience flickering in applications that use LUT +# animations, try enabling this attribute. +# +# When synchronous updates are enabled, XStoreColors requests will be processed +# at your screen's refresh rate. +# + +NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES = 367 # RWDG +NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES_DISABLE = 0 +NV_CTRL_SYNCHRONOUS_PALETTE_UPDATES_ENABLE = 1 + +# +# NV_CTRL_DITHERING_DEPTH - Controls the dithering depth when +# NV_CTRL_CURRENT_DITHERING is ENABLED. Some displays connected +# to the GPU via the DVI or LVDS interfaces cannot display the +# full color range of ten bits per channel, so the GPU will +# dither to either 6 or 8 bits per channel. +# +NV_CTRL_DITHERING_DEPTH = 368 # RWDG +NV_CTRL_DITHERING_DEPTH_AUTO = 0 +NV_CTRL_DITHERING_DEPTH_6_BITS = 1 +NV_CTRL_DITHERING_DEPTH_8_BITS = 2 + +# +# NV_CTRL_CURRENT_DITHERING_DEPTH - Returns the current dithering +# depth value. +# +NV_CTRL_CURRENT_DITHERING_DEPTH = 369 # R-DG +NV_CTRL_CURRENT_DITHERING_DEPTH_NONE = 0 +NV_CTRL_CURRENT_DITHERING_DEPTH_6_BITS = 1 +NV_CTRL_CURRENT_DITHERING_DEPTH_8_BITS = 2 + +# +# NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_FREQUENCY - Returns the +# frequency of the channel(in kHz) of the 3D Vision Pro transceiver. +# Use the display_mask parameter to specify the channel number. +# +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_FREQUENCY = 370 # R--T + +# +# NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_QUALITY - Returns the +# quality of the channel(in percentage) of the 3D Vision Pro transceiver. +# Use the display_mask parameter to specify the channel number. +# +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_QUALITY = 371 # R--T + +# +# NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_COUNT - Returns the number of +# channels on the 3D Vision Pro transceiver. +# +NV_CTRL_3D_VISION_PRO_TRANSCEIVER_CHANNEL_COUNT = 372 # R--T + +# +# NV_CTRL_3D_VISION_PRO_PAIR_GLASSES - Puts the 3D Vision Pro +# transceiver into pairing mode to gather additional glasses. +# NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_STOP - stops any pairing +# NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON - starts continuous +# pairing via beacon mode +# Any other value, N - Puts the 3D Vision Pro transceiver into +# authenticated pairing mode for N seconds. +# +NV_CTRL_3D_VISION_PRO_PAIR_GLASSES = 373 # -W-T +NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_STOP = 0 +NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON = 0xFFFFFFFF + +# +# NV_CTRL_3D_VISION_PRO_UNPAIR_GLASSES - Tells a specific pair +# of glasses to unpair. The glasses will "forget" the address +# of the 3D Vision Pro transceiver to which they have been paired. +# To unpair all the currently paired glasses, specify +# the glasses id as 0. +# +NV_CTRL_3D_VISION_PRO_UNPAIR_GLASSES = 374 # -W-T + +# +# NV_CTRL_3D_VISION_PRO_DISCOVER_GLASSES - Tells the 3D Vision Pro +# transceiver about the glasses that have been paired using +# NV_CTRL_3D_VISION_PRO_PAIR_GLASSES_BEACON. Unless this is done, +# the 3D Vision Pro transceiver will not know about glasses paired in +# beacon mode. +# +NV_CTRL_3D_VISION_PRO_DISCOVER_GLASSES = 375 # -W-T + +# +# NV_CTRL_3D_VISION_PRO_IDENTIFY_GLASSES - Causes glasses LEDs to +# flash for a short period of time. +# +NV_CTRL_3D_VISION_PRO_IDENTIFY_GLASSES = 376 # -W-T + +# +# NV_CTRL_3D_VISION_PRO_GLASSES_SYNC_CYCLE - Controls the +# sync cycle duration(in milliseconds) of the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_3D_VISION_PRO_GLASSES_SYNC_CYCLE = 378 # RW-T + +# +# NV_CTRL_3D_VISION_PRO_GLASSES_MISSED_SYNC_CYCLES - Returns the +# number of state sync cycles recently missed by the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_3D_VISION_PRO_GLASSES_MISSED_SYNC_CYCLES = 379 # R--T + +# +# NV_CTRL_3D_VISION_PRO_GLASSES_BATTERY_LEVEL - Returns the +# battery level(in percentage) of the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_3D_VISION_PRO_GLASSES_BATTERY_LEVEL = 380 # R--T + +# +# NV_CTRL_GVO_ANC_PARITY_COMPUTATION - Controls the SDI device's computation +# of the parity bit (bit 8) for ANC data words. +# + +NV_CTRL_GVO_ANC_PARITY_COMPUTATION = 381 # RW--- +NV_CTRL_GVO_ANC_PARITY_COMPUTATION_AUTO = 0 +NV_CTRL_GVO_ANC_PARITY_COMPUTATION_ON = 1 +NV_CTRL_GVO_ANC_PARITY_COMPUTATION_OFF = 2 + +# +# NV_CTRL_3D_VISION_PRO_GLASSES_PAIR_EVENT - This attribute is sent +# as an event when glasses get paired in response to pair command +# from any of the clients. +# +NV_CTRL_3D_VISION_PRO_GLASSES_PAIR_EVENT = 382 # ---T + +# +# NV_CTRL_3D_VISION_PRO_GLASSES_UNPAIR_EVENT - This attribute is sent +# as an event when glasses get unpaired in response to unpair command +# from any of the clients. +# +NV_CTRL_3D_VISION_PRO_GLASSES_UNPAIR_EVENT = 383 # ---T + +# +# NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH - returns the current +# PCIe link width, in number of lanes. +# +NV_CTRL_GPU_PCIE_CURRENT_LINK_WIDTH = 384 # R--GI + +# +# NV_CTRL_GPU_PCIE_CURRENT_LINK_SPEED - returns the current +# PCIe link speed, in megatransfers per second (GT/s). +# +NV_CTRL_GPU_PCIE_CURRENT_LINK_SPEED = 385 # R--GI + +# +# NV_CTRL_GVO_AUDIO_BLANKING - specifies whether the GVO device should delete +# audio ancillary data packets when frames are repeated. +# +# When a new frame is not ready in time, the current frame, including all +# ancillary data packets, is repeated. When this data includes audio packets, +# this can result in stutters or clicks. When this option is enabled, the GVO +# device will detect when frames are repeated, identify audio ancillary data +# packets, and mark them for deletion. +# +# This option is applied when the GVO device is bound. +# +NV_CTRL_GVO_AUDIO_BLANKING = 386 # RW- +NV_CTRL_GVO_AUDIO_BLANKING_DISABLE = 0 +NV_CTRL_GVO_AUDIO_BLANKING_ENABLE = 1 + +# +# NV_CTRL_CURRENT_METAMODE_ID - switch modes to the MetaMode with +# the specified ID. +# +NV_CTRL_CURRENT_METAMODE_ID = 387 # RW- + +# +# NV_CTRL_DISPLAY_ENABLED - Returns whether or not the display device +# is currently enabled. +# +NV_CTRL_DISPLAY_ENABLED = 388 # R-D +NV_CTRL_DISPLAY_ENABLED_TRUE = 1 +NV_CTRL_DISPLAY_ENABLED_FALSE = 0 + +# +# NV_CTRL_FRAMELOCK_INCOMING_HOUSE_SYNC_RATE: this is the rate +# of an incomming house sync signal to the frame lock board, in milliHz. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK or NV_CTRL_TARGET_TYPE_X_SCREEN +# target. +# +NV_CTRL_FRAMELOCK_INCOMING_HOUSE_SYNC_RATE = 389 # R--F + +# +# NV_CTRL_FXAA - enables FXAA. A pixel shader based anti- +# aliasing method. +# +NV_CTRL_FXAA = 390 # RW-X +NV_CTRL_FXAA_DISABLE = 0 +NV_CTRL_FXAA_ENABLE = 1 + +# +# NV_CTRL_DISPLAY_RANDR_OUTPUT_ID - the RandR Output ID (type RROutput) +# that corresponds to the specified Display Device target. If a new +# enough version of RandR is not available in the X server, +# DISPLAY_RANDR_OUTPUT_ID will be 0. +# +NV_CTRL_DISPLAY_RANDR_OUTPUT_ID = 391 # R-D- + +# +# NV_CTRL_FRAMELOCK_DISPLAY_CONFIG - Configures whether the display device +# should listen, ignore or drive the framelock sync signal. +# +# Note that whether or not a display device may be set as a client/server +# depends on the current configuration. For example, only one server may be +# set per Quadro Sync device, and displays can only be configured as a client +# if their refresh rate sufficiently matches the refresh rate of the server +# device. +# +# Note that when querying the ValidValues for this data type, the values are +# reported as bits within a bitmask (ATTRIBUTE_TYPE_INT_BITS); +# +NV_CTRL_FRAMELOCK_DISPLAY_CONFIG = 392 # RWD +NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_DISABLED = 0 +NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_CLIENT = 1 +NV_CTRL_FRAMELOCK_DISPLAY_CONFIG_SERVER = 2 + +# +# NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY - Returns the total amount of dedicated +# GPU video memory, in MB, on the specified GPU. This excludes any TurboCache +# padding included in the value returned by NV_CTRL_TOTAL_GPU_MEMORY. +# +NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY = 393 # R--G + +# +# NV_CTRL_USED_DEDICATED_GPU_MEMORY- Returns the amount of video memory +# currently used on the graphics card in MB. +# +NV_CTRL_USED_DEDICATED_GPU_MEMORY = 394 # R--G + +# +# NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE +# Some GPUs can make a tradeoff between double-precision floating-point +# performance and clock speed. Enabling double-precision floating point +# performance may benefit CUDA or OpenGL applications that require high +# bandwidth double-precision performance. Disabling this feature may benefit +# graphics applications that require higher clock speeds. +# +# This attribute is only available when toggling double precision boost +# can be done immediately (without need for a rebooot). +# +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE = 395 # RW-G +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE_DISABLED = 0 +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_IMMEDIATE_ENABLED = 1 + +# +# NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT +# Some GPUs can make a tradeoff between double-precision floating-point +# performance and clock speed. Enabling double-precision floating point +# performance may benefit CUDA or OpenGL applications that require high +# bandwidth double-precision performance. Disabling this feature may benefit +# graphics applications that require higher clock speeds. +# +# This attribute is only available when toggling double precision boost +# requires a reboot. +# + +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT = 396 # RW-G +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT_DISABLED = 0 +NV_CTRL_GPU_DOUBLE_PRECISION_BOOST_REBOOT_ENALED = 1 + +# +# NV_CTRL_DPY_HDMI_3D - Returns whether the specified display device is +# currently using HDMI 3D Frame Packed Stereo mode. Clients may use this +# to help interpret the refresh rate returned by NV_CTRL_REFRESH_RATE or +# NV_CTRL_REFRESH_RATE_3, which will be doubled when using HDMI 3D mode. +# +# This attribute may be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU target. +# + +NV_CTRL_DPY_HDMI_3D = 397 # R-DG +NV_CTRL_DPY_HDMI_3D_DISABLED = 0 +NV_CTRL_DPY_HDMI_3D_ENABLED = 1 + +# +# NV_CTRL_BASE_MOSAIC - Returns whether Base Mosaic is currently enabled on the +# given GPU. Querying the valid values of this attribute returns capabilities. +# + +NV_CTRL_BASE_MOSAIC = 398 # R--G +NV_CTRL_BASE_MOSAIC_DISABLED = 0 +NV_CTRL_BASE_MOSAIC_FULL = 1 +NV_CTRL_BASE_MOSAIC_LIMITED = 2 + +# +# NV_CTRL_MULTIGPU_MASTER_POSSIBLE - Returns whether the GPU can be configured +# as the master GPU in a Multi GPU configuration (SLI, SLI Mosaic, +# Base Mosaic). +# + +NV_CTRL_MULTIGPU_MASTER_POSSIBLE = 399 # R--G +NV_CTRL_MULTIGPU_MASTER_POSSIBLE_FALSE = 0 +NV_CTRL_MULTIGPU_MASTER_POSSIBLE_TRUE = 1 + +# +# NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE - Returns the default PowerMizer mode +# for the given GPU. +# +NV_CTRL_GPU_POWER_MIZER_DEFAULT_MODE = 400 # R--G + +# +# NV_CTRL_XV_SYNC_TO_DISPLAY_ID - When XVideo Sync To VBlank is enabled, this +# controls which display device will be synched to if the display is enabled. +# Returns NV_CTRL_XV_SYNC_TO_DISPLAY_ID_AUTO if no display has been +# selected. +# +NV_CTRL_XV_SYNC_TO_DISPLAY_ID = 401 # RW- +NV_CTRL_XV_SYNC_TO_DISPLAY_ID_AUTO = 0xFFFFFFFF + +# +# NV_CTRL_BACKLIGHT_BRIGHTNESS - The backlight brightness of an internal panel. +# +NV_CTRL_BACKLIGHT_BRIGHTNESS = 402 # RWD- + +# +# NV_CTRL_GPU_LOGO_BRIGHTNESS - Controls brightness +# of the logo on the GPU, if any. The value is variable from 0% - 100%. +# +NV_CTRL_GPU_LOGO_BRIGHTNESS = 403 # RW-G + +# +# NV_CTRL_GPU_SLI_LOGO_BRIGHTNESS - Controls brightness of the logo +# on the SLI bridge, if any. The value is variable from 0% - 100%. +# +NV_CTRL_GPU_SLI_LOGO_BRIGHTNESS = 404 # RW-G + +# +# NV_CTRL_THERMAL_COOLER_SPEED - Returns cooler's current operating speed in +# rotations per minute (RPM). +# + +NV_CTRL_THERMAL_COOLER_SPEED = 405 # R--C + +# +# NV_CTRL_PALETTE_UPDATE_EVENT - The Color Palette has been changed and the +# color correction info needs to be updated. +# + +NV_CTRL_PALETTE_UPDATE_EVENT = 406 # --- + +# +# NV_CTRL_VIDEO_ENCODER_UTILIZATION - Returns the video encoder engine +# utilization as a percentage. +# +NV_CTRL_VIDEO_ENCODER_UTILIZATION = 407 # R--G + +# +# NV_CTRL_GSYNC_ALLOWED - when TRUE, OpenGL will enable G-SYNC when possible; +# when FALSE, OpenGL will always use a fixed monitor refresh rate. +# + +NV_CTRL_GSYNC_ALLOWED = 408 # RW-X +NV_CTRL_GSYNC_ALLOWED_FALSE = 0 +NV_CTRL_GSYNC_ALLOWED_TRUE = 1 + +# +# NV_CTRL_GPU_NVCLOCK_OFFSET - This attribute controls the GPU clock offsets +# (in MHz) used for overclocking per performance level. +# Use the display_mask parameter to specify the performance level. +# +# Note: To enable overclocking support, set the X configuration +# option "Coolbits" to value "8". +# +# This offset can have any integer value between +# NVCTRLAttributeValidValues.u.range.min and +# NVCTRLAttributeValidValues.u.range.max (inclusive). +# +# This attribute is available on GeForce GTX 400 series and later +# Geforce GPUs. +# +NV_CTRL_GPU_NVCLOCK_OFFSET = 409 # RW-G + +# +# NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET - This attribute controls +# the memory transfer rate offsets (in MHz) used for overclocking +# per performance level. +# Use the display_mask parameter to specify the performance level. +# +# Note: To enable overclocking support, set the X configuration +# option "Coolbits" to value "8". +# +# This offset can have any integer value between +# NVCTRLAttributeValidValues.u.range.min and +# NVCTRLAttributeValidValues.u.range.max (inclusive). +# +# This attribute is available on GeForce GTX 400 series and later +# Geforce GPUs. +# +NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET = 410 # RW-G + +# +# NV_CTRL_VIDEO_DECODER_UTILIZATION - Returns the video decoder engine +# utilization as a percentage. +# +NV_CTRL_VIDEO_DECODER_UTILIZATION = 411 # R--G + +# +# NV_CTRL_GPU_OVER_VOLTAGE_OFFSET - This attribute controls +# the overvoltage offset in microvolts (uV). +# +# Note: To enable overvoltage support, set the X configuration +# option "Coolbits" to value "16". +# +# This offset can have any integer value between +# NVCTRLAttributeValidValues.u.range.min and +# NVCTRLAttributeValidValues.u.range.max (inclusive). +# +# This attribute is available on GeForce GTX 400 series and later +# Geforce GPUs. +# + +NV_CTRL_GPU_OVER_VOLTAGE_OFFSET = 412 # RW-G + +# +# NV_CTRL_GPU_CURRENT_CORE_VOLTAGE - This attribute returns the +# GPU's current operating voltage in microvolts (uV). +# +# This attribute is available on GPUs that support +# NV_CTRL_GPU_OVER_VOLTAGE_OFFSET. +# +NV_CTRL_GPU_CURRENT_CORE_VOLTAGE = 413 # R--G + +# +# NV_CTRL_CURRENT_COLOR_SPACE - Returns the current color space of the video +# signal. +# +# This will match NV_CTRL_COLOR_SPACE unless the current mode on this display +# device is an HDMI 2.0 4K@60Hz mode and the display device or GPU does not +# support driving this mode in RGB, in which case YCbCr420 will be returned. +# +NV_CTRL_CURRENT_COLOR_SPACE = 414 # R-DG +NV_CTRL_CURRENT_COLOR_SPACE_RGB = 0 +NV_CTRL_CURRENT_COLOR_SPACE_YCbCr422 = 1 +NV_CTRL_CURRENT_COLOR_SPACE_YCbCr444 = 2 +NV_CTRL_CURRENT_COLOR_SPACE_YCbCr420 = 3 + +# +# NV_CTRL_CURRENT_COLOR_RANGE - Returns the current color range of the video +# signal. +# +NV_CTRL_CURRENT_COLOR_RANGE = 415 # R-DG +NV_CTRL_CURRENT_COLOR_RANGE_FULL = 0 +NV_CTRL_CURRENT_COLOR_RANGE_LIMITED = 1 + +# +# NV_CTRL_SHOW_GSYNC_VISUAL_INDICATOR - when TRUE, OpenGL will indicate when +# G-SYNC is in use for full-screen applications. +# + +NV_CTRL_SHOW_GSYNC_VISUAL_INDICATOR = 416 # RW-X +NV_CTRL_SHOW_GSYNC_VISUAL_INDICATOR_FALSE = 0 +NV_CTRL_SHOW_GSYNC_VISUAL_INDICATOR_TRUE = 1 + +# +# NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL - Returns cooler's current +# operating level. This may fluctuate dynamically. When +# NV_CTRL_GPU_COOLER_MANUAL_CONTROL=TRUE, the driver attempts +# to make this match NV_CTRL_THERMAL_COOLER_LEVEL. When +# NV_CTRL_GPU_COOLER_MANUAL_CONTROL=FALSE, the driver adjusts the +# current level based on the needs of the GPU. +# + +NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL = 417 # R--C + +# +# NV_CTRL_STEREO_SWAP_MODE - This attribute controls the swap mode when +# Quad-Buffered stereo is used. +# NV_CTRL_STEREO_SWAP_MODE_APPLICATION_CONTROL : Stereo swap mode is derived +# from the value of swap interval. +# If it's odd, the per eye swap mode is used. +# If it's even, the per eye pair swap mode is used. +# NV_CTRL_STEREO_SWAP_MODE_PER_EYE : The driver swaps each eye as it is ready. +# NV_CTRL_STEREO_SWAP_MODE_PER_EYE_PAIR : The driver waits for both eyes to +# complete rendering before swapping. +# + +NV_CTRL_STEREO_SWAP_MODE = 418 # RW-X +NV_CTRL_STEREO_SWAP_MODE_APPLICATION_CONTROL = 0 +NV_CTRL_STEREO_SWAP_MODE_PER_EYE = 1 +NV_CTRL_STEREO_SWAP_MODE_PER_EYE_PAIR = 2 + +# +# NV_CTRL_CURRENT_XV_SYNC_TO_DISPLAY_ID - When XVideo Sync To VBlank is +# enabled, this returns the display id of the device currently synched to. +# Returns NV_CTRL_XV_SYNC_TO_DISPLAY_ID_AUTO if no display is currently +# set. +# + +NV_CTRL_CURRENT_XV_SYNC_TO_DISPLAY_ID = 419 # R-- + +# +# NV_CTRL_GPU_FRAMELOCK_FIRMWARE_UNSUPPORTED - Returns true if the +# Quadro Sync card connected to this GPU has a firmware version incompatible +# with this GPU. +# + +NV_CTRL_GPU_FRAMELOCK_FIRMWARE_UNSUPPORTED = 420 # R--G +NV_CTRL_GPU_FRAMELOCK_FIRMWARE_UNSUPPORTED_FALSE = 0 +NV_CTRL_GPU_FRAMELOCK_FIRMWARE_UNSUPPORTED_TRUE = 1 + +# +# NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE - Returns the connector type used by +# a DisplayPort display. +# + +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE = 421 # R-DG +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE_UNKNOWN = 0 +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE_DISPLAYPORT = 1 +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE_HDMI = 2 +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE_DVI = 3 +NV_CTRL_DISPLAYPORT_CONNECTOR_TYPE_VGA = 4 + +# +# NV_CTRL_DISPLAYPORT_IS_MULTISTREAM - Returns multi-stream support for +# DisplayPort displays. +# +NV_CTRL_DISPLAYPORT_IS_MULTISTREAM = 422 # R-DG + +# +# NV_CTRL_DISPLAYPORT_SINK_IS_AUDIO_CAPABLE - Returns whether a DisplayPort +# device supports audio. +# +NV_CTRL_DISPLAYPORT_SINK_IS_AUDIO_CAPABLE = 423 # R-DG + +# +# NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS - This attribute +# controls the GPU clock offsets (in MHz) used for overclocking. +# The offset is applied to all performance levels. +# +# Note: To enable overclocking support, set the X configuration +# option "Coolbits" to value "8". +# +# This offset can have any integer value between +# NVCTRLAttributeValidValues.u.range.min and +# NVCTRLAttributeValidValues.u.range.max (inclusive). +# +# This attribute is available on GeForce GTX 1000 series and later +# Geforce GPUs. +# +NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS = 424 # RW-G + +# +# NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS - This +# attribute controls the memory transfer rate offsets (in MHz) used +# for overclocking. The offset is applied to all performance levels. +# +# Note: To enable overclocking support, set the X configuration +# option "Coolbits" to value "8". +# +# This offset can have any integer value between +# NVCTRLAttributeValidValues.u.range.min and +# NVCTRLAttributeValidValues.u.range.max (inclusive). +# +# This attribute is available on GeForce GTX 1000 series and later +# Geforce GPUs. +# +NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS = 425 # RW-G + +# +# NV_CTRL_FRAMELOCK_FIRMWARE_VERSION - Queries the firmware major version of +# the Frame Lock device. +# +# This attribute must be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. +# + +NV_CTRL_FRAMELOCK_FIRMWARE_VERSION = 426 # R--F + +# +# NV_CTRL_FRAMELOCK_FIRMWARE_MINOR_VERSION - Queries the firmware minor +# version of the Frame Lock device. +# +# This attribute must be queried through XNVCTRLQueryTargetAttribute() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. +# + +NV_CTRL_FRAMELOCK_FIRMWARE_MINOR_VERSION = 427 # R--F + +# +# NV_CTRL_SHOW_GRAPHICS_VISUAL_INDICATOR - when TRUE, graphics APIs will +# indicate various runtime information such as flip/blit, vsync status, API +# in use. +# + +NV_CTRL_SHOW_GRAPHICS_VISUAL_INDICATOR = 428 # RW-X +NV_CTRL_SHOW_GRAPHICS_VISUAL_INDICATOR_FALSE = 0 +NV_CTRL_SHOW_GRAPHICS_VISUAL_INDICATOR_TRUE = 1 + +NV_CTRL_LAST_ATTRIBUTE = NV_CTRL_SHOW_GRAPHICS_VISUAL_INDICATOR + +############################################################################ + +# +# String Attributes: +# +# String attributes can be queryied through the XNVCTRLQueryStringAttribute() +# and XNVCTRLQueryTargetStringAttribute() function calls. +# +# String attributes can be set through the XNVCTRLSetStringAttribute() +# function call. (There are currently no string attributes that can be +# set on non-X Screen targets.) +# +# Unless otherwise noted, all string attributes can be queried/set using an +# NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take an +# NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried/set through +# XNVCTRLQueryStringAttribute()/XNVCTRLSetStringAttribute() (Since +# these assume an X Screen target). +# + + +# +# NV_CTRL_STRING_PRODUCT_NAME - the product name on which the +# specified X screen is running, or the product name of the specified +# Frame Lock device. +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target to +# return the product name of the GPU, or a NV_CTRL_TARGET_TYPE_FRAMELOCK to +# return the product name of the Frame Lock device. +# + +NV_CTRL_STRING_PRODUCT_NAME = 0 # R--GF + +# +# NV_CTRL_STRING_VBIOS_VERSION - the video bios version on the GPU on +# which the specified X screen is running. +# + +NV_CTRL_STRING_VBIOS_VERSION = 1 # R--G + +# +# NV_CTRL_STRING_NVIDIA_DRIVER_VERSION - string representation of the +# NVIDIA driver version number for the NVIDIA X driver in use. +# + +NV_CTRL_STRING_NVIDIA_DRIVER_VERSION = 3 # R--G + +# +# NV_CTRL_STRING_DISPLAY_DEVICE_NAME - name of the display device +# specified in the display_mask argument. +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_STRING_DISPLAY_DEVICE_NAME = 4 # R-DG + +# +# NV_CTRL_STRING_TV_ENCODER_NAME - not supported +# + +NV_CTRL_STRING_TV_ENCODER_NAME = 5 # not supported + +# +# NV_CTRL_STRING_GVIO_FIRMWARE_VERSION - indicates the version of the +# Firmware on the GVIO device. +# + +NV_CTRL_STRING_GVIO_FIRMWARE_VERSION = 8 # R--I + +# +# NV_CTRL_STRING_GVO_FIRMWARE_VERSION - renamed +# +# NV_CTRL_STRING_GVIO_FIRMWARE_VERSION should be used instead. +# +NV_CTRL_STRING_GVO_FIRMWARE_VERSION = 8 # renamed + +# +# NV_CTRL_STRING_CURRENT_MODELINE - Return the ModeLine currently +# being used by the specified display device. +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# +# The ModeLine string may be prepended with a comma-separated list of +# "token=value" pairs, separated from the ModeLine string by "::". +# This "token=value" syntax is the same as that used in +# NV_CTRL_BINARY_DATA_MODELINES +# + +NV_CTRL_STRING_CURRENT_MODELINE = 9 # R-DG + +# +# NV_CTRL_STRING_ADD_MODELINE - Adds a ModeLine to the specified +# display device. The ModeLine is not added if validation fails. +# +# The ModeLine string should have the same syntax as a ModeLine in +# the X configuration file; e.g., +# +# "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync +# + +NV_CTRL_STRING_ADD_MODELINE = 10 # -WDG + +# +# NV_CTRL_STRING_DELETE_MODELINE - Deletes an existing ModeLine +# from the specified display device. The currently selected +# ModeLine cannot be deleted. (This also means you cannot delete +# the last ModeLine.) +# +# The ModeLine string should have the same syntax as a ModeLine in +# the X configuration file; e.g., +# +# "1600x1200" 229.5 1600 1664 1856 2160 1200 1201 1204 1250 +HSync +VSync +# + +NV_CTRL_STRING_DELETE_MODELINE = 11 # -WDG + +# +# NV_CTRL_STRING_CURRENT_METAMODE - Returns the metamode currently +# being used by the specified X screen. The MetaMode string has the +# same syntax as the MetaMode X configuration option, as documented +# in the NVIDIA driver README. +# +# The returned string may be prepended with a comma-separated list of +# "token=value" pairs, separated from the MetaMode string by "::". +# This "token=value" syntax is the same as that used in +# NV_CTRL_BINARY_DATA_METAMODES. +# + +NV_CTRL_STRING_CURRENT_METAMODE = 12 # RW-- +NV_CTRL_STRING_CURRENT_METAMODE_VERSION_1 = NV_CTRL_STRING_CURRENT_METAMODE + +# +# NV_CTRL_STRING_ADD_METAMODE - Adds a MetaMode to the specified +# X Screen. +# +# It is recommended to not use this attribute, but instead use +# NV_CTRL_STRING_OPERATION_ADD_METAMODE. +# + +NV_CTRL_STRING_ADD_METAMODE = 13 # -W-- + +# +# NV_CTRL_STRING_DELETE_METAMODE - Deletes an existing MetaMode from +# the specified X Screen. The currently selected MetaMode cannot be +# deleted. (This also means you cannot delete the last MetaMode). +# The MetaMode string should have the same syntax as the MetaMode X +# configuration option, as documented in the NVIDIA driver README. +# + +NV_CTRL_STRING_DELETE_METAMODE = 14 # -WD-- + +# +# NV_CTRL_STRING_VCSC_PRODUCT_NAME - deprecated +# +# Queries the product name of the VCSC device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_PRODUCT_NAME = 15 # R---V + +# +# NV_CTRL_STRING_VCSC_PRODUCT_ID - deprecated +# +# Queries the product ID of the VCSC device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_PRODUCT_ID = 16 # R---V + +# +# NV_CTRL_STRING_VCSC_SERIAL_NUMBER - deprecated +# +# Queries the unique serial number of the VCS device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_SERIAL_NUMBER = 17 # R---V + +# +# NV_CTRL_STRING_VCSC_BUILD_DATE - deprecated +# +# Queries the date of the VCS device. the returned string is in the following +# format: "Week.Year" +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_BUILD_DATE = 18 # R---V + +# +# NV_CTRL_STRING_VCSC_FIRMWARE_VERSION - deprecated +# +# Queries the firmware version of the VCS device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_FIRMWARE_VERSION = 19 # R---V + +# +# NV_CTRL_STRING_VCSC_FIRMWARE_REVISION - deprecated +# +# Queries the firmware revision of the VCS device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCS target. +# + +NV_CTRL_STRING_VCSC_FIRMWARE_REVISION = 20 # R---V + +# +# NV_CTRL_STRING_VCSC_HARDWARE_VERSION - deprecated +# +# Queries the hardware version of the VCS device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_HARDWARE_VERSION = 21 # R---V + +# +# NV_CTRL_STRING_VCSC_HARDWARE_REVISION - deprecated +# +# Queries the hardware revision of the VCS device. +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# + +NV_CTRL_STRING_VCSC_HARDWARE_REVISION = 22 # R---V + +# +# NV_CTRL_STRING_MOVE_METAMODE - Moves a MetaMode to the specified +# index location. The MetaMode must already exist in the X Screen's +# list of MetaModes (as returned by the NV_CTRL_BINARY_DATA_METAMODES +# attribute). If the index is larger than the number of MetaModes in +# the list, the MetaMode is moved to the end of the list. The +# MetaMode string should have the same syntax as the MetaMode X +# configuration option, as documented in the NVIDIA driver README. + +# The MetaMode string must be prepended with a comma-separated list +# of "token=value" pairs, separated from the MetaMode string by "::". +# Currently, the only valid token is "index", which indicates where +# in the MetaMode list the MetaMode should be moved to. +# +# Other tokens may be added in the future. +# +# E.g., +# "index=5 :: CRT-0: 1024x768 @1024x768 +0+0" +# + +NV_CTRL_STRING_MOVE_METAMODE = 23 # -W-- + +# +# NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES - returns the valid +# horizontal sync ranges used to perform mode validation for the +# specified display device. The ranges are in the same format as the +# "HorizSync" X config option: +# +# "horizsync-range may be a comma separated list of either discrete +# values or ranges of values. A range of values is two values +# separated by a dash." +# +# The values are in kHz. +# +# Additionally, the string may be prepended with a comma-separated +# list of "token=value" pairs, separated from the HorizSync string by +# "::". Valid tokens: +# +# Token Value +# "source" "edid" - HorizSync is from the display device's EDID +# "xconfig" - HorizSync is from the "HorizSync" entry in +# the Monitor section of the X config file +# "option" - HorizSync is from the "HorizSync" NVIDIA X +# config option +# "builtin" - HorizSync is from NVIDIA X driver builtin +# default values +# +# Additional tokens and/or values may be added in the future. +# +# Example: "source=edid :: 30.000-62.000" +# + +NV_CTRL_STRING_VALID_HORIZ_SYNC_RANGES = 24 # R-DG + +# +# NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES - returns the valid +# vertical refresh ranges used to perform mode validation for the +# specified display device. The ranges are in the same format as the +# "VertRefresh" X config option: +# +# "vertrefresh-range may be a comma separated list of either discrete +# values or ranges of values. A range of values is two values +# separated by a dash." +# +# The values are in Hz. +# +# Additionally, the string may be prepended with a comma-separated +# list of "token=value" pairs, separated from the VertRefresh string by +# "::". Valid tokens: +# +# Token Value +# "source" "edid" - VertRefresh is from the display device's EDID +# "xconfig" - VertRefresh is from the "VertRefresh" entry in +# the Monitor section of the X config file +# "option" - VertRefresh is from the "VertRefresh" NVIDIA X +# config option +# "builtin" - VertRefresh is from NVIDIA X driver builtin +# default values +# +# Additional tokens and/or values may be added in the future. +# +# Example: "source=edid :: 50.000-75.000" +# + +NV_CTRL_STRING_VALID_VERT_REFRESH_RANGES = 25 # R-DG + +# +# NV_CTRL_STRING_SCREEN_RECTANGLE - returns the physical X Screen's +# initial position and size (in absolute coordinates) within the +# desktop as the "token=value" string: "x=#, y=#, width=#, height=#" +# +# Querying this attribute returns success only when Xinerama is enabled +# or the X server ABI is greater than equal to 12. +# + +NV_CTRL_STRING_SCREEN_RECTANGLE = 26 # R--- + +# +# NV_CTRL_STRING_XINERAMA_SCREEN_INFO - renamed +# +# NV_CTRL_STRING_SCREEN_RECTANGLE should be used instead. +# + +NV_CTRL_STRING_XINERAMA_SCREEN_INFO = 26 # renamed + +# +# NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER - used to specify the +# order that display devices will be returned via Xinerama when +# nvidiaXineramaInfo is enabled. Follows the same syntax as the +# nvidiaXineramaInfoOrder X config option. +# + +NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER = 27 # RW-- + +NV_CTRL_STRING_TWINVIEW_XINERAMA_INFO_ORDER = NV_CTRL_STRING_NVIDIA_XINERAMA_INFO_ORDER # for backwards compatibility: + +# +# NV_CTRL_STRING_SLI_MODE - returns a string describing the current +# SLI mode, if any, or FALSE if SLI is not currently enabled. +# +# This string should be used for informational purposes only, and +# should not be used to distinguish between SLI modes, other than to +# recognize when SLI is disabled (FALSE is returned) or +# enabled (the returned string is non-NULL and describes the current +# SLI configuration). +# + +NV_CTRL_STRING_SLI_MODE = 28 # R---*/ + +# +# NV_CTRL_STRING_PERFORMANCE_MODES - returns a string with all the +# performance modes defined for this GPU along with their associated +# NV Clock and Memory Clock values. +# Not all tokens will be reported on all GPUs, and additional tokens +# may be added in the future. +# For backwards compatibility we still provide nvclock, memclock, and +# processorclock those are the same as nvclockmin, memclockmin and +# processorclockmin. +# +# Note: These clock values take into account the offset +# set by clients through NV_CTRL_GPU_NVCLOCK_OFFSET and +# NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET. +# +# Each performance modes are returned as a comma-separated list of +# "token=value" pairs. Each set of performance mode tokens are separated +# by a ";". Valid tokens: +# +# Token Value +# "perf" integer - the Performance level +# "nvclock" integer - the GPU clocks (in MHz) for the perf level +# "nvclockmin" integer - the GPU clocks min (in MHz) for the perf level +# "nvclockmax" integer - the GPU clocks max (in MHz) for the perf level +# "nvclockeditable" integer - if the GPU clock domain is editable +# for the perf level +# "memclock" integer - the memory clocks (in MHz) for the perf level +# "memclockmin" integer - the memory clocks min (in MHz) for the perf level +# "memclockmax" integer - the memory clocks max (in MHz) for the perf level +# "memclockeditable" integer - if the memory clock domain is editable +# for the perf level +# "memtransferrate" integer - the memory transfer rate (in MHz) +# for the perf level +# "memtransferratemin" integer - the memory transfer rate min (in MHz) +# for the perf level +# "memtransferratemax" integer - the memory transfer rate max (in MHz) +# for the perf level +# "memtransferrateeditable" integer - if the memory transfer rate is editable +# for the perf level +# "processorclock" integer - the processor clocks (in MHz) +# for the perf level +# "processorclockmin" integer - the processor clocks min (in MHz) +# for the perf level +# "processorclockmax" integer - the processor clocks max (in MHz) +# for the perf level +# "processorclockeditable" integer - if the processor clock domain is editable +# for the perf level +# +# Example: +# +# perf=0, nvclock=324, nvclockmin=324, nvclockmax=324, nvclockeditable=0, +# memclock=324, memclockmin=324, memclockmax=324, memclockeditable=0, +# memtransferrate=648, memtransferratemin=648, memtransferratemax=648, +# memtransferrateeditable=0 ; +# perf=1, nvclock=324, nvclockmin=324, nvclockmax=640, nvclockeditable=0, +# memclock=810, memclockmin=810, memclockmax=810, memclockeditable=0, +# memtransferrate=1620, memtransferrate=1620, memtransferrate=1620, +# memtransferrateeditable=0 ; +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_STRING_PERFORMANCE_MODES = 29 # R--G + +# +# NV_CTRL_STRING_VCSC_FAN_STATUS - deprecated +# +# Returns a string with status of all the fans in the Visual Computing System, +# if such a query is supported. Fan information is reported along with its +# tachometer reading (in RPM) and a flag indicating whether the fan has failed +# or not. +# +# Valid tokens: +# +# Token Value +# "fan" integer - the Fan index +# "speed" integer - the tachometer reading of the fan in rpm +# "fail" integer - flag to indicate whether the fan has failed +# +# Example: +# +# fan=0, speed=694, fail=0 ; fan=1, speed=693, fail=0 +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# +# + +NV_CTRL_STRING_VCSC_FAN_STATUS = 30 # R---V + +# +# NV_CTRL_STRING_VCSC_TEMPERATURES - Deprecated +# +# Returns a string with all Temperature readings in the Visual Computing +# System, if such a query is supported. Intake, Exhaust and Board Temperature +# values are reported in Celcius. +# +# Valid tokens: +# +# Token Value +# "intake" integer - the intake temperature for the VCS +# "exhaust" integer - the exhaust temperature for the VCS +# "board" integer - the board temperature of the VCS +# +# Example: +# +# intake=29, exhaust=46, board=41 +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# +# + +NV_CTRL_STRING_VCSC_TEMPERATURES = 31 # R---V + +# +# NV_CTRL_STRING_VCSC_PSU_INFO - Deprecated +# +# Returns a string with all Power Supply Unit related readings in the Visual +# Computing System, if such a query is supported. Current in amperes, Power +# in watts, Voltage in volts and PSU state may be reported. Not all PSU types +# support all of these values, and therefore some readings may be unknown. +# +# Valid tokens: +# +# Token Value +# "current" integer - the current drawn in amperes by the VCS +# "power" integer - the power drawn in watts by the VCS +# "voltage" integer - the voltage reading of the VCS +# "state" integer - flag to indicate whether PSU is operating normally +# +# Example: +# +# current=10, power=15, voltage=unknown, state=normal +# +# This attribute must be queried through XNVCTRLQueryTargetStringAttribute() +# using a NV_CTRL_TARGET_TYPE_VCSC target. +# +# + + +NV_CTRL_STRING_VCSC_PSU_INFO = 32 # R---V + +# +# NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME - query the name for the specified +# NV_CTRL_GVIO_VIDEO_FORMAT_*. So that this can be queried with existing +# interfaces, XNVCTRLQueryStringAttribute() should be used, and the video +# format specified in the display_mask field; eg: +# +# XNVCTRLQueryStringAttribute(dpy, +# screen, +# NV_CTRL_GVIO_VIDEO_FORMAT_720P_60_00_SMPTE296, +# NV_CTRL_GVIO_VIDEO_FORMAT_NAME, +# &name); +# + +NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME = 33 # R--GI + +# +# NV_CTRL_STRING_GVO_VIDEO_FORMAT_NAME - renamed +# +# NV_CTRL_STRING_GVIO_VIDEO_FORMAT_NAME should be used instead. +# +NV_CTRL_STRING_GVO_VIDEO_FORMAT_NAME = 33 # renamed + +# +# NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS - returns a string with the +# associated NV Clock, Memory Clock and Processor Clock values. +# +# Current valid tokens are "nvclock", "nvclockmin", "nvclockmax", +# "memclock", "memclockmin", "memclockmax", "processorclock", +# "processorclockmin" and "processorclockmax". +# Not all tokens will be reported on all GPUs, and additional tokens +# may be added in the future. +# +# Note: These clock values take into account the offset +# set by clients through NV_CTRL_GPU_NVCLOCK_OFFSET and +# NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET. +# +# Clock values are returned as a comma-separated list of +# "token=value" pairs. +# Valid tokens: +# +# Token Value +# "nvclock" integer - the GPU clocks (in MHz) for the perf level +# "nvclockmin" integer - the GPU clocks min (in MHz) for the perf level +# "nvclockmax" integer - the GPU clocks max (in MHz) for the perf level +# "nvclockeditable" integer - if the GPU clock domain is editable +# for the perf level +# "memclock" integer - the memory clocks (in MHz) for the perf level +# "memclockmin" integer - the memory clocks min (in MHz) for the perf level +# "memclockmax" integer - the memory clocks (max in MHz) for the perf level +# "memclockeditable" integer - if the memory clock domain is editable +# for the perf level +# "memtransferrate" integer - the memory transfer rate (in MHz) +# for the perf level +# "memtransferratemin" integer - the memory transfer rate min (in MHz) +# for the perf level +# "memtransferratemax" integer - the memory transfer rate max (in MHz) +# for the perf level +# "memtransferrateeditable" integer - if the memory transfer rate is editable +# for the perf level +# "processorclock" integer - the processor clocks (in MHz) +# for the perf level +# "processorclockmin" integer - the processor clocks min (in MHz) +# for the perf level +# "processorclockmax" integer - the processor clocks max (in MHz) +# for the perf level +# "processorclockeditable" integer - if the processor clock domain is editable +# for the perf level +# +# Example: +# +# nvclock=324, nvclockmin=324, nvclockmax=324, nvclockeditable=0 +# memclock=324, memclockmin=324, memclockmax=324, memclockeditable=0 +# memtrasferrate=628 +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using an NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS = 34 # RW-G + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_HARDWARE_REVISION - Returns the +# hardware revision of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_HARDWARE_REVISION = 35 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_A - Returns the +# firmware version of chip A of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_A = 36 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_A - Returns the +# date of the firmware of chip A of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_A = 37 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_B - Returns the +# firmware version of chip B of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_VERSION_B = 38 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_B - Returns the +# date of the firmware of chip B of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_FIRMWARE_DATE_B = 39 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_ADDRESS - Returns the RF address +# of the 3D Vision Pro transceiver. +# +NV_CTRL_STRING_3D_VISION_PRO_TRANSCEIVER_ADDRESS = 40 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_VERSION_A - Returns the +# firmware version of chip A of the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_VERSION_A = 41 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_DATE_A - Returns the +# date of the firmware of chip A of the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_STRING_3D_VISION_PRO_GLASSES_FIRMWARE_DATE_A = 42 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_GLASSES_ADDRESS - Returns the RF address +# of the glasses. +# Use the display_mask parameter to specify the glasses id. +# +NV_CTRL_STRING_3D_VISION_PRO_GLASSES_ADDRESS = 43 # R--T + +# +# NV_CTRL_STRING_3D_VISION_PRO_GLASSES_NAME - Controls the name the +# glasses should use. +# Use the display_mask parameter to specify the glasses id. +# Glasses' name should start and end with an alpha-numeric character. +# +NV_CTRL_STRING_3D_VISION_PRO_GLASSES_NAME = 44 # RW-T + +# +# NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2 - Returns the metamode currently +# being used by the specified X screen. The MetaMode string has the same +# syntax as the MetaMode X configuration option, as documented in the NVIDIA +# driver README. Also, see NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 for more +# details on the base syntax. +# +# The returned string may also be prepended with a comma-separated list of +# "token=value" pairs, separated from the MetaMode string by "::". +# +NV_CTRL_STRING_CURRENT_METAMODE_VERSION_2 = 45 # RW-- + +# +# NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME - Returns a type name for the +# display device ("CRT", "DFP", or "TV"). However, note that the determination +# of the name is based on the protocol through which the X driver communicates +# to the display device. E.g., if the driver communicates using VGA ,then the +# basename is "CRT"; if the driver communicates using TMDS, LVDS, or DP, then +# the name is "DFP". +# +NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME = 46 # R-D- + +# +# NV_CTRL_STRING_DISPLAY_NAME_TYPE_ID - Returns the type-based name + ID for +# the display device, e.g. "CRT-0", "DFP-1", "TV-2". If this device is a +# DisplayPort multistream device, then this name will also be prepended with the +# device's port address like so: "DFP-1.0.1.2.3". See +# NV_CTRL_STRING_DISPLAY_NAME_TYPE_BASENAME for more information about the +# construction of type-based names. +# +NV_CTRL_STRING_DISPLAY_NAME_TYPE_ID = 47 # R-D- + +# +# NV_CTRL_STRING_DISPLAY_NAME_DP_GUID - Returns the GUID of the DisplayPort +# display device. e.g. "DP-GUID-f16a5bde-79f3-11e1-b2ae-8b5a8969ba9c" +# +# The display device must be a DisplayPort 1.2 device. +# +NV_CTRL_STRING_DISPLAY_NAME_DP_GUID = 48 # R-D- + +# +# NV_CTRL_STRING_DISPLAY_NAME_EDID_HASH - Returns the SHA-1 hash of the +# display device's EDID in 8-4-4-4-12 UID format. e.g. +# "DPY-EDID-f16a5bde-79f3-11e1-b2ae-8b5a8969ba9c" +# +# The display device must have a valid EDID. +# +NV_CTRL_STRING_DISPLAY_NAME_EDID_HASH = 49 # R-D- + +# +# NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX - Returns the current NV-CONTROL +# target ID (name) of the display device. e.g. "DPY-1", "DPY-4" +# +# This name for the display device is not guarenteed to be the same between +# different runs of the X server. +# +NV_CTRL_STRING_DISPLAY_NAME_TARGET_INDEX = 50 # R-D- + +# +# NV_CTRL_STRING_DISPLAY_NAME_RANDR - Returns the RandR output name for the +# display device. e.g. "VGA-1", "DVI-I-0", "DVI-D-3", "LVDS-1", "DP-2", +# "HDMI-3", "eDP-6". This name should match If this device is a DisplayPort +# 1.2 device, then this name will also be prepended with the device's port +# address like so: "DVI-I-3.0.1.2.3" +# +NV_CTRL_STRING_DISPLAY_NAME_RANDR = 51 # R-D- + +# +# NV_CTRL_STRING_GPU_UUID - Returns the UUID of the given GPU. +# +NV_CTRL_STRING_GPU_UUID = 52 # R--G + +# +# NV_CTRL_STRING_GPU_UTILIZATION - Returns the current percentage usage +# of the various components of the GPU. +# +# Current valid tokens are "graphics", "memory", "video" and "PCIe". +# Not all tokens will be reported on all GPUs, and additional tokens +# may be added in the future. +# +# Utilization values are returned as a comma-separated list of +# "token=value" pairs. +# Valid tokens: +# +# Token Value +# "graphics" integer - the percentage usage of graphics engine. +# "memory" integer - the percentage usage of FB. +# "video" integer - the percentage usage of video engine. +# "PCIe" integer - the percentage usage of PCIe bandwidth. +# +# +# Example: +# +# graphics=45, memory=6, video=0, PCIe=0 +# +# This attribute may be queried through XNVCTRLQueryTargetStringAttribute() +# using an NV_CTRL_TARGET_TYPE_GPU. +# +NV_CTRL_STRING_GPU_UTILIZATION = 53 # R--G + +# +# NV_CTRL_STRING_MULTIGPU_MODE - returns a string describing the current +# MULTIGPU mode, if any, or FALSE if MULTIGPU is not currently enabled. +# +NV_CTRL_STRING_MULTIGPU_MODE = 54 # R--- + +# +# NV_CTRL_STRING_PRIME_OUTPUTS_DATA - returns a semicolon delimited list of +# strings that describe all PRIME configured displays. +# +# ex. "xpos=1920, ypos=0, width=1280, height=1024, screen=0;xpos=3200, +# ypos=0, width=800, height=600, screen=0;" +# +NV_CTRL_STRING_PRIME_OUTPUTS_DATA = 55 # R--- + +NV_CTRL_STRING_LAST_ATTRIBUTE = NV_CTRL_STRING_PRIME_OUTPUTS_DATA + +############################################################################ + +# +# Binary Data Attributes: +# +# Binary data attributes can be queryied through the XNVCTRLQueryBinaryData() +# and XNVCTRLQueryTargetBinaryData() function calls. +# +# There are currently no binary data attributes that can be set. +# +# Unless otherwise noted, all Binary data attributes can be queried +# using an NV_CTRL_TARGET_TYPE_X_SCREEN target. Attributes that cannot take +# an NV_CTRL_TARGET_TYPE_X_SCREEN target also cannot be queried through +# XNVCTRLQueryBinaryData() (Since an X Screen target is assumed). +# + + +# +# NV_CTRL_BINARY_DATA_EDID - Returns a display device's EDID information +# data. +# +# This attribute may be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_BINARY_DATA_EDID = 0 # R-DG + +# +# NV_CTRL_BINARY_DATA_MODELINES - Returns a display device's supported +# ModeLines. ModeLines are returned in a buffer, separated by a single +# '\0' and terminated by two consecutive '\0' s like so: +# +# "ModeLine 1\0ModeLine 2\0ModeLine 3\0Last ModeLine\0\0" +# +# This attribute may be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU or NV_CTRL_TARGET_TYPE_X_SCREEN target. +# +# Each ModeLine string may be prepended with a comma-separated list +# of "token=value" pairs, separated from the ModeLine string with a +# "::". Valid tokens: +# +# Token Value +# "source" "xserver" - the ModeLine is from the core X server +# "xconfig" - the ModeLine was specified in the X config file +# "builtin" - the NVIDIA driver provided this builtin ModeLine +# "vesa" - this is a VESA standard ModeLine +# "edid" - the ModeLine was in the display device's EDID +# "nv-control" - the ModeLine was specified via NV-CONTROL +# +# "xconfig-name" - for ModeLines that were specified in the X config +# file, this is the name the X config file +# gave for the ModeLine. +# +# Note that a ModeLine can have several sources; the "source" token +# can appear multiple times in the "token=value" pairs list. +# Additional source values may be specified in the future. +# +# Additional tokens may be added in the future, so it is recommended +# that any token parser processing the returned string from +# NV_CTRL_BINARY_DATA_MODELINES be implemented to gracefully ignore +# unrecognized tokens. +# +# E.g., +# +# "source=xserver, source=vesa, source=edid :: "1024x768_70" 75.0 1024 1048 1184 1328 768 771 777 806 -HSync -VSync" +# "source=xconfig, xconfig-name=1600x1200_60.00 :: "1600x1200_60_0" 161.0 1600 1704 1880 2160 1200 1201 1204 1242 -HSync +VSync" +# + +NV_CTRL_BINARY_DATA_MODELINES = 1 # R-DG + +# +# NV_CTRL_BINARY_DATA_METAMODES - Returns an X Screen's supported +# MetaModes. MetaModes are returned in a buffer separated by a +# single '\0' and terminated by two consecutive '\0' s like so: +# +# "MetaMode 1\0MetaMode 2\0MetaMode 3\0Last MetaMode\0\0" +# +# The MetaMode string should have the same syntax as the MetaMode X +# configuration option, as documented in the NVIDIA driver README. + +# Each MetaMode string may be prepended with a comma-separated list +# of "token=value" pairs, separated from the MetaMode string with +# "::". Currently, valid tokens are: +# +# Token Value +# "id" - the id of this MetaMode; this is stored in +# the Vertical Refresh field, as viewed +# by the XRandR and XF86VidMode X# +# extensions. +# +# "switchable" "yes"/"no" - whether this MetaMode may be switched to via +# ctrl-alt-+/-; Implicit MetaModes (see +# the "IncludeImplicitMetaModes" X +# config option), for example, are not +# normally made available through +# ctrl-alt-+/-. +# +# "source" "xconfig" - the MetaMode was specified in the X +# config file. +# "implicit" - the MetaMode was implicitly added; see the +# "IncludeImplicitMetaModes" X config option +# for details. +# "nv-control" - the MetaMode was added via the NV-CONTROL X +# extension to the currently running X server. +# "RandR" - the MetaMode was modified in response to an +# RandR RRSetCrtcConfig request. +# +# Additional tokens may be added in the future, so it is recommended +# that any token parser processing the returned string from +# NV_CTRL_BINARY_DATA_METAMODES be implemented to gracefully ignore +# unrecognized tokens. +# +# E.g., +# +# "id=50, switchable=yes, source=xconfig :: CRT-0: 1024x768 @1024x768 +0+0" +# + +NV_CTRL_BINARY_DATA_METAMODES = 2 # R-D- +NV_CTRL_BINARY_DATA_METAMODES_VERSION_1 = NV_CTRL_BINARY_DATA_METAMODES + +# +# NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU - Returns the list of X +# screens currently driven by the given GPU. +# +# The format of the returned data is: +# +# 4 CARD32 number of screens +# 4# n CARD32 screen indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. +# + +NV_CTRL_BINARY_DATA_XSCREENS_USING_GPU = 3 # R-DG + +# +# NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN - Returns the list of GPUs +# currently in use by the given X screen. +# +# The format of the returned data is: +# +# 4 CARD32 number of GPUs +# 4# n CARD32 GPU indices +# + +NV_CTRL_BINARY_DATA_GPUS_USED_BY_XSCREEN = 4 # R--- + +# +# NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK - Returns the list of +# GPUs currently connected to the given frame lock board. +# +# The format of the returned data is: +# +# 4 CARD32 number of GPUs +# 4# n CARD32 GPU indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_FRAMELOCK target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. +# + +NV_CTRL_BINARY_DATA_GPUS_USING_FRAMELOCK = 5 # R-DF + +# +# NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT - Returns the Display Device's +# viewport box into the given X Screen (in X Screen coordinates.) +# +# The format of the returned data is: +# +# 4 CARD32 Offset X +# 4 CARD32 Offset Y +# 4 CARD32 Width +# 4 CARD32 Height +# + +NV_CTRL_BINARY_DATA_DISPLAY_VIEWPORT = 6 # R-DG + +# +# NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU - Returns the list of +# Framelock devices currently connected to the given GPU. +# +# The format of the returned data is: +# +# 4 CARD32 number of Framelocks +# 4# n CARD32 Framelock indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN. +# + +NV_CTRL_BINARY_DATA_FRAMELOCKS_USED_BY_GPU = 7 # R-DG + +# +# NV_CTRL_BINARY_DATA_GPUS_USING_VCSC - Deprecated +# +# Returns the list of GPU devices connected to the given VCS. +# +# The format of the returned data is: +# +# 4 CARD32 number of GPUs +# 4# n CARD32 GPU indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_VCSC target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN and cannot be queried using +# a NV_CTRL_TARGET_TYPE_X_GPU +# + +NV_CTRL_BINARY_DATA_GPUS_USING_VCSC = 8 # R-DV + +# +# NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU - Deprecated +# +# Returns the VCSC device that is controlling the given GPU. +# +# The format of the returned data is: +# +# 4 CARD32 number of VCS (always 1) +# 4# n CARD32 VCS indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN +# + +NV_CTRL_BINARY_DATA_VCSCS_USED_BY_GPU = 9 # R-DG + +# +# NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU - Returns the coolers that +# are cooling the given GPU. +# +# The format of the returned data is: +# +# 4 CARD32 number of COOLER +# 4# n CARD32 COOLER indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN +# + +NV_CTRL_BINARY_DATA_COOLERS_USED_BY_GPU = 10 # R-DG + +# +# NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN - Returns the list of +# GPUs currently driving the given X screen. If Xinerama is enabled, this +# will return all GPUs that are driving any X screen. +# +# The format of the returned data is: +# +# 4 CARD32 number of GPUs +# 4# n CARD32 GPU indices +# + +NV_CTRL_BINARY_DATA_GPUS_USED_BY_LOGICAL_XSCREEN = 11 # R--- + +# +# NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU - Returns the sensors that +# are attached to the given GPU. +# +# The format of the returned data is: +# +# 4 CARD32 number of SENSOR +# 4# n CARD32 SENSOR indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. This attribute cannot be +# queried using a NV_CTRL_TARGET_TYPE_X_SCREEN +# + +NV_CTRL_BINARY_DATA_THERMAL_SENSORS_USED_BY_GPU = 12 # R--G + +# +# NV_CTRL_BINARY_DATA_GLASSES_PAIRED_TO_3D_VISION_PRO_TRANSCEIVER - Returns +# the id of the glasses that are currently paired to the given +# 3D Vision Pro transceiver. +# +# The format of the returned data is: +# +# 4 CARD32 number of glasses +# 4# n CARD32 id of glasses +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER target. +# +NV_CTRL_BINARY_DATA_GLASSES_PAIRED_TO_3D_VISION_PRO_TRANSCEIVER = 13 # R--T + +# +# NV_CTRL_BINARY_DATA_DISPLAY_TARGETS - Returns all the display devices +# currently connected to any GPU on the X server. +# +# The format of the returned data is: +# +# 4 CARD32 number of display devices +# 4# n CARD32 display device indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData(). +# + +NV_CTRL_BINARY_DATA_DISPLAY_TARGETS = 14 # R--- + +# +# NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU - Returns the list of +# display devices that are connected to the GPU target. +# +# The format of the returned data is: +# +# 4 CARD32 number of display devices +# 4# n CARD32 display device indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. +# + +NV_CTRL_BINARY_DATA_DISPLAYS_CONNECTED_TO_GPU = 15 # R--G + +# +# NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 - Returns values similar to +# NV_CTRL_BINARY_DATA_METAMODES(_VERSION_1) but also returns extended syntax +# information to indicate a specific display device, as well as other per- +# display deviceflags as "token=value" pairs. For example: +# +# "DPY-1: 1280x1024 {Stereo=PassiveLeft}, +# DPY-2: 1280x1024 {Stereo=PassiveRight}," +# +# The display device names have the form "DPY-%d", where the integer +# part of the name is the NV-CONTROL target ID for that display device +# for this instance of the X server. Note that display device NV-CONTROL +# target IDs are not guaranteed to be the same from one run of the X +# server to the next. +# + +NV_CTRL_BINARY_DATA_METAMODES_VERSION_2 = 16 # R-D- + +# +# NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN - Returns the list of +# display devices that are currently scanning out the X screen target. +# +# The format of the returned data is: +# +# 4 CARD32 number of display devices +# 4# n CARD32 display device indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_BINARY_DATA_DISPLAYS_ENABLED_ON_XSCREEN = 17 # R--- + +# +# NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN - Returns the list of +# display devices that are currently assigned the X screen target. +# +# The format of the returned data is: +# +# 4 CARD32 number of display devices +# 4# n CARD32 display device indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + +NV_CTRL_BINARY_DATA_DISPLAYS_ASSIGNED_TO_XSCREEN = 18 # R--- + +# +# NV_CTRL_BINARY_DATA_GPU_FLAGS - Returns a list of flags for the +# given GPU. A flag can, for instance, be a capability which enables +# or disables some features according to the GPU state. +# +# The format of the returned data is: +# +# 4 CARD32 number of GPU flags +# 4# n CARD32 GPU flag +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. +# +NV_CTRL_BINARY_DATA_GPU_FLAGS = 19 # R--- + +# Stereo and display composition transformations are mutually exclusive. +NV_CTRL_BINARY_DATA_GPU_FLAGS_STEREO_DISPLAY_TRANSFORM_EXCLUSIVE = 0 +# Overlay and display composition transformations are mutually exclusive. +NV_CTRL_BINARY_DATA_GPU_FLAGS_OVERLAY_DISPLAY_TRANSFORM_EXCLUSIVE = 1 +# Depth 8 and display composition transformations are mutually exclusive. +NV_CTRL_BINARY_DATA_GPU_FLAGS_DEPTH_8_DISPLAY_TRANSFORM_EXCLUSIVE = 2 + +# +# NV_CTRL_BINARY_DATA_DISPLAYS_ON_GPU - Returns the list of valid +# display devices that can be connected to the GPU target. +# +# The format of the returned data is: +# +# 4 CARD32 number of display devices +# 4# n CARD32 display device indices +# +# This attribute can only be queried through XNVCTRLQueryTargetBinaryData() +# using a NV_CTRL_TARGET_TYPE_GPU target. +# + +NV_CTRL_BINARY_DATA_DISPLAYS_ON_GPU = 20 # R--G + +NV_CTRL_BINARY_DATA_LAST_ATTRIBUTE = NV_CTRL_BINARY_DATA_DISPLAYS_ON_GPU + +############################################################################ + +# +# String Operation Attributes: +# +# These attributes are used with the XNVCTRLStringOperation() +# function; a string is specified as input, and a string is returned +# as output. +# +# Unless otherwise noted, all attributes can be operated upon using +# an NV_CTRL_TARGET_TYPE_X_SCREEN target. +# + + +# +# NV_CTRL_STRING_OPERATION_ADD_METAMODE - provide a MetaMode string +# as input, and returns a string containing comma-separated list of +# "token=value" pairs as output. Currently, the only output token is +# "id", which indicates the id that was assigned to the MetaMode. +# +# All ModeLines referenced in the MetaMode must already exist for +# each display device (as returned by the +# NV_CTRL_BINARY_DATA_MODELINES attribute). +# +# The MetaMode string should have the same syntax as the MetaMode X +# configuration option, as documented in the NVIDIA driver README. +# +# The input string can optionally be prepended with a string of +# comma-separated "token=value" pairs, separated from the MetaMode +# string by "::". Currently, the only valid token is "index" which +# indicates the insertion index for the MetaMode. +# +# E.g., +# +# Input: "index=5 :: 1600x1200+0+0, 1600x1200+1600+0" +# Output: "id=58" +# +# which causes the MetaMode to be inserted at position 5 in the +# MetaMode list (all entries after 5 will be shifted down one slot in +# the list), and the X server's containing mode stores 58 as the +# VRefresh, so that the MetaMode can be uniquely identifed through +# XRandR and XF86VidMode. +# + +NV_CTRL_STRING_OPERATION_ADD_METAMODE = 0 # ---- + +# +# NV_CTRL_STRING_OPERATION_GTF_MODELINE - provide as input a string +# of comma-separated "token=value" pairs, and returns a ModeLine +# string, computed using the GTF formula using the parameters from +# the input string. Valid tokens for the input string are "width", +# "height", and "refreshrate". +# +# E.g., +# +# Input: "width=1600, height=1200, refreshrate=60" +# Output: "160.96 1600 1704 1880 2160 1200 1201 1204 1242 -HSync +VSync" +# +# This operation does not have any impact on any display device's +# modePool, and the ModeLine is not validated; it is simply intended +# for generating ModeLines. +# + +NV_CTRL_STRING_OPERATION_GTF_MODELINE = 1 # --- + +# +# NV_CTRL_STRING_OPERATION_CVT_MODELINE - provide as input a string +# of comma-separated "token=value" pairs, and returns a ModeLine +# string, computed using the CVT formula using the parameters from +# the input string. Valid tokens for the input string are "width", +# "height", "refreshrate", and "reduced-blanking". The +# "reduced-blanking" argument can be "0" or "1", to enable or disable +# use of reduced blanking for the CVT formula. +# +# E.g., +# +# Input: "width=1600, height=1200, refreshrate=60, reduced-blanking=1" +# Output: "130.25 1600 1648 1680 1760 1200 1203 1207 1235 +HSync -VSync" +# +# This operation does not have any impact on any display device's +# modePool, and the ModeLine is not validated; it is simply intended +# for generating ModeLines. +# + +NV_CTRL_STRING_OPERATION_CVT_MODELINE = 2 # --- + +# +# NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL - build a ModePool for the +# specified display device on the specified target (either an X +# screen or a GPU). This is typically used to generate a ModePool +# for a display device on a GPU on which no X screens are present. +# +# Currently, a display device's ModePool is static for the life of +# the X server, so XNVCTRLStringOperation will return FALSE if +# requested to build a ModePool on a display device that already has +# a ModePool. +# +# The string input to BUILD_MODEPOOL may be NULL. If it is not NULL, +# then it is interpreted as a double-colon ("::") separated list +# of "option=value" pairs, where the options and the syntax of their +# values are the X configuration options that impact the behavior of +# modePool construction; namely: +# +# "ModeValidation" +# "HorizSync" +# "VertRefresh" +# "FlatPanelProperties" +# "ExactModeTimingsDVI" +# "UseEdidFreqs" +# +# An example input string might look like: +# +# "ModeValidation=NoVesaModes :: HorizSync=50-110 :: VertRefresh=50-150" +# +# This request currently does not return a string. +# + +NV_CTRL_STRING_OPERATION_BUILD_MODEPOOL = 3 # DG + +# +# NV_CTRL_STRING_OPERATION_GVI_CONFIGURE_STREAMS - Configure the streams- +# to-jack+channel topology for a GVI (Graphics capture board). +# +# The string input to GVI_CONFIGURE_STREAMS may be NULL. If this is the +# case, then the current topology is returned. +# +# If the input string to GVI_CONFIGURE_STREAMS is not NULL, the string +# is interpreted as a semicolon (";") separated list of comma-separated +# lists of "option=value" pairs that define a stream's composition. The +# available options and their values are: +# +# "stream": Defines which stream this comma-separated list describes. +# Valid values are the integers between 0 and +# NV_CTRL_GVI_NUM_STREAMS-1 (inclusive). +# +# "linkN": Defines a jack+channel pair to use for the given link N. +# Valid options are the string "linkN", where N is an integer +# between 0 and NV_CTRL_GVI_MAX_LINKS_PER_STREAM-1 (inclusive). +# Valid values for these options are strings of the form +# "jackX" and/or "jackX.Y", where X is an integer between 0 and +# NV_CTRL_GVI_NUM_JACKS-1 (inclusive), and Y (optional) is an +# integer between 0 and NV_CTRL_GVI_MAX_CHANNELS_PER_JACK-1 +# (inclusive). +# +# An example input string might look like: +# +# "stream=0, link0=jack0, link1=jack1; stream=1, link0=jack2.1" +# +# This example specifies two streams, stream 0 and stream 1. Stream 0 +# is defined to capture link0 data from the first channel (channel 0) of +# BNC jack 0 and link1 data from the first channel of BNC jack 1. The +# second stream (Stream 1) is defined to capture link0 data from channel 1 +# (second channel) of BNC jack 2. +# +# This example shows a possible configuration for capturing 3G input: +# +# "stream=0, link0=jack0.0, link1=jack0.1" +# +# Applications should query the following attributes to determine +# possible combinations: +# +# NV_CTRL_GVI_MAX_STREAMS +# NV_CTRL_GVI_MAX_LINKS_PER_STREAM +# NV_CTRL_GVI_NUM_JACKS +# NV_CTRL_GVI_MAX_CHANNELS_PER_JACK +# +# Note: A jack+channel pair can only be tied to one link/stream. +# +# Upon successful configuration or querying of this attribute, a string +# representing the current topology for all known streams on the device +# will be returned. On failure, NULL is returned. +# +# Note: Setting this attribute may also result in the following +# NV-CONTROL attributes being reset on the GVI device (to ensure +# the configuration remains valid): +# NV_CTRL_GVIO_REQUESTED_VIDEO_FORMAT +# NV_CTRL_GVI_REQUESTED_STREAM_BITS_PER_COMPONENT +# NV_CTRL_GVI_REQUESTED_STREAM_COMPONENT_SAMPLING +# + +NV_CTRL_STRING_OPERATION_GVI_CONFIGURE_STREAMS = 4 # RW-I + +# +# NV_CTRL_STRING_OPERATION_PARSE_METAMODE - Parses the given MetaMode string +# and returns the validated MetaMode string - possibly re-calculating various +# values such as ViewPortIn. If the MetaMode matches an existing MetaMode, +# the details of the existing MetaMode are returned. If the MetaMode fails to +# be parsed, NULL is returned. +# +NV_CTRL_STRING_OPERATION_PARSE_METAMODE = 5 # R--- + +NV_CTRL_STRING_OPERATION_LAST_ATTRIBUTE = NV_CTRL_STRING_OPERATION_PARSE_METAMODE + +############################################################################### +# NV-CONTROL major op numbers. these constants identify the request type +# +X_nvCtrlQueryExtension = 0 +X_nvCtrlQueryAttribute = 2 +X_nvCtrlQueryStringAttribute = 4 +X_nvCtrlQueryValidAttributeValues = 5 +X_nvCtrlSetStringAttribute = 9 +X_nvCtrlSetAttributeAndGetStatus = 19 +X_nvCtrlQueryBinaryData = 20 +X_nvCtrlQueryTargetCount = 24 +X_nvCtrlStringOperation = 25 + +############################################################################### +# various lists that go with attrs, but are handled more compactly +# this way. these lists are indexed by the possible values of their attrs +# and are explained in NVCtrl.h +# + +ATTRIBUTE_TYPE_UNKNOWN = 0 +ATTRIBUTE_TYPE_INTEGER = 1 +ATTRIBUTE_TYPE_BITMASK = 2 +ATTRIBUTE_TYPE_BOOL = 3 +ATTRIBUTE_TYPE_RANGE = 4 +ATTRIBUTE_TYPE_INT_BITS = 5 + +ATTRIBUTE_TYPE_READ = 0x01 +ATTRIBUTE_TYPE_WRITE = 0x02 +ATTRIBUTE_TYPE_DISPLAY = 0x04 +ATTRIBUTE_TYPE_GPU = 0x08 +ATTRIBUTE_TYPE_FRAMELOCK = 0x10 +ATTRIBUTE_TYPE_X_SCREEN = 0x20 +ATTRIBUTE_TYPE_XINERAMA = 0x40 +ATTRIBUTE_TYPE_VCSC = 0x80 + +############################################################################ + +# +# Attribute Targets +# +# Targets define attribute groups. For example, some attributes are only +# valid to set on a GPU, others are only valid when talking about an +# X Screen. Target types are then what is used to identify the target +# group of the attribute you wish to set/query. +# +# Here are the supported target types: +# + +NV_CTRL_TARGET_TYPE_X_SCREEN = 0 +NV_CTRL_TARGET_TYPE_GPU = 1 +NV_CTRL_TARGET_TYPE_FRAMELOCK = 2 +# Visual Computing System - deprecated. To be removed along with all +# VCS-specific attributes in a later release. +NV_CTRL_TARGET_TYPE_VCSC = 3 +NV_CTRL_TARGET_TYPE_GVI = 4 +NV_CTRL_TARGET_TYPE_COOLER = 5 # e.g., fan +NV_CTRL_TARGET_TYPE_THERMAL_SENSOR = 6 +NV_CTRL_TARGET_TYPE_3D_VISION_PRO_TRANSCEIVER = 7 +NV_CTRL_TARGET_TYPE_DISPLAY = 8 + + +############################################################################### +# Targets, to indicate where a command should be executed. +# +class Target(object): + def __init__(self): + self._id = -1 + self._type = -1 + self._name = '' + + def id(self): + return self._id + + def type(self): + return self._type + + def __str__(self): + return ''.format(self._name, self.id()) + + +class Gpu(Target): + def __init__(self, ngpu=0): + """Target a GPU""" + super(self.__class__, self).__init__() + self._id = ngpu + self._type = NV_CTRL_TARGET_TYPE_GPU + self._name = 'GPU' + + +class Screen(Target): + def __init__(self, nscr=0): + """Target an X screen""" + super(self.__class__, self).__init__() + self._id = nscr + self._type = NV_CTRL_TARGET_TYPE_X_SCREEN + self._name = 'X screen' + + +class Cooler(Target): + def __init__(self, nfan=0): + """Target a fann""" + super(self.__class__, self).__init__() + self._id = nfan + self._type = NV_CTRL_TARGET_TYPE_COOLER + self._name = 'Cooler' + + +class NVCtrlQueryTargetCountReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryTargetCount), + rq.RequestLength(), + rq.Card32('target_type'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('padb1'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('count'), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + rq.Card32('pad8'), + ) + + +class NVCtrlQueryAttributeReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryAttribute), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Int32('value'), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + ) + + +class NVCtrlSetAttributeAndGetStatusReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlSetAttributeAndGetStatus), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + rq.Int32('value') + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Card32('pad3'), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + ) + + +class NVCtrlQueryStringAttributeReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryStringAttribute), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Card32('string', 4), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + rq.String8('string'), + ) + + +class NVCtrlQueryValidAttributeValuesReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryValidAttributeValues), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Int32('attr_type'), + rq.Int32('min'), + rq.Int32('max'), + rq.Card32('bits'), + rq.Card32('perms'), + ) + + +class NVCtrlQueryBinaryDataReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryBinaryData), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Card32('data', 4), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + rq.Binary('data'), + ) + + +class NVCtrlQueryListCard32ReplyRequest(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(X_nvCtrlQueryBinaryData), + rq.RequestLength(), + rq.Card16('target_id'), + rq.Card16('target_type'), + rq.Card32('display_mask'), + rq.Card32('attr'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('pad0'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('flags'), + rq.Card32('list', 4), + rq.Card32('pad4'), + rq.Card32('pad5'), + rq.Card32('pad6'), + rq.Card32('pad7'), + rq.List('list', rq.Card32), + ) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/randr.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/randr.py new file mode 100644 index 0000000..8149c48 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/randr.py @@ -0,0 +1,1292 @@ +# Xlib.ext.randr -- RandR extension module +# +# Copyright (C) 2006 Mike Meyer +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +"""RandR - provide access to the RandR extension information. + +This implementation is based off version 1.5 of the XRandR protocol, and may +not be compatible with other versions. + +Version 1.5 of the protocol is documented at: +http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt + +Version 1.3.1 here: +http://www.x.org/releases/X11R7.5/doc/randrproto/randrproto.txt + +""" + + +from Xlib import X +from Xlib.protocol import rq + +extname = 'RANDR' + + +# Event codes # +RRScreenChangeNotify = 0 + +# V1.2 additions +RRNotify = 1 + +# RRNotify Subcodes +RRNotify_CrtcChange = 0 +RRNotify_OutputChange = 1 +RRNotify_OutputProperty = 2 + + +# Event selection bits # +RRScreenChangeNotifyMask = (1 << 0) + +# V1.2 additions +RRCrtcChangeNotifyMask = (1 << 1) +RROutputChangeNotifyMask = (1 << 2) +RROutputPropertyNotifyMask = (1 << 3) + + +# Constants # +SetConfigSuccess = 0 +SetConfigInvalidConfigTime = 1 +SetConfigInvalidTime = 2 +SetConfigFailed = 3 + +# used in the rotation field; rotation and reflection in 0.1 proto. +Rotate_0 = 1 +Rotate_90 = 2 +Rotate_180 = 4 +Rotate_270 = 8 + +# new in 1.0 protocol, to allow reflection of screen +Reflect_X = 16 +Reflect_Y = 32 + +# new in 1.2 protocol +HSyncPositive = 0x00000001 +HSyncNegative = 0x00000002 +VSyncPositive = 0x00000004 +VSyncNegative = 0x00000008 +Interlace = 0x00000010 +DoubleScan = 0x00000020 +CSync = 0x00000040 +CSyncPositive = 0x00000080 +CSyncNegative = 0x00000100 +HSkewPresent = 0x00000200 +BCast = 0x00000400 +PixelMultiplex = 0x00000800 +DoubleClock = 0x00001000 +ClockDivideBy2 = 0x00002000 + +# event types? +Connected = 0 +Disconnected = 1 +UnknownConnection = 2 + +# Conventional RandR output properties +PROPERTY_RANDR_EDID = "EDID" +PROPERTY_SIGNAL_FORMAT = "SignalFormat" +PROPERTY_SIGNAL_PROPERTIES = "SignalProperties" +PROPERTY_CONNECTOR_TYPE = "ConnectorType" +PROPERTY_CONNECTOR_NUMBER = "ConnectorNumber" +PROPERTY_COMPATIBILITY_LIST = "CompatibilityList" +PROPERTY_CLONE_LIST = "CloneList" + +# subpixel order - TODO: These constants are part of the RENDER extension and +# should be moved there if/when that extension is added to python-xlib. +SubPixelUnknown = 0 +SubPixelHorizontalRGB = 1 +SubPixelHorizontalBGR = 2 +SubPixelVerticalRGB = 3 +SubPixelVerticalBGR = 4 +SubPixelNone = 5 + + +# Error Codes # +BadRROutput = 0 +BadRRCrtc = 1 +BadRRMode = 2 + +# Error classes # +class BadRROutputError(Exception): pass + +class BadRRCrtcError(Exception): pass + +class BadRRModeError(Exception): pass + +# Data Structures # + +RandR_ScreenSizes = rq.Struct( + rq.Card16('width_in_pixels'), + rq.Card16('height_in_pixels'), + rq.Card16('width_in_millimeters'), + rq.Card16('height_in_millimeters'), + ) + + +RandR_ModeInfo = rq.Struct( + rq.Card32('id'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card32('dot_clock'), + rq.Card16('h_sync_start'), + rq.Card16('h_sync_end'), + rq.Card16('h_total'), + rq.Card16('h_skew'), + rq.Card16('v_sync_start'), + rq.Card16('v_sync_end'), + rq.Card16('v_total'), + rq.Card16('name_length'), + rq.Card32('flags'), + ) + +RandR_Rates = rq.Struct( + rq.LengthOf('rates', 2), + rq.List('rates', rq.Card16Obj) + ) + +# TODO: This struct is part of the RENDER extension and should be moved there +# if/when that extension is added to python-xlib. +Render_Transform = rq.Struct( + rq.Card32('matrix11'), #FIXME: All of these are listed as FIXED in the protocol header. + rq.Card32('matrix12'), + rq.Card32('matrix13'), + rq.Card32('matrix21'), + rq.Card32('matrix22'), + rq.Card32('matrix23'), + rq.Card32('matrix31'), + rq.Card32('matrix32'), + rq.Card32('matrix33'), + ) + +MonitorInfo = rq.Struct( + rq.Card32('name'), + rq.Bool('primary'), + rq.Bool('automatic'), + rq.LengthOf('crtcs', 2), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width_in_pixels'), + rq.Card16('height_in_pixels'), + rq.Card32('width_in_millimeters'), + rq.Card32('height_in_millimeters'), + rq.List('crtcs', rq.Card32Obj) +) + +# Requests # + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + rq.Pad(16), + ) + +def query_version(self): + """Get the current version of the RandR extension. + + """ + return QueryVersion( + display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=5, + ) + + +class _1_0SetScreenConfig(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.Card16('size_id'), + rq.Card16('rotation'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('new_timestamp'), + rq.Card32('new_config_timestamp'), + rq.Window('root'), + rq.Card16('subpixel_order'), + rq.Pad(10), + ) + +def _1_0set_screen_config(self, size_id, rotation, config_timestamp, timestamp=X.CurrentTime): + """Sets the screen to the specified size and rotation. + + """ + return _1_0SetScreenConfig( + display=self.display, + opcode=self.display.get_extension_major(extname), + drawable=self, + timestamp=timestamp, + config_timestamp=config_timestamp, + size_id=size_id, + rotation=rotation, + ) + + +class SetScreenConfig(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.Card16('size_id'), + rq.Card16('rotation'), + rq.Card16('rate'), # added in version 1.1 + rq.Pad(2), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('new_timestamp'), + rq.Card32('new_config_timestamp'), + rq.Window('root'), + rq.Card16('subpixel_order'), + rq.Pad(10), + ) + +def set_screen_config(self, size_id, rotation, config_timestamp, rate=0, timestamp=X.CurrentTime): + """Sets the screen to the specified size, rate, rotation and reflection. + + rate can be 0 to have the server select an appropriate rate. + + """ + return SetScreenConfig( + display=self.display, + opcode=self.display.get_extension_major(extname), + drawable=self, + timestamp=timestamp, + config_timestamp=config_timestamp, + size_id=size_id, + rotation=rotation, + rate=rate, + ) + + +class SelectInput(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Window('window'), + rq.Card16('mask'), + rq.Pad(2), + ) + +def select_input(self, mask): + return SelectInput( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + mask=mask, + ) + + +class GetScreenInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('set_of_rotations'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('root'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.LengthOf('sizes', 2), + rq.Card16('size_id'), + rq.Card16('rotation'), + rq.Card16('rate'), # added in version 1.1 + rq.Card16('n_rate_ents'), # XCB's protocol description disagrees with the X headers on this; ignoring. + rq.Pad(2), + rq.List('sizes', RandR_ScreenSizes), + #rq.List('rates', RandR_Rates) #FIXME: Why does uncommenting this cause an error? + ) + +def get_screen_info(self): + """Retrieve information about the current and available configurations for + the screen associated with this window. + + """ + return GetScreenInfo( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + ) + + +# version 1.2 + +class GetScreenSizeRange(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(6), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('min_width'), + rq.Card16('min_height'), + rq.Card16('max_width'), + rq.Card16('max_height'), + rq.Pad(16), + ) + +def get_screen_size_range(self): + """Retrieve the range of possible screen sizes. The screen may be set to + any size within this range. + + """ + return GetScreenSizeRange( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + ) + + +class SetScreenSize(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(7), + rq.RequestLength(), + rq.Window('window'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card32('width_in_millimeters'), + rq.Card32('height_in_millimeters'), + ) + +def set_screen_size(self, width, height, width_in_millimeters=None, height_in_millimeters=None): + return SetScreenSize( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + width=width, + height=height, + width_in_millimeters=width_in_millimeters, + height_in_millimeters=height_in_millimeters, + ) + + +class GetScreenResources(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(8), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.LengthOf('crtcs', 2), + rq.LengthOf('outputs', 2), + rq.LengthOf('modes', 2), + rq.LengthOf('mode_names', 2), + rq.Pad(8), + rq.List('crtcs', rq.Card32Obj), + rq.List('outputs', rq.Card32Obj), + rq.List('modes', RandR_ModeInfo), + rq.String8('mode_names'), + ) + +def get_screen_resources(self): + return GetScreenResources( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + ) + + +class GetOutputInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(9), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('config_timestamp'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.Card32('crtc'), + rq.Card32('mm_width'), + rq.Card32('mm_height'), + rq.Card8('connection'), + rq.Card8('subpixel_order'), + rq.LengthOf('crtcs', 2), + rq.LengthOf('modes', 2), + rq.Card16('num_preferred'), + rq.LengthOf('clones', 2), + rq.LengthOf('name', 2), + rq.List('crtcs', rq.Card32Obj), + rq.List('modes', rq.Card32Obj), + rq.List('clones', rq.Card32Obj), + rq.String8('name'), + ) + +def get_output_info(self, output, config_timestamp): + return GetOutputInfo( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + config_timestamp=config_timestamp, + ) + + +class ListOutputProperties(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(10), + rq.RequestLength(), + rq.Card32('output'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('atoms', 2), + rq.Pad(22), + rq.List('atoms', rq.Card32Obj), + ) + +def list_output_properties(self, output): + return ListOutputProperties ( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + ) + + +class QueryOutputProperty(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(11), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('property'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Bool('pending'), + rq.Bool('range'), + rq.Bool('immutable'), + rq.Pad(21), + rq.List('valid_values', rq.Card32Obj), + ) + +def query_output_property(self, output, property): + return QueryOutputProperty ( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + property=property, + ) + + +class ConfigureOutputProperty (rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(12), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('property'), + rq.Bool('pending'), + rq.Bool('range'), + rq.Pad(2), + rq.List('valid_values', rq.Card32Obj), + ) + +def configure_output_property (self, output, property): + return ConfigureOutputProperty ( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + property=property, + ) + + +class ChangeOutputProperty(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(13), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('property'), + rq.Card32('type'), + rq.Format('value', 1), + rq.Card8('mode'), + rq.Pad(2), + rq.LengthOf('value', 4), + rq.PropertyData('value'), + ) + +def change_output_property(self, output, property, type, mode, value): + return ChangeOutputProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + property=property, + type=type, + mode=mode, + value=value, + ) + + +class DeleteOutputProperty(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(14), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('property'), + ) + +def delete_output_property(self, output, property): + return DeleteOutputProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + property=property, + ) + + +class GetOutputProperty(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(15), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('property'), + rq.Card32('type'), + rq.Card32('long_offset'), + rq.Card32('long_length'), + rq.Bool('delete'), + rq.Bool('pending'), + rq.Pad(2), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Format('value', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('property_type'), + rq.Card32('bytes_after'), + rq.LengthOf('value', 4), + rq.Pad(12), + rq.List('value', rq.Card8Obj), + ) + +def get_output_property(self, output, property, type, long_offset, long_length, delete=False, pending=False): + return GetOutputProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + property=property, + type=type, + long_offset=long_offset, + long_length=long_length, + delete=delete, + pending=pending, + ) + + +class CreateMode(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(16), + rq.RequestLength(), + rq.Window('window'), + rq.Object('mode', RandR_ModeInfo), + rq.String8('name'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('mode'), + rq.Pad(20), + ) + +def create_mode(self, mode, name): + return CreateMode ( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + mode=mode, + name=name, + ) + + +class DestroyMode(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(17), + rq.RequestLength(), + rq.Card32('mode'), + ) + +def destroy_mode(self, mode): + return DestroyMode( + display=self.display, + opcode=self.display.get_extension_major(extname), + mode=mode, + ) + + +class AddOutputMode(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(18), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('mode'), + ) + +def add_output_mode(self, output, mode): + return AddOutputMode( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + mode=mode, + ) + + +class DeleteOutputMode(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(19), + rq.RequestLength(), + rq.Card32('output'), + rq.Card32('mode'), + ) + +def delete_output_mode(self, output, mode): + return DeleteOutputMode( + display=self.display, + opcode=self.display.get_extension_major(extname), + output=output, + mode=mode, + ) + + +class GetCrtcInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(20), + rq.RequestLength(), + rq.Card32('crtc'), + rq.Card32('config_timestamp'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card32('mode'), + rq.Card16('rotation'), + rq.Card16('possible_rotations'), + rq.LengthOf('outputs', 2), + rq.LengthOf('possible_outputs', 2), + rq.List('outputs', rq.Card32Obj), + rq.List('possible_outputs', rq.Card32Obj), + ) + +def get_crtc_info(self, crtc, config_timestamp): + return GetCrtcInfo ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + config_timestamp=config_timestamp, + ) + + +class SetCrtcConfig(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(21), + rq.RequestLength(), + rq.Card32('crtc'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card32('mode'), + rq.Card16('rotation'), + rq.Pad(2), + rq.List('outputs', rq.Card32Obj), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('new_timestamp'), + rq.Pad(20), + ) + +def set_crtc_config(self, crtc, config_timestamp, x, y, mode, rotation, outputs, timestamp=X.CurrentTime): + return SetCrtcConfig ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + config_timestamp=config_timestamp, + x=x, + y=y, + mode=mode, + rotation=rotation, + outputs=outputs, + timestamp=timestamp, + ) + + +class GetCrtcGammaSize(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(22), + rq.RequestLength(), + rq.Card32('crtc'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('size'), + rq.Pad(22), + ) + +def get_crtc_gamma_size(self, crtc): + return GetCrtcGammaSize ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + ) + + +class GetCrtcGamma(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(23), + rq.RequestLength(), + rq.Card32('crtc'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf(('red', 'green', 'blue'), 2), + rq.Pad(22), + rq.List('red', rq.Card16Obj), + rq.List('green', rq.Card16Obj), + rq.List('blue', rq.Card16Obj), + ) + +def get_crtc_gamma(self, crtc): + return GetCrtcGamma ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + ) + + +class SetCrtcGamma(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(24), + rq.RequestLength(), + rq.Card32('crtc'), + rq.Card16('size'), + rq.Pad(2), + rq.List('red', rq.Card16Obj), + rq.List('green', rq.Card16Obj), + rq.List('blue', rq.Card16Obj), + ) + +def set_crtc_gamma(self, crtc, size, red, green, blue): + return SetCrtcGamma( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + size=size, + red=red, + green=green, + blue=blue, + ) + + +# version 1.3 + +class GetScreenResourcesCurrent(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(25), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.LengthOf('crtcs', 2), + rq.LengthOf('outputs', 2), + rq.LengthOf('modes', 2), + rq.LengthOf('names', 2), + rq.Pad(8), + rq.List('crtcs', rq.Card32Obj), + rq.List('outputs', rq.Card32Obj), + rq.List('modes', RandR_ModeInfo), + rq.String8('names'), + ) + +def get_screen_resources_current(self): + return GetScreenResourcesCurrent( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + ) + + +class SetCrtcTransform(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(26), + rq.RequestLength(), + rq.Card32('crtc'), + rq.Object('transform', Render_Transform), + rq.LengthOf('filter_name', 2), + rq.Pad(2), + rq.String8('filter_name'), + rq.List('filter_params', rq.Card32Obj), #FIXME: The protocol says FIXED? http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt#n2161 + ) + +def set_crtc_transform(self, crtc, n_bytes_filter): + return SetCrtcTransform( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + n_bytes_filter=n_bytes_filter, + ) + + +class GetCrtcTransform(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(27), + rq.RequestLength(), + rq.Card32('crtc'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Object('pending_transform', Render_Transform), + rq.Bool('has_transforms'), + rq.Pad(3), + rq.Object('current_transform', Render_Transform), + rq.Pad(4), + rq.LengthOf('pending_filter_name', 2), + rq.LengthOf('pending_filter_params', 2), + rq.LengthOf('current_filter_name', 2), + rq.LengthOf('current_filter_params', 2), + rq.String8('pending_filter_name'), + rq.List('pending_filter_params', rq.Card32Obj), #FIXME: The protocol says FIXED? http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt#n2161 + rq.String8('current_filter_name'), + rq.List('current_filter_params', rq.Card32Obj), #FIXME: The protocol says FIXED? http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt#n2161 + ) + +def get_crtc_transform(self, crtc): + return GetCrtcTransform( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + ) + + +class GetPanning(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(28), + rq.RequestLength(), + rq.Card32('crtc'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.Card16('left'), + rq.Card16('top'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('track_left'), + rq.Card16('track_top'), + rq.Card16('track_width'), + rq.Card16('track_height'), + rq.Int16('border_left'), + rq.Int16('border_top'), + rq.Int16('border_right'), + rq.Int16('border_bottom'), + ) + +def get_panning(self, crtc): + return GetPanning ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + ) + + +class SetPanning(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(29), + rq.RequestLength(), + rq.Card32('crtc'), + rq.Card32('timestamp'), + rq.Card16('left'), + rq.Card16('top'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('track_left'), + rq.Card16('track_top'), + rq.Card16('track_width'), + rq.Card16('track_height'), + rq.Int16('border_left'), + rq.Int16('border_top'), + rq.Int16('border_right'), + rq.Int16('border_bottom'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('new_timestamp'), + rq.Pad(20), + ) + +def set_panning(self, crtc, left, top, width, height, track_left, track_top, track_width, track_height, border_left, border_top, border_width, border_height, timestamp=X.CurrentTime): + return SetPanning ( + display=self.display, + opcode=self.display.get_extension_major(extname), + crtc=crtc, + left=left, + top=top, + width=width, + height=height, + track_left=track_left, + track_top=track_top, + track_width=track_width, + track_height=track_height, + border_left=border_left, + border_top=border_top, + border_width=border_width, + border_height=border_height, + timestamp=timestamp, + ) + + +class SetOutputPrimary(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(30), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('output'), + ) + +def set_output_primary(self, output): + return SetOutputPrimary( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + output=output, + ) + + +class GetOutputPrimary(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(31), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('output'), + rq.Pad(20), + ) + +def get_output_primary(self): + return GetOutputPrimary( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + ) + + +# Version 1.5 methods + +class GetMonitors(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(42), + rq.RequestLength(), + rq.Window('window'), + rq.Bool('is_active'), + rq.Pad(3) + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('timestamp'), + rq.LengthOf('monitors', 4), + rq.Card32('outputs'), + rq.Pad(12), + rq.List('monitors', MonitorInfo) + ) + + +def get_monitors(self, is_active=True): + return GetMonitors( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + is_active=is_active + ) + +class SetMonitor(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(43), + rq.RequestLength(), + rq.Window('window'), + rq.Object('monitor_info', MonitorInfo) + ) + + +def set_monitor(self, monitor_info): + return SetMonitor( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + monitor_info=monitor_info + ) + + +class DeleteMonitor(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(44), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('name') + ) + + +def delete_monitor(self, name): + return DeleteMonitor( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + name=name + ) + +# Events # + +class ScreenChangeNotify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('rotation'), + rq.Card16('sequence_number'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.Window('root'), + rq.Window('window'), + rq.Card16('size_id'), + rq.Card16('subpixel_order'), + rq.Card16('width_in_pixels'), + rq.Card16('height_in_pixels'), + rq.Card16('width_in_millimeters'), + rq.Card16('height_in_millimeters'), + ) + + +class CrtcChangeNotify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('sub_code'), + rq.Card16('sequence_number'), + rq.Card32('timestamp'), + rq.Window('window'), + rq.Card32('crtc'), + rq.Card32('mode'), + rq.Card16('rotation'), + rq.Pad(2), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + ) + + +class OutputChangeNotify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('sub_code'), + rq.Card16('sequence_number'), + rq.Card32('timestamp'), + rq.Card32('config_timestamp'), + rq.Window('window'), + rq.Card32('output'), + rq.Card32('crtc'), + rq.Card32('mode'), + rq.Card16('rotation'), + rq.Card8('connection'), + rq.Card8('subpixel_order'), + ) + + +class OutputPropertyNotify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Card8('sub_code'), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card32('output'), + rq.Card32('atom'), + rq.Card32('timestamp'), + rq.Card8('state'), + rq.Pad(11), + ) +# Initialization # + +def init(disp, info): + disp.extension_add_method('display', 'xrandr_query_version', query_version) + disp.extension_add_method('window', 'xrandr_select_input', select_input) + disp.extension_add_method('window', 'xrandr_get_screen_info', get_screen_info) + disp.extension_add_method('drawable', 'xrandr_1_0set_screen_config', _1_0set_screen_config) + disp.extension_add_method('drawable', 'xrandr_set_screen_config', set_screen_config) + disp.extension_add_method('window', 'xrandr_get_screen_size_range', get_screen_size_range) + disp.extension_add_method('window', 'xrandr_set_screen_size', set_screen_size) + disp.extension_add_method('window', 'xrandr_get_screen_resources', get_screen_resources) + disp.extension_add_method('display', 'xrandr_get_output_info', get_output_info) + disp.extension_add_method('display', 'xrandr_list_output_properties', list_output_properties) + disp.extension_add_method('display', 'xrandr_query_output_property', query_output_property) + disp.extension_add_method('display', 'xrandr_configure_output_property ', configure_output_property ) + disp.extension_add_method('display', 'xrandr_change_output_property', change_output_property) + disp.extension_add_method('display', 'xrandr_delete_output_property', delete_output_property) + disp.extension_add_method('display', 'xrandr_get_output_property', get_output_property) + disp.extension_add_method('window', 'xrandr_create_mode', create_mode) + disp.extension_add_method('display', 'xrandr_destroy_mode', destroy_mode) + disp.extension_add_method('display', 'xrandr_add_output_mode', add_output_mode) + disp.extension_add_method('display', 'xrandr_delete_output_mode', delete_output_mode) + disp.extension_add_method('display', 'xrandr_get_crtc_info', get_crtc_info) + disp.extension_add_method('display', 'xrandr_set_crtc_config', set_crtc_config) + disp.extension_add_method('display', 'xrandr_get_crtc_gamma_size', get_crtc_gamma_size) + disp.extension_add_method('display', 'xrandr_get_crtc_gamma', get_crtc_gamma) + disp.extension_add_method('display', 'xrandr_set_crtc_gamma', set_crtc_gamma) + disp.extension_add_method('window', 'xrandr_get_screen_resources_current', get_screen_resources_current) + disp.extension_add_method('display', 'xrandr_set_crtc_transform', set_crtc_transform) + disp.extension_add_method('display', 'xrandr_get_crtc_transform', get_crtc_transform) + disp.extension_add_method('window', 'xrandr_set_output_primary', set_output_primary) + disp.extension_add_method('window', 'xrandr_get_output_primary', get_output_primary) + disp.extension_add_method('display', 'xrandr_get_panning', get_panning) + disp.extension_add_method('display', 'xrandr_set_panning', set_panning) + + # If the server is running RANDR 1.5+, enable 1.5 compatible methods and events + version = query_version(disp) + if version.major_version == 1 and version.minor_version >= 5: + # version 1.5 compatible + disp.extension_add_method('window', 'xrandr_get_monitors', get_monitors) + disp.extension_add_method('window', 'xrandr_set_monitor', set_monitor) + disp.extension_add_method('window', 'xrandr_delete_monitor', delete_monitor) + + disp.extension_add_event(info.first_event + RRScreenChangeNotify, ScreenChangeNotify) + # add RRNotify events (1 event code with 3 subcodes) + disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_CrtcChange, CrtcChangeNotify) + disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputChange, OutputChangeNotify) + disp.extension_add_subevent(info.first_event + RRNotify, RRNotify_OutputProperty, OutputPropertyNotify) + + disp.extension_add_error(BadRROutput, BadRROutputError) + disp.extension_add_error(BadRRCrtc, BadRRCrtcError) + disp.extension_add_error(BadRRMode, BadRRModeError) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/record.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/record.py new file mode 100644 index 0000000..5b1e2a8 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/record.py @@ -0,0 +1,282 @@ +# Xlib.ext.record -- RECORD extension module +# +# Copyright (C) 2006 Alex Badea +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib.protocol import rq + +extname = 'RECORD' + +FromServerTime = 0x01 +FromClientTime = 0x02 +FromClientSequence = 0x04 + +CurrentClients = 1 +FutureClients = 2 +AllClients = 3 + +FromServer = 0 +FromClient = 1 +ClientStarted = 2 +ClientDied = 3 +StartOfData = 4 +EndOfData = 5 + +Record_Range8 = rq.Struct( + rq.Card8('first'), + rq.Card8('last')) +Record_Range16 = rq.Struct( + rq.Card16('first'), + rq.Card16('last')) +Record_ExtRange = rq.Struct( + rq.Card8('major_range_first'), + rq.Card8('major_range_last'), + rq.Card16('minor_range_first'), + rq.Card16('minor_range_last')) +Record_Range = rq.Struct( + rq.Object('core_requests', Record_Range8), + rq.Object('core_replies', Record_Range8), + rq.Object('ext_requests', Record_ExtRange), + rq.Object('ext_replies', Record_ExtRange), + rq.Object('delivered_events', Record_Range8), + rq.Object('device_events', Record_Range8), + rq.Object('errors', Record_Range8), + rq.Bool('client_started'), + rq.Bool('client_died')) + +Record_ClientInfo = rq.Struct( + rq.Card32('client_resource'), + rq.LengthOf('ranges', 4), + rq.List('ranges', Record_Range)) + + +class RawField(rq.ValueField): + """A field with raw data, stored as a string""" + + structcode = None + + def pack_value(self, val): + return val, len(val), None + + def parse_binary_value(self, data, display, length, format): + return data, '' + + +class GetVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card16('major_version'), + rq.Card16('minor_version')) + _reply = rq.Struct( + rq.Pad(2), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20)) + +def get_version(self, major, minor): + return GetVersion( + display = self.display, + opcode = self.display.get_extension_major(extname), + major_version = major, + minor_version = minor) + + +class CreateContext(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.Card32('context'), # Record_RC + rq.Card8('element_header'), # Record_Element_Header + rq.Pad(3), + rq.LengthOf('clients', 4), + rq.LengthOf('ranges', 4), + rq.List('clients', rq.Card32Obj), + rq.List('ranges', Record_Range)) + +def create_context(self, datum_flags, clients, ranges): + context = self.display.allocate_resource_id() + CreateContext( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context, + element_header = datum_flags, + clients = clients, + ranges = ranges) + return context + + +class RegisterClients(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Card32('context'), # Record_RC + rq.Card8('element_header'), # Record_Element_Header + rq.Pad(3), + rq.LengthOf('clients', 4), + rq.LengthOf('ranges', 4), + rq.List('clients', rq.Card32Obj), + rq.List('ranges', Record_Range)) + +def register_clients(self, context, element_header, clients, ranges): + RegisterClients( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context, + element_header = element_header, + clients = clients, + ranges = ranges) + + +class UnregisterClients(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Card32('context'), # Record_RC + rq.LengthOf('clients', 4), + rq.List('clients', rq.Card32Obj)) + +def unregister_clients(self, context, clients): + UnregisterClients( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context, + clients = clients) + + +class GetContext(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Card32('context')) # Record_RC + _reply = rq.Struct( + rq.Pad(2), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card8('element_header'), # Record_Element_Header + rq.Pad(3), + rq.LengthOf('client_info', 4), + rq.Pad(16), + rq.List('client_info', Record_ClientInfo)) + +def get_context(self, context): + return GetContext( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context) + + +class EnableContext(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + rq.Card32('context')) # Record_RC + _reply = rq.Struct( + rq.Pad(1), + rq.Card8('category'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card8('element_header'), # Record_Element_Header + rq.Bool('client_swapped'), + rq.Pad(2), + rq.Card32('id_base'), # Record_XIDBase + rq.Card32('server_time'), + rq.Card32('recorded_sequence_number'), + rq.Pad(8), + RawField('data')) + + # This request receives multiple responses, so we need to keep + # ourselves in the 'sent_requests' list in order to receive them all. + + # See the discussion on ListFonstsWithInfo in request.py + + def __init__(self, callback, *args, **keys): + self._callback = callback + rq.ReplyRequest.__init__(self, *args, **keys) + + def _parse_response(self, data): + r, d = self._reply.parse_binary(data, self._display) + self._callback(r) + + if r.category == StartOfData: + # Hack ourselves a sequence number, used by the code in + # Xlib.protocol.display.Display.parse_request_response() + self.sequence_number = r.sequence_number + + if r.category == EndOfData: + self._response_lock.acquire() + self._data = r + self._response_lock.release() + else: + self._display.sent_requests.insert(0, self) + +def enable_context(self, context, callback): + EnableContext( + callback = callback, + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context) + + +class DisableContext(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(6), + rq.RequestLength(), + rq.Card32('context')) # Record_RC + +def disable_context(self, context): + DisableContext( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context) + + +class FreeContext(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(7), + rq.RequestLength(), + rq.Card32('context')) # Record_RC + +def free_context(self, context): + FreeContext( + display = self.display, + opcode = self.display.get_extension_major(extname), + context = context) + self.display.free_resource_id(context) + + +def init(disp, info): + disp.extension_add_method('display', 'record_get_version', get_version) + disp.extension_add_method('display', 'record_create_context', create_context) + disp.extension_add_method('display', 'record_register_clients', register_clients) + disp.extension_add_method('display', 'record_unregister_clients', unregister_clients) + disp.extension_add_method('display', 'record_get_context', get_context) + disp.extension_add_method('display', 'record_enable_context', enable_context) + disp.extension_add_method('display', 'record_disable_context', disable_context) + disp.extension_add_method('display', 'record_free_context', free_context) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/res.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/res.py new file mode 100644 index 0000000..810a3b9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/res.py @@ -0,0 +1,288 @@ +# Xlib.ext.res -- X-Resource extension module +# +# Copyright (C) 2021 Aleksei Bavshin +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, +# Fifth Floor, +# Boston, MA 02110-1301 USA + +"""X-Resource extension allows a client to query the X server about its usage +of various resources. + +For detailed description see any of the following documents. +Protocol specification: + https://www.x.org/releases/current/doc/resourceproto/resproto.txt +XCB Protocol specification: + https://cgit.freedesktop.org/xcb/proto/tree/src/res.xml +""" +from Xlib.protocol import rq + +RES_MAJOR_VERSION = 1 +RES_MINOR_VERSION = 2 + +extname = "X-Resource" + +# v1.0 +ResQueryVersion = 0 +ResQueryClients = 1 +ResQueryClientResources = 2 +ResQueryClientPixmapBytes = 3 +# v1.2 +ResQueryClientIds = 4 +ResQueryResourceBytes = 5 + + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryVersion), + rq.RequestLength(), + rq.Card8("client_major"), + rq.Card8("client_minor"), + rq.Pad(2)) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.Card16("server_major"), + rq.Card16("server_minor"), + rq.Pad(20)) + + +def query_version(self, client_major=RES_MAJOR_VERSION, + client_minor=RES_MINOR_VERSION): + """ Query the protocol version supported by the X server. + + The client sends the highest supported version to the server and the + server sends the highest version it supports, but no higher than the + requested version.""" + return QueryVersion( + display=self.display, + opcode=self.display.get_extension_major(extname), + client_major=client_major, + client_minor=client_minor) + + +Client = rq.Struct( + rq.Card32("resource_base"), + rq.Card32("resource_mask")) + + +class QueryClients(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryClients), + rq.RequestLength()) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.LengthOf("clients", 4), + rq.Pad(20), + rq.List("clients", Client)) + + +def query_clients(self): + """Request the list of all currently connected clients.""" + return QueryClients( + display=self.display, + opcode=self.display.get_extension_major(extname)) + + +Type = rq.Struct( + rq.Card32("resource_type"), + rq.Card32("count")) + + +class QueryClientResources(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryClientResources), + rq.RequestLength(), + rq.Card32("client")) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.LengthOf("types", 4), + rq.Pad(20), + rq.List("types", Type)) + + +def query_client_resources(self, client): + """Request the number of resources owned by a client. + + The server will return the counts of each type of resource. + """ + return QueryClientResources( + display=self.display, + opcode=self.display.get_extension_major(extname), + client=client) + + +class QueryClientPixmapBytes(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryClientPixmapBytes), + rq.RequestLength(), + rq.Card32("client")) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.Card32("bytes"), + rq.Card32("bytes_overflow"), + rq.Pad(16)) + + +def query_client_pixmap_bytes(self, client): + """Query the pixmap usage of some client. + + The returned number is a sum of memory usage of each pixmap that can be + attributed to the given client. + """ + return QueryClientPixmapBytes( + display=self.display, + opcode=self.display.get_extension_major(extname), + client=client) + + +class SizeOf(rq.LengthOf): + """A SizeOf stores the size in bytes of some other Field whose size + may vary, e.g. List + """ + def __init__(self, name, size, item_size): + rq.LengthOf.__init__(self, name, size) + self.item_size = item_size + + def parse_value(self, length, display): + return length // self.item_size + + +ClientXIDMask = 1 << 0 +LocalClientPIDMask = 1 << 1 + + +ClientIdSpec = rq.Struct( + rq.Card32("client"), + rq.Card32("mask")) + + +ClientIdValue = rq.Struct( + rq.Object("spec", ClientIdSpec), + SizeOf("value", 4, 4), + rq.List("value", rq.Card32Obj)) + + +class QueryClientIds(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryClientIds), + rq.RequestLength(), + rq.LengthOf("specs", 4), + rq.List("specs", ClientIdSpec)) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.LengthOf("ids", 4), + rq.Pad(20), + rq.List("ids", ClientIdValue)) + + +def query_client_ids(self, specs): + """Request to identify a given set of clients with some identification method. + + The request sends a list of specifiers that select clients and + identification methods to server. The server then tries to identify the + chosen clients using the identification methods specified for each client. + The server returns IDs for those clients that were successfully identified. + """ + return QueryClientIds( + display=self.display, + opcode=self.display.get_extension_major(extname), + specs=specs) + + +ResourceIdSpec = rq.Struct( + rq.Card32("resource"), + rq.Card32("type")) + + +ResourceSizeSpec = rq.Struct( + # inline struct ResourceIdSpec to work around + # a parser bug with nested objects + rq.Card32("resource"), + rq.Card32("type"), + rq.Card32("bytes"), + rq.Card32("ref_count"), + rq.Card32("use_count")) + + +ResourceSizeValue = rq.Struct( + rq.Object("size", ResourceSizeSpec), + rq.LengthOf("cross_references", 4), + rq.List("cross_references", ResourceSizeSpec)) + + +class QueryResourceBytes(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8("opcode"), + rq.Opcode(ResQueryResourceBytes), + rq.RequestLength(), + rq.Card32("client"), + rq.LengthOf("specs", 4), + rq.List("specs", ResourceIdSpec)) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16("sequence_number"), + rq.ReplyLength(), + rq.LengthOf("sizes", 4), + rq.Pad(20), + rq.List("sizes", ResourceSizeValue)) + + +def query_resource_bytes(self, client, specs): + """Query the sizes of resources from X server. + + The request sends a list of specifiers that selects resources for size + calculation. The server tries to calculate the sizes of chosen resources + and returns an estimate for a resource only if the size could be determined + """ + return QueryResourceBytes( + display=self.display, + opcode=self.display.get_extension_major(extname), + client=client, + specs=specs) + + +def init(disp, info): + disp.extension_add_method("display", "res_query_version", query_version) + disp.extension_add_method("display", "res_query_clients", query_clients) + disp.extension_add_method("display", "res_query_client_resources", + query_client_resources) + disp.extension_add_method("display", "res_query_client_pixmap_bytes", + query_client_pixmap_bytes) + disp.extension_add_method("display", "res_query_client_ids", + query_client_ids) + disp.extension_add_method("display", "res_query_resource_bytes", + query_resource_bytes) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/screensaver.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/screensaver.py new file mode 100644 index 0000000..d6bad53 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/screensaver.py @@ -0,0 +1,198 @@ +# Xlib.ext.screensaver -- X ScreenSaver extension module +# +# Copyright (C) 2022 Vladimir Panteleev +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, +# Fifth Floor, +# Boston, MA 02110-1301 USA + +"""This extension allows registering the client as an X screensaver, +or query information about the current screensaver. + +For detailed description see any of the following documents. +Protocol specification: + https://www.x.org/releases/X11R7.7/doc/scrnsaverproto/saver.html +XCB Protocol specification: + https://cgit.freedesktop.org/xcb/proto/tree/src/screensaver.xml + +""" + +from Xlib import X +from Xlib.protocol import rq, structs + +extname = 'MIT-SCREEN-SAVER' + +# Event members +NotifyMask = 1 +CycleMask = 2 + +# Notify state +StateOff = 0 +StateOn = 1 +StateCycle = 2 + +# Notify kind +KindBlanked = 0 +KindInternal = 1 +KindExternal = 2 + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card8('major_version'), + rq.Card8('minor_version'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20), + ) + +def query_version(self): + return QueryVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=0) + + +class QueryInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.Drawable('drawable'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('state'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('saver_window'), + rq.Card32('til_or_since'), + rq.Card32('idle'), + rq.Card32('event_mask'), # rq.Set('event_mask', 4, (NotifyMask, CycleMask)), + rq.Card8('kind'), + rq.Pad(7), + ) + +def query_info(self): + return QueryInfo(display=self.display, + opcode=self.display.get_extension_major(extname), + drawable=self, + ) + + +class SelectInput(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Card32('event_mask'), # rq.Set('event_mask', 4, (NotifyMask, CycleMask)), + ) + +def select_input(self, mask): + return SelectInput(display=self.display, + opcode=self.display.get_extension_major(extname), + drawable=self, + event_mask=mask, + ) + + +class SetAttributes(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Set('window_class', 1, (X.CopyFromParent, X.InputOutput, X.InputOnly)), + rq.Card8('depth'), + rq.Card32('visual'), + structs.WindowValues('attrs'), + ) + +def set_attributes(self, x, y, width, height, border_width, + window_class = X.CopyFromParent, + depth = X.CopyFromParent, + visual = X.CopyFromParent, + onerror = None, + **keys): + return SetAttributes(display=self.display, + onerror = onerror, + opcode=self.display.get_extension_major(extname), + drawable=self, + x = x, + y = y, + width = width, + height = height, + border_width = border_width, + window_class = window_class, + depth = depth, + visual = visual, + attrs = keys) + + +class UnsetAttributes(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Drawable('drawable'), + ) + +def unset_attributes(self, onerror = None): + return UnsetAttributes(display=self.display, + onerror = onerror, + opcode=self.display.get_extension_major(extname), + drawable=self) + + +class Notify(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + rq.Set('state', 1, (StateOff, StateOn, StateCycle)), + rq.Card16('sequence_number'), + rq.Card32('timestamp'), + rq.Window('root'), + rq.Window('window'), + rq.Set('kind', 1, (KindBlanked, KindInternal, KindExternal)), + rq.Bool('forced'), + rq.Pad(14), + ) + +def init(disp, info): + disp.extension_add_method('display', 'screensaver_query_version', query_version) + disp.extension_add_method('drawable', 'screensaver_query_info', query_info) + disp.extension_add_method('drawable', 'screensaver_select_input', select_input) + disp.extension_add_method('drawable', 'screensaver_set_attributes', set_attributes) + disp.extension_add_method('drawable', 'screensaver_unset_attributes', unset_attributes) + + disp.extension_add_event(info.first_event + 0, Notify) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/security.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/security.py new file mode 100644 index 0000000..ea5070c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/security.py @@ -0,0 +1,139 @@ +# Xlib.ext.security -- SECURITY extension module +# +# Copyright (C) 2010-2013 Outpost Embedded, LLC +# Forest Bond +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +''' +A partial implementation of the SECURITY extension. Support for the +SecurityAuthorizationRevoked event is not implemented. +''' + +from Xlib.protocol import rq + + +extname = 'SECURITY' + + +SecurityClientTrusted = 0 +SecurityClientUntrusted = 1 + +SecurityAuthorizationRevokedMask = 1 + + +AUTHID = rq.Card32 + + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card16('major_version'), + rq.Card16('minor_version') + ) + _reply = rq.Struct(rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20) + ) + + +def query_version(self): + return QueryVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=0) + + +class SecurityGenerateAuthorization(rq.ReplyRequest): + # The order of fields here does not match the specifications I've seen + # online, but it *does* match with the X.org implementation. I guess the + # spec is out-of-date. + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.LengthOf('auth_proto', 2), + rq.LengthOf('auth_data', 2), + rq.Card32('value_mask'), + rq.String8('auth_proto'), + rq.Binary('auth_data'), + rq.List('values', rq.Card32Obj) + ) + _reply = rq.Struct(rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + AUTHID('authid'), + rq.LengthOf('auth_data_return', 2), + rq.Pad(18), + rq.Binary('auth_data_return') + ) + + +def generate_authorization(self, auth_proto, auth_data=b'', timeout=None, + trust_level=None, group=None, event_mask=None): + value_mask = 0 + values = [] + if timeout is not None: + value_mask |= 1 + values.append(timeout) + if trust_level is not None: + value_mask |= 2 + values.append(trust_level) + if group is not None: + value_mask |= 4 + values.append(group) + if event_mask is not None: + value_mask |= 8 + values.append(event_mask) + return SecurityGenerateAuthorization(display=self.display, + opcode=self.display.get_extension_major(extname), + value_mask=value_mask, + auth_proto=auth_proto, + auth_data=auth_data, + values=values) + + +class SecurityRevokeAuthorization(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + AUTHID('authid') + ) + + +def revoke_authorization(self, authid): + return SecurityRevokeAuthorization(display=self.display, + opcode=self.display.get_extension_major(extname), + authid=authid) + + +def init(disp, info): + disp.extension_add_method('display', + 'security_query_version', + query_version) + disp.extension_add_method('display', + 'security_generate_authorization', + generate_authorization) + disp.extension_add_method('display', + 'security_revoke_authorization', + revoke_authorization) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/shape.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/shape.py new file mode 100644 index 0000000..1fd440a --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/shape.py @@ -0,0 +1,297 @@ +# Automatically generated file; DO NOT EDIT. +# Generated from: /usr/share/xcb/shape.xml + +from Xlib.protocol import rq, structs + + +extname = 'SHAPE' + +OP = rq.Card8 + +class SO: + Set = 0 + Union = 1 + Intersect = 2 + Subtract = 3 + Invert = 4 + +class SK: + Bounding = 0 + Clip = 1 + Input = 2 + +class KIND(rq.Set): + + def __init__(self, name): + super(KIND, self).__init__(name, 1, + values=(SK.Bounding, + SK.Clip, + SK.Input)) + +class NotifyEventData(rq.Event): + _code = None + _fields = rq.Struct( + rq.Card8('type'), + KIND('shape_kind'), + rq.Card16('sequence_number'), + rq.Window('affected_window'), + rq.Int16('extents_x'), + rq.Int16('extents_y'), + rq.Card16('extents_width'), + rq.Card16('extents_height'), + rq.Card32('server_time'), + rq.Card8('shaped'), + rq.Pad(11), + ) + +class QueryVersion(rq.ReplyRequest): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + ) + +class Rectangles(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + OP('operation'), + KIND('destination_kind'), + rq.Card8('ordering'), + rq.Pad(1), + rq.Window('destination_window'), + rq.Int16('x_offset'), + rq.Int16('y_offset'), + rq.List('rectangles', structs.Rectangle, pad=0), + ) + +class Mask(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + OP('operation'), + KIND('destination_kind'), + rq.Pad(2), + rq.Window('destination_window'), + rq.Int16('x_offset'), + rq.Int16('y_offset'), + rq.Pixmap('source_bitmap'), + ) + +class Combine(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + OP('operation'), + KIND('destination_kind'), + KIND('source_kind'), + rq.Pad(1), + rq.Window('destination_window'), + rq.Int16('x_offset'), + rq.Int16('y_offset'), + rq.Window('source_window'), + ) + +class Offset(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + KIND('destination_kind'), + rq.Pad(3), + rq.Window('destination_window'), + rq.Int16('x_offset'), + rq.Int16('y_offset'), + ) + +class QueryExtents(rq.ReplyRequest): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + rq.Window('destination_window'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card8('bounding_shaped'), + rq.Card8('clip_shaped'), + rq.Pad(2), + rq.Int16('bounding_shape_extents_x'), + rq.Int16('bounding_shape_extents_y'), + rq.Card16('bounding_shape_extents_width'), + rq.Card16('bounding_shape_extents_height'), + rq.Int16('clip_shape_extents_x'), + rq.Int16('clip_shape_extents_y'), + rq.Card16('clip_shape_extents_width'), + rq.Card16('clip_shape_extents_height'), + ) + +class SelectInput(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(6), + rq.RequestLength(), + rq.Window('destination_window'), + rq.Card8('enable'), + rq.Pad(3), + ) + +class InputSelected(rq.ReplyRequest): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(7), + rq.RequestLength(), + rq.Window('destination_window'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('enabled'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + ) + +class GetRectangles(rq.ReplyRequest): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(8), + rq.RequestLength(), + rq.Window('window'), + KIND('source_kind'), + rq.Pad(3), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('ordering'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('rectangles', 4), + rq.Pad(20), + rq.List('rectangles', structs.Rectangle, pad=0), + ) + +class Event: + # Sub events. + Notify = 0 + +def combine(self, operation, destination_kind, source_kind, x_offset, y_offset): + Combine( + display=self.display, + opcode=self.display.get_extension_major(extname), + source_window=self, + operation=operation, + destination_kind=destination_kind, + source_kind=source_kind, + x_offset=x_offset, + y_offset=y_offset, + ) + +def get_rectangles(self, source_kind): + return GetRectangles( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + source_kind=source_kind, + ) + +def input_selected(self, ): + return InputSelected( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + ) + +def mask(self, operation, destination_kind, x_offset, y_offset, source_bitmap): + Mask( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + operation=operation, + destination_kind=destination_kind, + x_offset=x_offset, + y_offset=y_offset, + source_bitmap=source_bitmap, + ) + +def offset(self, destination_kind, x_offset, y_offset): + Offset( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + destination_kind=destination_kind, + x_offset=x_offset, + y_offset=y_offset, + ) + +def query_extents(self, ): + return QueryExtents( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + ) + +def query_version(self, ): + return QueryVersion( + display=self.display, + opcode=self.display.get_extension_major(extname), + ) + +def rectangles(self, operation, destination_kind, ordering, x_offset, y_offset, rectangles): + Rectangles( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + operation=operation, + destination_kind=destination_kind, + ordering=ordering, + x_offset=x_offset, + y_offset=y_offset, + rectangles=rectangles, + ) + +def select_input(self, enable): + SelectInput( + display=self.display, + opcode=self.display.get_extension_major(extname), + destination_window=self, + enable=enable, + ) + +def init(disp, info): + disp.extension_add_method('window', 'shape_combine', combine) + disp.extension_add_method('window', 'shape_get_rectangles', get_rectangles) + disp.extension_add_method('window', 'shape_input_selected', input_selected) + disp.extension_add_method('window', 'shape_mask', mask) + disp.extension_add_method('window', 'shape_offset', offset) + disp.extension_add_method('window', 'shape_query_extents', query_extents) + disp.extension_add_method('display', 'shape_query_version', query_version) + disp.extension_add_method('window', 'shape_rectangles', rectangles) + disp.extension_add_method('window', 'shape_select_input', select_input) + disp.extension_add_event(info.first_event + Event.Notify, NotifyEventData, 'ShapeNotify') + diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xfixes.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xfixes.py new file mode 100644 index 0000000..a7cf35f --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xfixes.py @@ -0,0 +1,200 @@ +# Xlib.ext.xfixes -- XFIXES extension module +# +# Copyright (C) 2010-2011 Outpost Embedded, LLC +# Forest Bond +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +''' +A partial implementation of the XFIXES extension. Only the HideCursor and +ShowCursor requests and SelectionNotify events are provided. +''' + +from Xlib.protocol import rq + +extname = 'XFIXES' + +XFixesSelectionNotify = 0 +XFixesCursorNotify = 1 + +XFixesSetSelectionOwnerNotifyMask = (1 << 0) +XFixesSelectionWindowDestroyNotifyMask = (1 << 1) +XFixesSelectionClientCloseNotifyMask = (1 << 2) +XFixesDisplayCursorNotifyMask = (1 << 0) + +XFixesSetSelectionOwnerNotify = 0 +XFixesSelectionWindowDestroyNotify = 1 +XFixesSelectionClientCloseNotify = 2 +XFixesDisplayCursorNotify = 0 + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card32('major_version'), + rq.Card32('minor_version') + ) + _reply = rq.Struct(rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('major_version'), + rq.Card32('minor_version'), + rq.Pad(16) + ) + + +def query_version(self): + return QueryVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=4, + minor_version=0) + + +class HideCursor(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(29), + rq.RequestLength(), + rq.Window('window') + ) + +def hide_cursor(self): + HideCursor(display=self.display, + opcode=self.display.get_extension_major(extname), + window=self) + + +class ShowCursor(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(30), + rq.RequestLength(), + rq.Window('window') + ) + + +def show_cursor(self): + ShowCursor(display=self.display, + opcode=self.display.get_extension_major(extname), + window=self) + +class SelectSelectionInput(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('selection'), + rq.Card32('mask') + ) + +def select_selection_input(self, window, selection, mask): + return SelectSelectionInput(opcode=self.display.get_extension_major(extname), + display=self.display, + window=window, + selection=selection, + mask=mask) + + +class SelectionNotify(rq.Event): + _code = None + _fields = rq.Struct(rq.Card8('type'), + rq.Card8('sub_code'), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Window('owner'), + rq.Card32('selection'), + rq.Card32('timestamp'), + rq.Card32('selection_timestamp'), + rq.Pad(8)) + + +class SetSelectionOwnerNotify(SelectionNotify): + pass + + +class SelectionWindowDestroyNotify(SelectionNotify): + pass + + +class SelectionClientCloseNotify(SelectionNotify): + pass + + +class SelectCursorInput(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('mask') + ) + +def select_cursor_input(self, window, mask): + return SelectCursorInput(opcode=self.display.get_extension_major(extname), + display=self.display, + window=window, + cursor_serial=0, + mask=mask) + + +class GetCursorImage(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength() + ) + _reply = rq.Struct(rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('xhot'), + rq.Card16('yhot'), + rq.Card32('cursor_serial'), + rq.Pad(8), + rq.List('cursor_image', rq.Card32) + ) + +def get_cursor_image(self, window): + return GetCursorImage(opcode=self.display.get_extension_major(extname), + display=self.display, + ) + + +class DisplayCursorNotify(rq.Event): + _code = None + _fields = rq.Struct(rq.Card8('type'), + rq.Card8('sub_code'), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card32('cursor_serial'), + rq.Card32('timestamp')) + + +def init(disp, info): + disp.extension_add_method('display', 'xfixes_select_selection_input', select_selection_input) + disp.extension_add_method('display', 'xfixes_query_version', query_version) + disp.extension_add_method('window', 'xfixes_hide_cursor', hide_cursor) + disp.extension_add_method('window', 'xfixes_show_cursor', show_cursor) + disp.extension_add_method('display', 'xfixes_select_cursor_input', select_cursor_input) + disp.extension_add_method('display', 'xfixes_get_cursor_image', get_cursor_image) + + disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSetSelectionOwnerNotify, SetSelectionOwnerNotify) + disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSelectionWindowDestroyNotify, SelectionWindowDestroyNotify) + disp.extension_add_subevent(info.first_event + XFixesSelectionNotify, XFixesSelectionClientCloseNotify, SelectionClientCloseNotify) + disp.extension_add_subevent(info.first_event + XFixesCursorNotify, XFixesDisplayCursorNotify, DisplayCursorNotify) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinerama.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinerama.py new file mode 100644 index 0000000..eff1acd --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinerama.py @@ -0,0 +1,222 @@ +# Xlib.ext.xinerama -- Xinerama extension module +# +# Copyright (C) 2006 Mike Meyer +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +"""Xinerama - provide access to the Xinerama extension information. + +There are at least there different - and mutually incomparable - +Xinerama extensions available. This uses the one bundled with XFree86 +4.6 and/or Xorg 6.9 in the ati/radeon driver. It uses the include +files from that X distribution, so should work with it as well. I +provide code for the lone Sun 1.0 request that isn't part of 1.1, but +this is untested because I don't have a server that implements it. + +The functions loosely follow the libXineram functions. Mostly, they +return an rq.Struct in lieu of passing in pointers that get data from +the rq.Struct crammed into them. The exception is isActive, which +returns the state information - because that's what libXinerama does.""" + + +from Xlib.protocol import rq, structs + +extname = 'XINERAMA' + + +class QueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card8('major_version'), + rq.Card8('minor_version'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20), + ) + +def query_version(self): + return QueryVersion(display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=1, + minor_version=1) + + +class GetState(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Bool('state'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('window'), + rq.Pad(20), + ) + +def get_state(self): + return GetState(display=self.display, + opcode=self.display.get_extension_major(extname), + window=self.id, + ) + + +class GetScreenCount(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Window('window'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('screen_count'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('window'), + rq.Pad(20), + ) + +def get_screen_count(self): + return GetScreenCount(display=self.display, + opcode=self.display.get_extension_major(extname), + window=self.id, + ) + + +class GetScreenSize(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('screen'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Card32('length'), + rq.Card32('width'), + rq.Card32('height'), + rq.Window('window'), + rq.Card32('screen'), + rq.Pad(8), + ) + +def get_screen_size(self, screen_no): + """Returns the size of the given screen number""" + return GetScreenSize(display=self.display, + opcode=self.display.get_extension_major(extname), + window=self.id, + screen=screen_no, + ) + + +# IsActive is only available from Xinerama 1.1 and later. +# It should be used in preference to GetState. +class IsActive(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('state'), + rq.Pad(20), + ) + +def is_active(self): + r = IsActive(display=self.display, + opcode=self.display.get_extension_major(extname), + ) + return r.state + + +# QueryScreens is only available from Xinerama 1.1 and later +class QueryScreens(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(5), + rq.RequestLength(), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('number'), + rq.Pad(20), + rq.List('screens', structs.Rectangle), + ) + +def query_screens(self): + # Hmm. This one needs to read the screen data from the socket. Ooops... + return QueryScreens(display=self.display, + opcode=self.display.get_extension_major(extname), + ) + + +# GetInfo is only available from some Xinerama 1.0, and *NOT* later! Untested +class GetInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(4), + rq.RequestLength(), + rq.Card32('visual'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('window'), + # An array of subwindow slots goes here. Bah. + ) + +def get_info(self, visual): + r = GetInfo(display=self.display, + opcode=self.display.get_extension_major(extname), + visual=visual) + +def init(disp, info): + disp.extension_add_method('display', 'xinerama_query_version', query_version) + disp.extension_add_method('window', 'xinerama_get_state', get_state) + disp.extension_add_method('window', 'xinerama_get_screen_count', get_screen_count) + disp.extension_add_method('window', 'xinerama_get_screen_size', get_screen_size) + disp.extension_add_method('display', 'xinerama_is_active', is_active) + disp.extension_add_method('display', 'xinerama_query_screens', query_screens) + disp.extension_add_method('display', 'xinerama_get_info', get_info) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinput.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinput.py new file mode 100644 index 0000000..95560dd --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xinput.py @@ -0,0 +1,777 @@ +# Xlib.ext.xinput -- XInput extension module +# +# Copyright (C) 2012 Outpost Embedded, LLC +# Forest Bond +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +''' +A very incomplete implementation of the XInput extension. +''' + +import sys +import array +import struct + +# Python 2/3 compatibility. +from six import integer_types + +from Xlib.protocol import rq +from Xlib import X + + +extname = 'XInputExtension' + +PropertyDeleted = 0 +PropertyCreated = 1 +PropertyModified = 2 + +NotifyNormal = 0 +NotifyGrab = 1 +NotifyUngrab = 2 +NotifyWhileGrabbed = 3 +NotifyPassiveGrab = 4 +NotifyPassiveUngrab = 5 + +NotifyAncestor = 0 +NotifyVirtual = 1 +NotifyInferior = 2 +NotifyNonlinear = 3 +NotifyNonlinearVirtual = 4 +NotifyPointer = 5 +NotifyPointerRoot = 6 +NotifyDetailNone = 7 + +GrabtypeButton = 0 +GrabtypeKeycode = 1 +GrabtypeEnter = 2 +GrabtypeFocusIn = 3 +GrabtypeTouchBegin = 4 + +AnyModifier = (1 << 31) +AnyButton = 0 +AnyKeycode = 0 + +AsyncDevice = 0 +SyncDevice = 1 +ReplayDevice = 2 +AsyncPairedDevice = 3 +AsyncPair = 4 +SyncPair = 5 + +SlaveSwitch = 1 +DeviceChange = 2 + +MasterAdded = (1 << 0) +MasterRemoved = (1 << 1) +SlaveAdded = (1 << 2) +SlaveRemoved = (1 << 3) +SlaveAttached = (1 << 4) +SlaveDetached = (1 << 5) +DeviceEnabled = (1 << 6) +DeviceDisabled = (1 << 7) + +AddMaster = 1 +RemoveMaster = 2 +AttachSlave = 3 +DetachSlave = 4 + +AttachToMaster = 1 +Floating = 2 + +ModeRelative = 0 +ModeAbsolute = 1 + +MasterPointer = 1 +MasterKeyboard = 2 +SlavePointer = 3 +SlaveKeyboard = 4 +FloatingSlave = 5 + +KeyClass = 0 +ButtonClass = 1 +ValuatorClass = 2 +ScrollClass = 3 +TouchClass = 8 + +KeyRepeat = (1 << 16) + +AllDevices = 0 +AllMasterDevices = 1 + +DeviceChanged = 1 +KeyPress = 2 +KeyRelease = 3 +ButtonPress = 4 +ButtonRelease = 5 +Motion = 6 +Enter = 7 +Leave = 8 +FocusIn = 9 +FocusOut = 10 +HierarchyChanged = 11 +PropertyEvent = 12 +RawKeyPress = 13 +RawKeyRelease = 14 +RawButtonPress = 15 +RawButtonRelease = 16 +RawMotion = 17 + +DeviceChangedMask = (1 << DeviceChanged) +KeyPressMask = (1 << KeyPress) +KeyReleaseMask = (1 << KeyRelease) +ButtonPressMask = (1 << ButtonPress) +ButtonReleaseMask = (1 << ButtonRelease) +MotionMask = (1 << Motion) +EnterMask = (1 << Enter) +LeaveMask = (1 << Leave) +FocusInMask = (1 << FocusIn) +FocusOutMask = (1 << FocusOut) +HierarchyChangedMask = (1 << HierarchyChanged) +PropertyEventMask = (1 << PropertyEvent) +RawKeyPressMask = (1 << RawKeyPress) +RawKeyReleaseMask = (1 << RawKeyRelease) +RawButtonPressMask = (1 << RawButtonPress) +RawButtonReleaseMask = (1 << RawButtonRelease) +RawMotionMask = (1 << RawMotion) + +GrabModeSync = 0 +GrabModeAsync = 1 +GrabModeTouch = 2 + +DEVICEID = rq.Card16 +DEVICE = rq.Card16 +DEVICEUSE = rq.Card8 + +PROPERTY_TYPE_FLOAT = 'FLOAT' + +class FP1616(rq.Int32): + + def check_value(self, value): + return int(value * 65536.0) + + def parse_value(self, value, display): + return float(value) / float(1 << 16) + +class FP3232(rq.ValueField): + structcode = 'lL' + structvalues = 2 + + def check_value(self, value): + return value + + def parse_value(self, value, display): + integral, frac = value + ret = float(integral) + # optimised math.ldexp(float(frac), -32) + ret += float(frac) * (1.0 / (1 << 32)) + return ret + +class XIQueryVersion(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(47), + rq.RequestLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + ) + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('major_version'), + rq.Card16('minor_version'), + rq.Pad(20), + ) + + +def query_version(self): + return XIQueryVersion( + display=self.display, + opcode=self.display.get_extension_major(extname), + major_version=2, + minor_version=0, + ) + +class Mask(rq.List): + + def __init__(self, name): + rq.List.__init__(self, name, rq.Card32, pad=0) + + def pack_value(self, val): + + mask_seq = array.array(rq.struct_to_array_codes['L']) + + if isinstance(val, integer_types): + # We need to build a "binary mask" that (as far as I can tell) is + # encoded in native byte order from end to end. The simple case is + # with a single unsigned 32-bit value, for which we construct an + # array with just one item. For values too big to fit inside 4 + # bytes we build a longer array, being careful to maintain native + # byte order across the entire set of values. + if sys.byteorder == 'little': + def fun(val): + mask_seq.insert(0, val) + elif sys.byteorder == 'big': + fun = mask_seq.append + else: + raise AssertionError(sys.byteorder) + while val: + fun(val & 0xFFFFFFFF) + val = val >> 32 + else: + mask_seq.extend(val) + + return rq.encode_array(mask_seq), len(mask_seq), None + +EventMask = rq.Struct( + DEVICE('deviceid'), + rq.LengthOf('mask', 2), + Mask('mask'), +) + + +class XISelectEvents(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(46), + rq.RequestLength(), + rq.Window('window'), + rq.LengthOf('masks', 2), + rq.Pad(2), + rq.List('masks', EventMask), + ) + +def select_events(self, event_masks): + ''' + select_events(event_masks) + + event_masks: + Sequence of (deviceid, mask) pairs, where deviceid is a numerical device + ID, or AllDevices or AllMasterDevices, and mask is either an unsigned + integer or sequence of 32 bits unsigned values + ''' + return XISelectEvents( + display=self.display, + opcode=self.display.get_extension_major(extname), + window=self, + masks=event_masks, + ) + +AnyInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.Pad(2), +) + +class ButtonMask(object): + + def __init__(self, value, length): + self._value = value + self._length = length + + def __len__(self): + return self._length + + def __getitem__(self, key): + return self._value & (1 << key) + + def __str__(self): + return repr(self) + + def __repr__(self): + return '0b{value:0{width}b}'.format(value=self._value, + width=self._length) + +class ButtonState(rq.ValueField): + + structcode = None + + def __init__(self, name): + rq.ValueField.__init__(self, name) + + def parse_binary_value(self, data, display, length, fmt): + # Mask: bitfield of button states. + mask_len = 4 * ((((length + 7) >> 3) + 3) >> 2) + mask_data = data[:mask_len] + mask_value = 0 + for byte in reversed(struct.unpack('={0:d}B'.format(mask_len), mask_data)): + mask_value <<= 8 + mask_value |= byte + data = data[mask_len:] + assert (mask_value & 1) == 0 + return ButtonMask(mask_value >> 1, length), data + +ButtonInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.LengthOf(('state', 'labels'), 2), + ButtonState('state'), + rq.List('labels', rq.Card32), +) + +KeyInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.LengthOf('keycodes', 2), + rq.List('keycodes', rq.Card32), +) + +ValuatorInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.Card16('number'), + rq.Card32('label'), + FP3232('min'), + FP3232('max'), + FP3232('value'), + rq.Card32('resolution'), + rq.Card8('mode'), + rq.Pad(3), +) + +ScrollInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.Card16('number'), + rq.Card16('scroll_type'), + rq.Pad(2), + rq.Card32('flags'), + FP3232('increment'), +) + +TouchInfo = rq.Struct( + rq.Card16('type'), + rq.Card16('length'), + rq.Card16('sourceid'), + rq.Card8('mode'), + rq.Card8('num_touches'), +) + +INFO_CLASSES = { + KeyClass: KeyInfo, + ButtonClass: ButtonInfo, + ValuatorClass: ValuatorInfo, + ScrollClass: ScrollInfo, + TouchClass: TouchInfo, +} + +class ClassInfoClass(object): + + structcode = None + + def parse_binary(self, data, display): + class_type, length = struct.unpack('=HH', data[:4]) + class_struct = INFO_CLASSES.get(class_type, AnyInfo) + class_data, _ = class_struct.parse_binary(data, display) + data = data[length * 4:] + return class_data, data + +ClassInfo = ClassInfoClass() + +DeviceInfo = rq.Struct( + DEVICEID('deviceid'), + rq.Card16('use'), + rq.Card16('attachment'), + rq.LengthOf('classes', 2), + rq.LengthOf('name', 2), + rq.Bool('enabled'), + rq.Pad(1), + rq.String8('name', 4), + rq.List('classes', ClassInfo), +) + +class XIQueryDevice(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(48), + rq.RequestLength(), + DEVICEID('deviceid'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('devices', 2), + rq.Pad(22), + rq.List('devices', DeviceInfo), + ) + +def query_device(self, deviceid): + return XIQueryDevice( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + ) + +class XIListProperties(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(56), + rq.RequestLength(), + DEVICEID('deviceid'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('atoms', 2), + rq.Pad(22), + rq.List('atoms', rq.Card32Obj), + ) + +def list_device_properties(self, deviceid): + return XIListProperties( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + ) + +class XIGetProperty(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(59), + rq.RequestLength(), + DEVICEID('deviceid'), + rq.Card8('delete'), + rq.Pad(1), + rq.Card32('property'), + rq.Card32('type'), + rq.Card32('offset'), + rq.Card32('length'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('type'), + rq.Card32('bytes_after'), + rq.LengthOf('value', 4), + rq.Format('value', 1), + rq.Pad(11), + rq.PropertyData('value') + ) + +def get_device_property(self, deviceid, property, type, offset, length, delete=False): + return XIGetProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + property=property, + type=type, + offset=offset, + length=length, + delete=delete, + ) + +class XIChangeProperty(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(57), + rq.RequestLength(), + DEVICEID('deviceid'), + rq.Card8('mode'), + rq.Format('value', 1), + rq.Card32('property'), + rq.Card32('type'), + rq.LengthOf('value', 4), + rq.PropertyData('value'), + ) + +def change_device_property(self, deviceid, property, type, mode, value): + return XIChangeProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + property=property, + type=type, + mode=mode, + value=value, + ) + +class XIDeleteProperty(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(58), + rq.RequestLength(), + DEVICEID('deviceid'), + rq.Pad(2), + rq.Card32('property'), + ) + +def delete_device_property(self, deviceid, property): + return XIDeleteProperty( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + property=property, + ) + +class XIGrabDevice(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(51), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card32('time'), + rq.Cursor('cursor', (X.NONE, )), + DEVICEID('deviceid'), + rq.Set('grab_mode', 1, (GrabModeSync, GrabModeAsync)), + rq.Set('paired_device_mode', 1, (GrabModeSync, GrabModeAsync)), + rq.Bool('owner_events'), + rq.Pad(1), + rq.LengthOf('mask', 2), + Mask('mask'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card8('status'), + rq.Pad(23), + ) + +def grab_device(self, deviceid, time, grab_mode, paired_device_mode, owner_events, event_mask): + return XIGrabDevice( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + grab_window=self, + time=time, + cursor=X.NONE, + grab_mode=grab_mode, + paired_device_mode=paired_device_mode, + owner_events=owner_events, + mask=event_mask, + ) + +class XIUngrabDevice(rq.Request): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(52), + rq.RequestLength(), + rq.Card32('time'), + DEVICEID('deviceid'), + rq.Pad(2), + ) + +def ungrab_device(self, deviceid, time): + return XIUngrabDevice( + display=self.display, + opcode=self.display.get_extension_major(extname), + time=time, + deviceid=deviceid, + ) + +class XIPassiveGrabDevice(rq.ReplyRequest): + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(54), + rq.RequestLength(), + rq.Card32('time'), + rq.Window('grab_window'), + rq.Cursor('cursor', (X.NONE, )), + rq.Card32('detail'), + DEVICEID('deviceid'), + rq.LengthOf('modifiers', 2), + rq.LengthOf('mask', 2), + rq.Set('grab_type', 1, (GrabtypeButton, GrabtypeKeycode, GrabtypeEnter, + GrabtypeFocusIn, GrabtypeTouchBegin)), + rq.Set('grab_mode', 1, (GrabModeSync, GrabModeAsync)), + rq.Set('paired_device_mode', 1, (GrabModeSync, GrabModeAsync)), + rq.Bool('owner_events'), + rq.Pad(2), + Mask('mask'), + rq.List('modifiers', rq.Card32), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('modifiers', 2), + rq.Pad(22), + rq.List('modifiers', rq.Card32), + ) + +def passive_grab_device(self, deviceid, time, detail, + grab_type, grab_mode, paired_device_mode, + owner_events, event_mask, modifiers): + return XIPassiveGrabDevice( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + grab_window=self, + time=time, + cursor=X.NONE, + detail=detail, + grab_type=grab_type, + grab_mode=grab_mode, + paired_device_mode=paired_device_mode, + owner_events=owner_events, + mask=event_mask, + modifiers=modifiers, + ) + +def grab_keycode(self, deviceid, time, keycode, + grab_mode, paired_device_mode, + owner_events, event_mask, modifiers): + return passive_grab_device(self, deviceid, time, keycode, + GrabtypeKeycode, + grab_mode, paired_device_mode, + owner_events, event_mask, modifiers) + +class XIPassiveUngrabDevice(rq.Request): + + _request = rq.Struct( + rq.Card8('opcode'), + rq.Opcode(55), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card32('detail'), + DEVICEID('deviceid'), + rq.LengthOf('modifiers', 2), + rq.Set('grab_type', 1, (GrabtypeButton, GrabtypeKeycode, + GrabtypeEnter, GrabtypeFocusIn, + GrabtypeTouchBegin)), + rq.Pad(3), + rq.List('modifiers', rq.Card32), + ) + +def passive_ungrab_device(self, deviceid, detail, grab_type, modifiers): + return XIPassiveUngrabDevice( + display=self.display, + opcode=self.display.get_extension_major(extname), + deviceid=deviceid, + grab_window=self, + detail=detail, + grab_type=grab_type, + modifiers=modifiers, + ) + +def ungrab_keycode(self, deviceid, keycode, modifiers): + return passive_ungrab_device(self, deviceid, keycode, + GrabtypeKeycode, modifiers) + +HierarchyInfo = rq.Struct( + DEVICEID('deviceid'), + DEVICEID('attachment'), + DEVICEUSE('type'), + rq.Bool('enabled'), + rq.Pad(2), + rq.Card32('flags'), +) + + +HierarchyEventData = rq.Struct( + DEVICEID('deviceid'), + rq.Card32('time'), + rq.Card32('flags'), + rq.LengthOf('info', 2), + rq.Pad(10), + rq.List('info', HierarchyInfo), +) + +ModifierInfo = rq.Struct( + rq.Card32('base_mods'), + rq.Card32('latched_mods'), + rq.Card32('locked_mods'), + rq.Card32('effective_mods'), +) + +GroupInfo = rq.Struct( + rq.Card8('base_group'), + rq.Card8('latched_group'), + rq.Card8('locked_group'), + rq.Card8('effective_group'), +) + +DeviceEventData = rq.Struct( + DEVICEID('deviceid'), + rq.Card32('time'), + rq.Card32('detail'), + rq.Window('root'), + rq.Window('event'), + rq.Window('child'), + FP1616('root_x'), + FP1616('root_y'), + FP1616('event_x'), + FP1616('event_y'), + rq.LengthOf('buttons', 2), + rq.Card16('valulators_len'), + DEVICEID('sourceid'), + rq.Pad(2), + rq.Card32('flags'), + rq.Object('mods', ModifierInfo), + rq.Object('groups', GroupInfo), + ButtonState('buttons'), +) + +DeviceChangedEventData = rq.Struct( + DEVICEID('deviceid'), + rq.Card32('time'), + rq.LengthOf('classes', 2), + DEVICEID('sourceid'), + rq.Card8('reason'), + rq.Pad(11), + rq.List('classes', ClassInfo), +) + +PropertyEventData = rq.Struct( + DEVICEID('deviceid'), + rq.Card32('time'), + rq.Card32('property'), + rq.Card8('what'), + rq.Pad(11), +) + +def init(disp, info): + disp.extension_add_method('display', 'xinput_query_version', query_version) + disp.extension_add_method('window', 'xinput_select_events', select_events) + disp.extension_add_method('display', 'xinput_query_device', query_device) + disp.extension_add_method('window', 'xinput_grab_device', grab_device) + disp.extension_add_method('display', 'xinput_ungrab_device', ungrab_device) + disp.extension_add_method('window', 'xinput_grab_keycode', grab_keycode) + disp.extension_add_method('window', 'xinput_ungrab_keycode', ungrab_keycode) + disp.extension_add_method('display', 'xinput_get_device_property', get_device_property) + disp.extension_add_method('display', 'xinput_list_device_properties', list_device_properties) + disp.extension_add_method('display', 'xinput_change_device_property', change_device_property) + disp.extension_add_method('display', 'xinput_delete_device_property', delete_device_property) + if hasattr(disp,"ge_add_event_data"): + for device_event in (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion): + disp.ge_add_event_data(info.major_opcode, device_event, DeviceEventData) + disp.ge_add_event_data(info.major_opcode, DeviceChanged, DeviceEventData) + disp.ge_add_event_data(info.major_opcode, HierarchyChanged, HierarchyEventData) + disp.ge_add_event_data(info.major_opcode, PropertyEvent, PropertyEventData) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xtest.py b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xtest.py new file mode 100644 index 0000000..0b5d7da --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/ext/xtest.py @@ -0,0 +1,122 @@ +# Xlib.ext.xtest -- XTEST extension module +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib import X +from Xlib.protocol import rq + +extname = 'XTEST' + +CurrentCursor = 1 + +class GetVersion(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(0), + rq.RequestLength(), + rq.Card8('major_version'), + rq.Pad(1), + rq.Card16('minor_version') + ) + + _reply = rq.Struct(rq.Pad(1), + rq.Card8('major_version'), + rq.Card16('sequence_number'), + rq.Pad(4), + rq.Card16('minor_version'), + rq.Pad(22) + ) + +def get_version(self, major, minor): + return GetVersion(display = self.display, + opcode = self.display.get_extension_major(extname), + major_version = major, + minor_version = minor) + + +class CompareCursor(rq.ReplyRequest): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(1), + rq.RequestLength(), + rq.Window('window'), + rq.Cursor('cursor', (X.NONE, CurrentCursor)), + ) + + _reply = rq.Struct(rq.Pad(1), + rq.Card8('same'), + rq.Card16('sequence_number'), + rq.Pad(28), + ) + +def compare_cursor(self, cursor): + r = CompareCursor(display = self.display, + opcode = self.display.get_extension_major(extname), + window = self.id, + cursor = cursor) + return r.same + +class FakeInput(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(2), + rq.RequestLength(), + rq.Set('event_type', 1, (X.KeyPress, + X.KeyRelease, + X.ButtonPress, + X.ButtonRelease, + X.MotionNotify)), + rq.Card8('detail'), + rq.Pad(2), + rq.Card32('time'), + rq.Window('root', (X.NONE, )), + rq.Pad(8), + rq.Int16('x'), + rq.Int16('y'), + rq.Pad(8) + ) + +def fake_input(self, event_type, detail = 0, time = X.CurrentTime, + root = X.NONE, x = 0, y = 0): + + FakeInput(display = self.display, + opcode = self.display.get_extension_major(extname), + event_type = event_type, + detail = detail, + time = time, + root = root, + x = x, + y = y) + +class GrabControl(rq.Request): + _request = rq.Struct(rq.Card8('opcode'), + rq.Opcode(3), + rq.RequestLength(), + rq.Bool('impervious'), + rq.Pad(3) + ) + +def grab_control(self, impervious): + GrabControl(display = self.display, + opcode = self.display.get_extension_major(extname), + impervious = impervious) + +def init(disp, info): + disp.extension_add_method('display', 'xtest_get_version', get_version) + disp.extension_add_method('window', 'xtest_compare_cursor', compare_cursor) + disp.extension_add_method('display', 'xtest_fake_input', fake_input) + disp.extension_add_method('display', 'xtest_grab_control', grab_control) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__init__.py b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__init__.py new file mode 100644 index 0000000..6c7ebb2 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__init__.py @@ -0,0 +1,42 @@ +# Xlib.keysymdef -- X keysym defs +# +# Copyright (C) 2001 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +__all__ = [ + 'apl', + 'arabic', + 'cyrillic', + 'greek', + 'hebrew', + 'katakana', + 'korean', + 'latin1', + 'latin2', + 'latin3', + 'latin4', + 'miscellany', + 'publishing', + 'special', + 'technical', + 'thai', + 'xf86', + 'xk3270', + 'xkb', + ] diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3005518464786b4026b8897347c4142d1fd23ea GIT binary patch literal 369 zcmXw#u};G<5QZIE(o*OI6570FAtcLjugS@dV>xbVMxKFzosCz4 zH}J{}pmys-B86W%{omaUzwW;K{T``gR$u8`n~%9uzNkXRNBX}ZZFxVRG z`xZCKhurcQh3|^eqEZ!YCl)~ZFooE{i|9E|^zG&B^4y0@IgTz)eQPP>`$6D4jB%wH z`y}i7j?FX8w4=8c7ZA}0w7Eey;d3ogu=HkfM;D+MRAEd_>C#+}hoguV=-|X~A$bA? zeXO?<%A(AsFr$p2M#tFDl$-8VmQUvjuI*737F1Q#U;AwZL9jYL*bQGh_OKfK0TA$d A7XSbN literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/apl.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/apl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d723dda127d05ae829ea2c822bf294110de9b877 GIT binary patch literal 683 zcmY+Cy>8S%6ou_vjG> zZ7&Tpz(5mB+<*=2K@T@!6SrUs`_RV$3~&fTw7^0eY;?du7hLqf!x4kq8+IHX&KXYo*k!pW`1MSs1jjsQ z2UI=bRbDNSAF&{dce3hYxVK2LjQK5jP0gWyBS(c_J<~KBe_p%I_)6_{CvRHYjmBtJ jJB>T3t*)S@HLClK?bm~@psQ=Mj?z92fBxK+SJj}uJ$lr0 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/arabic.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/arabic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a46e1248a5e494e3e8fd3eb852dacb49eb026408 GIT binary patch literal 1764 zcmZvcOK;Ok6vrpDg;JV#(xfk1D6ayoX%S+BkkGxGD-bId=xnNK&IFspcCejR=>qjz z@EMT!1}qToH<t@EG^8;D8O%Z!bCAP4!ZMVxANp|s25=AtaR`QR7>02pY{U^5 z!BH5+O|S_!!)6?VG28-Mg5Or$3fpiSY{%`e19!kUj>Ase3A=C??8emP6l)T!`E&@;smS%d6C;fx-&Y{OWHB)lWtK(3Onh*VuyTCO=j%^_fxv92Ff|T9n zD2Esio%mK3;vvT>>S&Vz6Q1ZuieiSB`Pm*`w|UbCA)`y>~gelB`}DtA=wa6{IR2e*2aR^zr6YEn1CwQ_sH zg|ZN?@-tC6TcsN=TkK}7X~Zn^np08FvSs>oegj1}9OX|-n-kN@G0id?nsbCVjfyHP z<&PtODRaV@Q|j8R(r7uVY3!YxnpSMh5fcqwsqquSR*utbO|Uf-b0^4`FR%SvsbJnXWf*Jf$RWd(0=)MaI_ zJ)WtsNN=KCM8jI}T5%MUxvM}zs#D9^W(?gO; zNUxJ#A;qLRN)PFkKq{&4dneuLoqta}v!8kUw!D3-eX`CK7tc_{U*gi)$YHU%044ud zlv`XrBUaZatdPP*RKyc#0#BrgLMHJfn#_}Fijb*1g{BFa&QocIkeNJH43aS+{muJ&FuB7=w7H}0U6tak`X|a$c zTtiEREaN$}T*wNprIkFFR`EPq&GV^F$QoWiYk489<3+Td7gIeiAr~*D4ZMst@^Wh6 z6|{+0(q>*oTX;2XJXCL9M)#yu6Eiyqos(Rn*3NsGavx2k)a!Zlo@5q66Ga2iZ;C>>)q5 zP=H%0$X+_cK03_%sfXLBm)nWBgN|?~9px@M#s}y)AEZ9+rmNXcAr4SK2Pw>li1{$7 z+(QH0OM^@l;UlE+Q96-1R(D*xc8a2C*8$f9Hvl&RHvu;Tw*aSsTY=kv+krcPJApI6 zUBKPIJ;1%deZc*|1Hgm8L%_qpBfz7;W5DCU6Tp+eQ^3=}Gr+UJbHMY!3&4xOS>PP- z67Vwc3h*j03Y-UC16~K-0Nw=N0^SD3fOmi_@GkHk@ILSX@FDOK@GG{0LkEE(1RSKLfu2zXHDjzXMl*KY%}hzkt7ie*`+~ zhO#9+ZGC=K@7F@HK0cvl%Y@z$3acECX`#MBu>+6hjIKqaTDVV(XG?`19MVIYaESG3 zrUNz%eOwAo+8()(Y;i7ynZc1UqZvn98FRW-f;a*3`J#o2iY#+9S90DCU2=#y9H7G? zACO8$oNX8qF4e-NDWgW?dODfJ&6AP1o=O`HvkvEzB35eYNweBmdRW!tNo_DDnce$6 zj*hpA9jW8KE=PZSri0a=aVgw>+r#X*Pwu$Sk+Ih&cRZ(Cw-P55c3h}ZL)&vD=NkxJ za_Dq8Krifg!0&aop-s4q>$u&J;lLVmWX`-5GUO;yjmkBs!wx+r9}$<$3C9&O z&h)zMuO?+ZWe%}bURu6!e&{Xxh?=dGt{5Lk8MBXX7t1T7>S_5L@mQq6Njh7nX3GmR zBqL$rA%%oR_ocHVA)T#vXPw;}lpEG47t-XI;6Uz4S@CYikmVkwW%snmWwqv})N=4P z$_4o3p)f|>e3n*7o1;iiyIi!V!=ZP|M|8>N1CA^7I@5Q{{vN-q2h48;tGu9mhd2bHsa=K4HJJbsl*r{N85aA%!%H?n^`AZR~dA?9<9+ z{3g9})HNJSx!k%oqBgh!njTMRsrFDhCZVOVfYoC+%Q2=E>0{e zDjF-VK2_Q3WrR(AOggKf3**UTSPDhn@fn2Z#awWCV8*-+EVjyG0z68ju` P@Bb+Byi%#h#N_-7fW3pY literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/greek.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/greek.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a36e7c1c1a1a13b8b2909d07c6e04171b33b6529 GIT binary patch literal 2559 zcmb`J*-smH5XaXc2?Q_(-(WBh5)u+%1LO`NG2qy4Y-}YU(Rqm$&jzpXv9b*~>f!R%ruUhKo_T3^>}7vH6IFewC4cmrW4|-=^B8>9YONRa zmwMw$YNb{Xu930vvKWW;e*JW>fC30;0Sj({Em#9JxD~eIHrR&SVLR4BE!IID?tmRw z5B1mp4cG{cXay@aK@-}*hRx87Ezp8?u%iPU=maOaz=dvbqX#_b1uwQjE4D!!`oM?n z(2gC@fqw8~Cv;*Lbm{MI?1r7V6MC=*cHu7Ajk}>2dtndmfxWmF`mhi7;Xc@p`=KBE zVE_kU5C=g-5f0!17{VbK#$g!25jcnk;Se5z!+02u;1M{AN8yKuRX%Y;nzPdV`7ck!XC%@Y|VxdL!3i`XX`D$ppxWiX`Xdf>Pjw8_jsk{7T1WdW#uIUd%$r4-f3d0=b}feAEaNxJR6SwF*|p^|^8Cgi zP3BYOEm*Uf_IPkQu*SlnKrF`FlfkGSZ#L77b>Ren1R7aFmE3fgqO2M%3s>!IAd%qh zXdpHjShJa8x;?Ht8cauQhBKykV>ZHdY3v@Cn}~2do(sphCeBAf`p9g8>A(ypWvnF^ zPlS1`i7HFqZBDtoxSU;HL+&=_^iAW!^HL_m+bE~?IJ<7GDT5Ms_qsi&JJ{W47C9r!8+R&Pm&Sr~xvIkTm`~-nCJM^DJ~G?(i%M2X z7cx>hU5T*Siqaxi#MpgKS55I%l2w-e)#7TFzZcw~g*%jDGIdEC7sa15kdo{stJlo=4 zZ7MapR;{J-sSJl#6Phbdn{&0X64{hv_pI7VO^($D4wdK1PWD{+REd<246NWL?fmXGP5&Oc#HPY?hA literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/hebrew.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/hebrew.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..752d73e21a61d12f2b905d274ead15058361b534 GIT binary patch literal 1377 zcmZvcNpI6Y6o4m9_hw(4bYq7KwHD=yxWEBK#fd}pE|rrvsjWCph@D310p(xt2e|N8 z;1X`Z7nV}?rL?TQ(0Mk2{9pYoPvaqBu+yLXCRF+$Y30@ zn1CE6A&)62U>b^;fmtCX%t9G+Fo$`V#{w(}S;QhN2|0nYa8k%AEWv3k!x@}|vqH|{ zJe=<>EHCQMVvOm}2`>mQ3A=<>ggwG*!W+U{!aKry!Uw`f!Y9IK!WY6m;Va>Qa7g$@ z_)hpi_(}Lh_)Rz>-221W?d1zjapTse#w%^!-Na_6VsN9`HFT3ZNq<8%cuRBQzM;Zx zClOFJ*?&uKaKlOY4#GedDJ6=Ww(Q~>G$-Z7S7^I%6n#eD; z98&Gz1VRlA*lVJb^;@awrfSqxaR^ccSC>XI)CNZ<6N+l^hTI0JVHdMw$}XfzXJ?7D zRV{3(2U>B5PlqbExO|#I3lFrT;(v|0Jf-U-O)d1m{@rHqY1BJ4IlRrSK&O@_u1UHU zTU={Et+|ul@Lr_V)$OYGkR8&G{RotXX)D*;`Zixv?&$4iOSjk6jw!CXtz28bscds| zTQT&C((2h-)4aTTX-%6dj4dgY&d-$uZ-qGZhMiV;*zuI0A zrRdMadMdCVjYJ~D^3s46hnZqOIZWmI@nO2qPk3r}cED2dGMVeg!cMNc8|X*7tHRuX uWul?E(5bSrroq&%*JUofP)RkNihEY-d!raK1TFw%?w literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/katakana.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/katakana.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b5a98c1df22c957779e3452f4c6b6b474c34e1c GIT binary patch literal 2054 zcmciDS#J|p6bJAzNg#1z<0Wxc!oCDZh9vBSfC)jdf{kPwL5?b+!DmQ@*fW-A?8-05 z{SSOfrLKr;SyMaP0)nR(2On6;*O=b6qeyKXvJ1&!#41v zAKI}UIb#IOsxF$O)@4ZYX{eb@{A*arjH z4=Zp025|+f#6ehvD`7RRf;G4r*1BUIu7UOL*nn$cBd&u@xE_XZ18l~Pumv~4Rvdz1 z+zcbQ1!UX`+uSjV!!U*;Fpe^8$8E3!M`0(9!7dz!-MAh0;11Y}J7FL0f(hIW`*9CU z;$Ap_``{o>KpgkOA)JIMJOGFBAWT=|Lx;3;&61=&MLbPBLp)17M?6owK)gttCtf06 zCSD<4C0-+5C*C05B;F$4Cf*_5CEg?6Cq5u95EqF{#D~O3#K*)Z#HYk(#AV_Nah146 zTqkZ2pA%mYH;G%sm&8}Z*TgqOo%ojcj`*JVf%uX5iMUPJ#2vyRekOh)ekFb*ekacT zElH`NBToCt*;7VEE#);`bwciBQPGuCXUh4!X&FT))>tu$s;=qtr%Ot1QMJT+E^nA@ zJN#$rK3%&TZvj=!;V;+WIcs1;FaqAZJ26{R6sR25d2 zS#5YX>)oGavIADxyQE^t$Q$~+il$N4QM8VWG9k+2qMR1xF>$)tII9z^KF;cCRWoKBHU(gYj zo#8d>GsF5MS)U}kh9t`-SvJYCb1XZ@_Rq0BX|^ZL`ls3cH0z&c*%RzBNjX9H8Lk*w zuJJHM+_|Y1G`>cAyob?zT(fcu=cT*!^MCI#xu9F};gb8NjLBK8WE3^)sN%jm3u;N8 zI+~Cxs$P-v+G)91wH6G0d}MS?HZ@BfF1oL#GOwEQNjkcyR?TVw)id&qNo8a$cP*&AKO}KOFO{>z_?NpU)0PYwdQlr!Ix;-od&QduXVu7O-Rebt!6h_SU7a z9f;KYc1O6@_OEzH1zuBc`XKyYbE1P+i8hZs@W?IyNc?Y8?^eUHTF~z5t4k3(-2Ftb IlyJZE`wifaVE_OC literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/korean.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/korean.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f48e4b1d576cd5edb968817b03bf94a0648bd0a7 GIT binary patch literal 3845 zcmZ{n*Iye)5XTR9Ocx+JxZAiO1MbEJgKQAh6br^hKA1xs5+_B4e0a%+{1tvqk5irA zd$&`Rt|&cDua2GS7iVYpoZCY-58u!3Z)Rs^XLk=clasSpVL##Xr^ioZDau)zT>i;0 z2NzDU(Fp|=P%r~Ba1PADxiA;!!91J~^Kk(zz=g077r`RTgiKrvi!lqbFdMQl2XZhM zaxo9`Fdy=<01D6n4lIO1EP^5|hGKMr6HA~3OQ96YpbX2Q94nv#E1?prpbD#@8f%~i zm%tKS3QKVrEW_on99O^!TnQ_26|BP5uo~CE8mxs{TnlS)9jwFkupT$S2CRcRbb$*u z!bYrzdTf9OY=lPK1eilJ8Z`tumg9(PHciE+y%REH|)keum|_T zUTlVD+z0!x1zNBbTG0(|+zb(gj)!=5^f{hPB=-pgK#I|F2db}dkFUuP7&@S+)sFb@F3wK z!o!3|2#*pTBRo!cg775aDZPI!ax zCgCkYg77xs9m2bW_XzJ3J|KKZND@9GqzE4qJ|TQc_>Ay5;S0i-gs%u^311VwA$&{t zj_^I<2f~kpp9nt_ej)ry_>FLm@H^o=;R4|g!k>h{2!9j)A^c0YNVvq%T^mSc4t4n2 zRKp(+rtrwwvVk0%6?o(uaV1L%z08y&edL~j>u=qRlXgmdM*wy z*H~J%-f@uSdF?d@fxczI65(w6i1d%ZHNIe!fho zQeiD@L!-94KwG>O!%kOfy*=BV2q@*ZrniI0>G4Sq+~X6^&*myUz;s<4maPu+wb{b*XOOa$#-%Hj#tq`q+wyT;+;ZvT z;_-2vU*U9jaoy7Mnzt@}f!L3&c2SB=xrC`1lObybG1hFDXqaZphrSsJ=UqljnQ!};%ez^ zcTH)=lq;x@xWd!1@sQD2SKr`@>M?CYSRDbMg=7^xyiz^gp!|hRwk4} zbIiSpD-w#slq;7dl(J;?iiA>OvZy?v6qxRXr4*pFDxnl7OIVnqq@#qT5ko=Qg&SpW z;o@ZZ3e82bmAgv;g@F_RUnsS4sUCGZ1 zWsP{KV%8ogD`MIfcJaYS>X%nnx-%Q8awX%7jv7ZZ5z0`kaWtZrXpJk1T!w literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin1.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin1.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd413c9f3a5faa350b26614da5016e4109f9810d GIT binary patch literal 4960 zcmcK62XGuk76#xI&Ox%A$QcY6u-7?&G03)T%RzFG93H{U?%&dmH9NDK*_FK}t;sp( zoWbOrGZ*0km&IN_E^(2Ai(H)ljc}`6)D_g#skC2B=zjgWU-wFH*47S9#Xp7j-^h)t zOQqi7%||~qy%!(U_e-U&Ng*XE)JP3>lAX{``k}w{#{e0Cfie(-WKjGWjKMMlLu4q1 z$}kL*;TSHpsFga@$q0;)deqBEjFeFrC8IG~#$b$$#aP)HJIgNEMRvumvKw}j-Lbpu zfjwkT>?wO;FWDP=%Rbmg_Qk%kANG^|vA-OE1LQy)DC00r4#GilFbzVuh^2N?DCn(u&p6hE`dFHd%``vJPuyJ=Td}y&MaX<8Z7T zkK^P794{Mif}DsA;^0Kdz>zF60%XMi(hegXXqOy1#6?av!j(>J6c3$}hbKPr62O-N z0_j3QLUc)lP>P78gran#B%9DJo3TmC*eqL6mXokWPR2=c3Qm?&af+OVQ>B8_WGgCi zI=0FgI9<-f8FCiRl(TV`oP)FFT%054;aoW%=g9>)UoON2auF_+i*b=$f{W!+Tq2jn zpUZKnT!G8vN?a~i;R?ALSIRZGO0LD#aviRb>v65zfa~N&TrW4_2DuqG$}PA_ZjC>; z;byrVx5yp1Rqn)Xau;rwyK#rygFEG3+$Gy^x7>$&M4`7=-i2LLr+%FH~0eJ)u z%Ac@(I3AHF@TfeA$K)wIE>GhLc?M6)vv^9L!_)FSo{<;uth|WlzdZhxclV9Y$GiKH{mB93Kr)UTL=Gm0kn!YDau_+BOdu0UnoJ^-$rLh` zOe53D3^J36ah(P3jVLsk%&Et~RSJ>I!wGx=LNGwyJIF8g;F@PF=4`wJuIE6FS*WQ`7>mbeZ@z z(ghr0-zEiNb0^BWZq^O6rM%Xwu(0ZC5+g zq;RfYZ&W)~PtB{o8mI-eOAXaXO;*07*WKzSb+cMlw`itZ0i&4?)cJ=xF@2iMoBLkp zU35K|D%ZsiGI7m2lk>v&$$3GrDcK}?61ai6e?8al(7ll@h4Eg`ma817Y?9rT34>1K zXL?UjWU{(@SPHm~2~Ffinr1dAlx-b?5bg1{^j+Un>*KZ^CD-#zK1d45^XLb~?Z-4% zjt`%&^9oIe%cKnS*yNpT7;jddAeeX`C&lAQOO6(6UfdK!B|TrEj#bRX?Y2MR_lA=# z6^-urd`XjykFgW)g+i`6GJc($O|FTK%j~iSal(#n!N9lCIPZMC*rj;UjCS5WGh2+f zLwxo^9y!K}Z*z{8EL7yO38uL+Hjr?$tKmyBymo%A=%XJp4qIc(U26IwQaD4 z;A9&@)|1D(p;5~^|D(w;WTTDVXrnjwiO!IXHY7VW*-lNiQ_~KenrtU-pvKn4x{(@- zInB5^$(Zq4Y`hj5ucc2sZDps}VncJ+=1X4DEqG;}UQ3Yi+;|mrkTx5+%|>qP6PeR% zv*9?<`lKZnuXSnoeMV@J}BxV<)x zNse6K+Qb|Dqv*y)H+`b(QMMsDm}@(^wo~tSpl%m-a&0Hp#`M<2w>1fDoWRBj`V7v| z0z0+9hGb3PcDoV(uxPX7E1H)j8@FWRmiokHekB`>oyti|E?H6Qz&7RWZMLQOA4Tdz zN$34ydO_%RnKekev+}4h&4DA^)rZPNvrZ4QRHXb^nGAIdPqv+M3;g$Y9 zp9<}!;cZaOKnEIJTN&`_;(e;YKWXEUJ6GzGB^k9#WkiqO>bltMKWV7{UprmIA$663 zed?y^YNoonx~7V@(;l|mdaH9Az3W@4`W}6wJH&1dz1^{)u7Z|I-;CMqt<=b*w_Uj8 zp$5{p$q<^K##FSq9nr?soOfuqLsGUVIyc4k__*+PHEcT@MW1N~if!_7q5hXl|9j*e VW^M~bI*MDJKvd*JW3>@A@7r&csOKM zhC**~nEr&PipdXNaX7>w3UQdiJcDL%1yyh*Rq{-l$+Kt{&!*WNp$Jz|6-Oz`F^X}V z;+&uaCn?D(N^vz+a}CvSE!A=z)p0%5^BkJP4b;Gm)W~ybF3+QRJfG(C0$RWeX(2D7 zMZB06^AcLZOKB-Dqh;JgO}w0z^9owQD`_RKqE*~X&D=sQ+)AyynpX1~TElB;Ew@n{ zw^KW7r13gh#~swcX-ab^b@F;z&l_k1Z={X9i8k?O+Fabyy45)1Ep8kIjseGk6TnH} z6mS|i1DplU0q21Wz(wE^a2dD)Tm`NH*MS?rP2d)A8@L191?~a&fd{}t;4$z7cnUlN zo&zs{G2kWe3V02?0p0@dfcL-$;3Mz}_zZjjz5)}#H{ciW9rywK2L5>HY27j&-M{C+ z4tvnH#PE2;s|OrW5Pr8i=Q{SV7_aiW-5K4nEx+v5GkI5bdu2D~33@Yv4b#+pNuN@a zQj_e)JvHeAc0sW1`h)bT@fb8!B9$4KZz{)}bVSxbQroy(QjzjJ_Lhg-C!b;O ze#fu|$D!&Es<3@uaC=8N>ngsfx|u+!!ihk9A=_A+m4XBDE#+ZJ1%lbZU})rn4cIwS zjD7O{K8Wv5$H!s%t2h~&#Glts(nc&->vD{ONNatDV`mMwThCjWA>n8{yLW2^VHGsf z7|^mscgVIn+dI-)&TvIrR?iIUgCeKx$J1d^%oRsi9MnwRHLP@dw)iu$ZN%ohDYiS? zy;0t8Bb00M_@yEo4v!^jOVP1dbtxjNculElOd(lUiUp4TgH(Mf9uWHm>V|LSAIt96 sG?bFk$~RCq%BnKIvSV#yDJ5O}LH@C9(Et0DnfiXox*Py-Eh(6Is)tU?u6U(84yfu>&3KLKin-Gwp4i5sxaGCLR+G2~P-53C{@62`>mQ39ksR32zAR2|3{d z;UnQQ;S1ph;V0o2;kUw#t=`<&zkc_sjH6)8=QiD45xKL;fzR*HO;ztY!yw@p#PhnU z2E&LaCym!ijTGXQLcEe|C@0js&!t>sjEanVr9N8L|F?{u(m!PfOLkDQ^t9VW?9Gy* zSa)gAJ!MBrc2u$yJ1b&kp$@ep`X!EmO{Ous5{ZOwvs)qxLJ{vdv#IOxi1qh&S;D6Y z^Tm*bY3v2loeLMYnG`WUA3E;X8F9(>$&Ps{(+Tne<~y-aZDD#`yEF-K=JU(ZIkk#@ yLMau#Rdrp@t#)SQtzKs5&2DDqW-F_ol!dT6S)(KteZ|D$R*e0}KCq*+YVRLO7ye!V literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin4.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/latin4.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abb5023856bf8d5b054bf862959123a136773eb7 GIT binary patch literal 1109 zcma)*%WD%+6vk(gHqAR}lD^*$kSy$Abt!^qDWM^PG*Hf_OmnWuC6k$9G6`fC{|CXn zqTpjE3ck>tPz6ypF`x)8+z4v3vY7C7?$}89e9#FM44JhhP|o!G}H=!4dGI9|9PFAO<0XAqZm_A{c=v zMj?hVh+`Z^aTF4mfFvd%g((=rF&M{jn7|2`#7UUKDVWA-n86vC#aWocIhe&{?@1ra5)bs53NdcPb+|=lagHazPNbL?Pev zqWFCGzBHc~;#8sLLNxm;nhOcKm|zG(SrlqQbZrn_>(1YjI`jh^f>P0K<-En~Y+c#r zmSJ)`tJd^FiCN0IY(}Xwy{>3{Pca*I$Wy{czQX4!(P3S#AZQO~Ns literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/miscellany.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/miscellany.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1f12cdca975fe4bfb811e1b9c972460b1294ae6 GIT binary patch literal 4176 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/special.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/special.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2165ffe3395dbb7ff833fd6a2132411e37372157 GIT binary patch literal 852 zcmZ|NO>fgM7zgmAUDq^i*4M3_5FcO%7HtzkNQetu5ECa3)58I!dEC}&8b^*>R8Hl> zSKu@7Rp7E?l?yKeiFd}zn|8ua0@6e^AAWxPw-Z~IpF56i=oXzk8{~3^aYTcE&HP&| zP!~@OG{8U;Ow2(J^N`0CSiu4ma1~au2t~BO!V;9w1{=#z#tKx>0SDJ$4XaSa8q}~3 zb!hy83unzydqu`N5mWAE%AbCow7L z6$6!ay1Z6CO=!b$6tLdeCHkxX5?_iq z=3zhJA&b*L4}|0o)1mK$JIm4Da&&n)y0RQyO|OIYS4l~qEf z6DC#HlTVEWy_nN`?kH65P01&0*S*W7h`8GK#-YAJ>E77CC`P>V(qv@%2Z6t6UuPDi1m`HnlQhYB%5#AVT%;mT(G-`c#APb;G)?mi&2WV(JWI1YM{_(+^SnR{yhw|D zl#cQ-I>t-1#LKkI$LTnqpc8zOPVx$^@F_aQr|C4Gp)-7z&hjd)@;N%k=jl9OpbNZ4 zYrIbD?2^kD>0)PNbyGf-bsYIL@C@)Q@Eq_w@B;86a07S=co}#FcoldJcpZ2HcoTRF zcpG>Jco%pNcpvxx_z?IA_!#&E_!RgI_#C(id;xq7d;@$7+yY|YJK%fZ2jEBGC*W7$ z58zMWFW_(BAA^TiH{!|54?XIOTBJReRnL!$#*TvKepfxv^6_e*l&D65wpAuesz_{W zQw5c+Alk7D#%>E84J%4R-SFC$_NrG!6vJuC@UWq?oMdXbUEk+5sr$TmPTFnL(?W$Y zJgH>rNhh+EyIcdY)KxKc=%XQ-eNk;`zk@DCJZl2B_CJx`Befb0FOq@UGt!Q8F=-PU z2?x&MY7jNu{7-bxItIltyn_jLBx4M*tJh%wTk%C0Ms-h#Yc2D}#*Ie>QDR_{Z7saW zG`J^Y=Y>v~jHoWOs0CWYu-cxM$;gnBswS0;I&sz*%G>fidndeRQwNVpvl|iTO(c{J z>6;g|(}Ju8%J0ZpJO+_Q)0ZN&@{)y$?2SZZa65CzQdPgjf~B%Uq-JRK(XS589mT6a zD=mc+%KTs(a-L$VpPJ?_W0mF-MAGwFXxTPHwS|?gwN#>nd2u;Bt%K{f)t0Hi8OnC! ziHSrGt}AQZaBkzz^3D~vp(6JIBP}-FN2E62O?1gK+Gd~b{g)ne+d{QnUv9b0PE-%n zUF#d0ZYU$M)-<1qw=F{VGNM;SC+sv>)Z9o^>k8AXH#>K-_cj7<`Qko(k9ivYpTnZz zZzGvZreB=tPWH=lJ*Sw`IxI@FJ*Uv0S?D>Xl$FJvQ|>2Bq6v4`&oA|yN`GOw=gjV@ zU0Ufmi~WSVb&~u-LWLao(j|5ToSM; Xw!-?XO7h&H^sppfequu3ZC3LyF6dJi literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/thai.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/thai.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c1c262df1f1ba59fe7b6965ba102ce93ee372d5 GIT binary patch literal 2799 zcmZXW*K-qB6o=PTV=Q+Yo8G|`3rz35o9;}=d10=7gm*{M-W^GcM{mwwk>~V~kluSj zI;1FF(L);PWrjd1PdUGpwRdeaqi^mx_uNzO)#y?zR%6M>yL!=HTy0sGAyht9!;5RZ zvbxP;i!839Djq{)cr1OTsD>xgWUi%Jj!}&3sE+HY zo*Srv8>x|-sEM1YnOmrZTd9@XsEw!46mF+>?w}5yN>h0nP2=e_ooCPto=G!#7R}<> zG@Iwp9G**ac^=K<`81yw&;nja3waSO;>EO>JE@bG&=OusOL-YB+W??xt>DMXPu!hfhS$rw1GF$M&3l5cr$J0EwqKV(pKI^+ju)| z=N+_zchXMYMZ0)6?dCnShxgK6-bed*KkerObbt@iK|Vx>xQBZ9FdgP2bcB!6Q9ee; z_&6Qs6Lf-4(#d>p=S|M-G0Sr90PY0t0`3Ox0qzCv1I_{W0}lY_fd_$yfQNxcfJcGH zfX9I+fG2^cfTw|HfMO;}iNl}*? zMksuh8>Jb%;gEJqO_4(xC4St2Qe8#o4rq74H<9{n-7gl#Z=i7GNEmzAWS~@Aagx

7AThl8*hMhI3$k<*^asboZ9>m0IZtwhM#+LgT1+Le{5NCeOJ#Z;Ttx!O&* zMr6&2q!DvEC&pnd;vi@Hl3ZgXlK30Zg1|`HWD1rTzH!p0`;?QG)`#Qsw3kxGzzfoh zIyj@xMCuRrrQGm5wj+a+{j5rRC^PJNTBnscAT5^uh37LmhN3@w1UKWnaRCQEhEIo*80F#_Y@SFlCLK7q(s|Dwo<%n$~;D z$t%~@(FiJ|l$p0QStg^Ba`8=4Fo`A!Ic>7aitLOucSgy6!ek9|Kam)DKGLILKk{Ha z+mSozmpUrVHaVV_C9Z4OfIemCMmmnX5;#_);%f5(f^FQgv@chqtrE?sWl~P5xuQ?0 zWbo4S(c3Pk^D3<)Ek}mRkujLGL?sUyz-R{BEL|s z#8I{r8C@!o%=)hBy~r*eWB5w}13bJiIuz02LXKP)5$(uTfGE{Q-Syjv+z5rIL=p9$ zRQjBC4gX25pNgm5Tzq%NIh*K?_c|HvIk_I?yW%7h-_>&D$i`1$H<`$1^Jz|;iAz(QE-!z*dUIN{pGs`a+#-SS4=8&`BL*h} z!$22^)8`bdj-pA$1S^-_F|%N`72Bp2tmfegBk_#uvO(0$gb3mozoQZu-o3RhbF<9y Ef4*U{z5oCK literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xf86.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xf86.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63b2bdb1e260595b8a14bdcbbf28c5b89c714d35 GIT binary patch literal 6201 zcmbuDNploO7ROucn?N8yAdJmwjBOASAcT#vrPhX}mPB_;EuI&-)Gs9!s;+8RS4*@v z@V?-E!~4GBeYYnj<_pYRG&iD8j+prX6XVnPFf;kjQdO4PI!wgq@QccSWo5p6OJ=tI zQeC|wCjavP{PV>5EwR|&&h2`+`{PLX2Y+<0`7+1+;({(n4NDi+C|D<|VX* zm(o&RM$33PE$0=qf>+W?UPY_8nyPs!hfhHI#X*V0;EN9(wjYI!}a=MA)hH_}F~ zqdMM1n|L#A=6b5?d7ZKYQBc9;cMwy-bed*KkerRYTyHOfE%fio2ZEo(m_5%hxjlZ=4NW< zBXopYsD+QxQNE6@g5C_xR3g{pZa-#2KXeMyo9^a& z=pMe8?&bUFK0Zrl`5c|&`{{mufF9rn=|O&o9^!}TVSa=j;YaCFevBUD$LVo?f}Y^> zbe^B2C;2IQil3&Z`5AhKpQUH{IeLztr|0OzG`j)?=@A!NAo`0Yp_(%GYf1;mC zKkxm6S@oY~HRb|fA+QKo3@ibb0yV%|U>#5ktOqs#8-Y4t6R;Vm2ets00b7B~fh&M* zz;<8;|p`_5fD_dx5KgYk+HkeZYR80XP6O0!_d{;1F;aXaY%d1K>m8Bj97;6W}87HSi7aE$|)iJ@5nY zBk&XOGf?$!i3PwyU=gqwSOP2smI2Fw6~Ibh6|fE14(tGS0=t0S5`BArF4qkAj0|_S zG>;@47QIe(vRtPXyUjJnCp=pe3WNFb=6PSVJJWV~L-49+lzZ_>zuiAJriYU9{6o!o zp@ymthDtb*>EorWCCY1pcPY=Xd9+mC6bP+FHl1E)TDU`wRm_R<+Bt6$MNd?8P8w!G z%-eauGD;QSr#vTLAq}`^J3d7A# zlxu^wT2WGD9hb}N0x@n_*`j55jvEvY^{LoOwBhH`26Iw{6n zQJB!{P&OimLI-7xNg)jh{nv3?WIgS#RMr*3P8n0uhLypxGMSA2AY};=iDIWQ<+!FN z3VLnI=L1HuAS$$kVAIfAq7-*>d6`qL)`p~$9T!2@j#j16Rq zHtU+ju7DT@kqbxcHHvn2;(#{V7aA*trb^*prEsWHI9w?-R|-ceg_cU;Xr<6vDYR7z z@k*h+Qs}4@I<=!(^Lfk68lLIcy<*JML5aLbVpG&v(B?RknT7Sx-k;Lh+3sZJPHB4uJ#@#Jtgv*Rb)3mt zjvFoNE<@&bXn2>S%hOCdMY(^4<=X3v&ne%8;ZBN(Z3!Vf(;n9!B!pe;X`9;~h=eLp zN~vlM7t<%EwHIU~Qpj>avhJHe6>CyZ1h?idZfZY5cdS-Rd+GGRS`!_>)=D(3T!Jdwg1LE0!x4j9r6S`lteZYPmLEbTZ} zL3<$7Sd6;?(KNT33g7XqA!zt3r>a zO}Qt80Z0i8=W_UV$dqLo#yjogQRjNqNfAlYE*#-{s8cd&ok)$tg?gw|u^=m&wZYxy zsBmpredX|4qxPh{!D(k4YYW#K=>4{ibEwHnN4R3;v4ojb7s$}FJ)$(~%(=~EGBT8* z50afdX0+baDDuKskQ-olzYVqoT)Hdm>nvKd?|ziiok zZq21FyJupX6xaUl*;k^hk$ujs0;+-4>XX`E>UYh=)?KRKC12sOCc?Gqd1FLD$C(&D zQr)Eu(I@|FIkFV1{hoMSsoVaD{wTjE-bTj7;BqoW7>~uu4!-P<EI6q#@#5O2uhpHKaSo$(N$+iJ_-&zOqhDuVxOD%lGZ7xs%Pr{Oq0efj_BY z4LbU(Q0-b(cJ=Ccov%cU^G*C;=r3uOn8WvnpRPfKHtj&nHg5ZCtk(Ub+yed!1d@{` literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xk3270.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xk3270.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f590ceb76c837f2711e802b9166ecb6085f42096 GIT binary patch literal 1114 zcmY+D%}(1u5XU!!kC4QPlQ`cARn-%R;t~$MRFxorL`z!=NJVo&CbJMLj$_$tgry$R zr|2V8eUJdzG|Zs0r39{9P?>r}t#i;gda_A$Q>%zS9>X}!U@cIC^VaA0c=KlpIy z7yna^Ov@EfmQ(I<;b%jakFGBKOlY0#ZpV#I+}MeN&bbpyu`7h>m%M)SNo3)G&7#m>&QP#;fxV(X?@Bz(NA15Tfrr3 zH{4M#=<9%cjyFVpt=y$TSa~$+LWsSES9VRofG$ UENaYy=E^*oT=^o|PlI0n0pAf*7ytkO literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xkb.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/keysymdef/__pycache__/xkb.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c787a85337dec68413ebe77a749db324610cc110 GIT binary patch literal 3788 zcmZ{nX>;2~5{4n)w(k3~Wy`mGh!!d3bevd{%5K#bv$d&W@l$ql?Y-G}Pw#FLyfXv|$_zg|1-#SU)6>&UO224sKB9%6>~}xk z_+_J}eSw$g(@=hR{&D#9iN+df+&~SyhxYJZ+ROWBAMdCAe1Hz{K|08X=nx;K!+eB} za3eKx6E$%&HFFEKa4WTP8?|vewQ~n`a3^(g7joS+0>p({K_W1OTUrzpkaG|m$=!LQIO{3^Z5uhDD#I=#+s&>Q?Fy~$VU zD!)Z<@in@}Z`0fS4!y(I={ir+Bu~*4Pt!Etpc_0xGklY7^1Jjd-=bUm9=*r6={C>O zEYHy#&(l0F&;l>gBHy7qyhKZ!rZg|pGOy4I-=({JkM8j*t@3@k&qTxz=m9^Zhx~{h z@nd?-I_dm`p0Gg%XDGuancF-ftcLG3&DsO(1@-~^fscL&aR5&TfkVJy;0VwNGy%;( z3(yLj0EU5+z$xG~a0WOFoCD4SBftgVB5(<~42%K^;0iDXB!Lt#4lDw9fF&ReECVaR zUEm(D3fu<>cmO;E9s!R59e4s1fKP#60lx-51G2yefCuo^z??c7VH+4Wk=jSr9wv9 zP0!6`%g(i$@@+5sDm$4?B+ZLwfiCq@PuZ#}sa+z|MNi~+nO3FRgk~(ykHYqr!^X7Q zxU)vZHcFu?Dbv=<;nxCv*~nB%H0S1pK5IEbU&)rb%T`r!+I{L&&b4TGfo0eg^S-iq zjV?XAjZv>T%(jw633~$|XluuNFn64b6U`xUlhA(QI2Fn}m zT2qd@7bo3dqwMXMqU~l-*QuQ6yPnD;I&geJ#fvHzUkM9ZFOn=!wEvXr1eTL?bH2Xf zu<-2gCQ3u)%%?5ithe4)Uca%G-7tLXLs9A~D^tP=gr_fL-WO(2YKrV2mYTyi76$9< zo{<;TSHsK&qJ*xOtET0dxve!@Jgb@nmd&En5}9lnrsq1<TZ4B-ji@~e_G@+@avcA~O!bD8iOWjd8)O#@q@eN}dXE!#G#xwz}DBR1txrGe!J zhAfAC%e$5-SohtW!zJ9FRDH2!)vQ!f&j{Oniqvs&YToWzUXTl$K5cqJs9BIhTSu33 zUq_e2xJ$>E*|PAqEXN3ho)%s{ydo6rx@ijEU)66oMpz9wE|D}N1ZNC$Gg`x~FNv%$ zg4<%-k5t@bIy^>PgXLsc1XJu*(}87fZpT$*HWxNzjVT7YDk32}zTZNay=`od)zOlX zh7q}*V=Fw>q_8XQxY|Y6l6@<`AaEIxpoR<05GmnM#XaOOp={N483aYBN-7Kv7HRO4 zhNw(jRHpbEjnv6p5V(#$y=Dh;N^147I$E-hma3zT*U=_qn?`#~XY46EydbrEO|IpY zG1=_9?UQxYR9$tvt~ybxdd9lSA$~j4p*kk#zOsL)BwtceFDc_MDHHO?CyJw*A6;1^ z%f1s{I5G04BC^KSOa>0dubz%^{h9V0f91cpm)LTG#I$GSMKZB$d2ZGUW{q$#HiVa$ zn!T0C3n!njtxO`j9c;KxYIH1_@U1{x4u8QmjdkHCRUln-f1ef_3Sh&sO;o>d+$z*5|w@YSgH)tOy(_Z zWhfO@?XUdQ{^~Swsu(J&I*0OADX3>fWvOZqFSI(JOh9c_O-O}R#>!oVQVGO^y!@<^ bk0 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +__all__ = [ + 'display', + 'event', + 'request', + 'rq', + 'structs', + ] diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e81df66e5f8753a0593c4f83dcd8e8123d3640c GIT binary patch literal 249 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/event.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/__pycache__/event.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b51a88bb2a81a29809c48afc62463e826cc31cd1 GIT binary patch literal 24833 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

( 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/display.py b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/display.py new file mode 100644 index 0000000..8531ee3 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/display.py @@ -0,0 +1,1075 @@ +# -*- coding: utf-8 -*- +# +# Xlib.protocol.display -- core display communication +# +# Copyright (C) 2000-2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Standard modules +import errno +import math +import select +import socket +import struct +import sys + +# Python 2/3 compatibility. +from six import PY3, byte2int, indexbytes + +# Xlib modules +from .. import error +from ..ext import ge + +from ..support import lock, connect + +# Xlib.protocol modules +from . import rq +from . import event + +if PY3: + + class bytesview(object): + + def __init__(self, data, offset=0, size=None): + if size is None: + size = len(data)-offset + if isinstance(data, bytes): + view = memoryview(data) + elif isinstance(data, bytesview): + view = data.view + else: + raise TypeError('unsupported type: {}'.format(type(data))) + self.view = view[offset:offset+size] + + def __len__(self): + return len(self.view) + + def __getitem__(self, key): + if isinstance(key, slice): + return bytes(self.view[key]) + return self.view[key] + +else: + + def bytesview(data, offset=0, size=None): + if not isinstance(data, (bytes, buffer)): + raise TypeError('unsupported type: {}'.format(type(data))) + if size is None: + size = len(data)-offset + return buffer(data, offset, size) + + +class Display(object): + extension_major_opcodes = {} + error_classes = error.xerror_class.copy() + event_classes = event.event_class.copy() + + def __init__(self, display = None): + name, protocol, host, displayno, screenno = connect.get_display(display) + + self.display_name = name + self.default_screen = screenno + + self.socket = connect.get_socket(name, protocol, host, displayno) + + auth_name, auth_data = connect.get_auth(self.socket, name, + protocol, host, displayno) + + # Internal structures for communication, grouped + # by their function and locks + + # Socket error indicator, set when the socket is closed + # in one way or another + self.socket_error_lock = lock.allocate_lock() + self.socket_error = None + + # Event queue + self.event_queue_read_lock = lock.allocate_lock() + self.event_queue_write_lock = lock.allocate_lock() + self.event_queue = [] + + # Unsent request queue and sequence number counter + self.request_queue_lock = lock.allocate_lock() + self.request_serial = 1 + self.request_queue = [] + + # Send-and-receive loop, see function send_and_receive + # for a detailed explanation + self.send_recv_lock = lock.allocate_lock() + self.send_active = 0 + self.recv_active = 0 + + self.event_waiting = 0 + self.event_wait_lock = lock.allocate_lock() + self.request_waiting = 0 + self.request_wait_lock = lock.allocate_lock() + + # Calculate optimal default buffer size for recv. + buffer_size = self.socket.getsockopt(socket.SOL_SOCKET, + socket.SO_RCVBUF) + buffer_size = math.pow(2, math.floor(math.log(buffer_size, 2))) + self.recv_buffer_size = int(buffer_size) + + # Data used by the send-and-receive loop + self.sent_requests = [] + self.recv_packet_len = 0 + self.data_send = b'' + self.data_recv = b'' + self.data_sent_bytes = 0 + + # Resource ID structures + self.resource_id_lock = lock.allocate_lock() + self.resource_ids = {} + self.last_resource_id = 0 + + # Use an default error handler, one which just prints the error + self.error_handler = None + + + # Right, now we're all set up for the connection setup + # request with the server. + + # Figure out which endianness the hardware uses + self.big_endian = struct.unpack('BB', struct.pack('H', 0x0100))[0] + + if self.big_endian: + order = 0x42 + else: + order = 0x6c + + # Send connection setup + r = ConnectionSetupRequest(self, + byte_order = order, + protocol_major = 11, + protocol_minor = 0, + auth_prot_name = auth_name, + auth_prot_data = auth_data) + + # Did connection fail? + if r.status != 1: + raise error.DisplayConnectionError(self.display_name, r.reason) + + # Set up remaining info + self.info = r + self.default_screen = min(self.default_screen, len(self.info.roots) - 1) + + + # + # Public interface + # + + def get_display_name(self): + return self.display_name + + def get_default_screen(self): + return self.default_screen + + def fileno(self): + self.check_for_error() + return self.socket.fileno() + + def next_event(self): + self.check_for_error() + + # Main lock, so that only one thread at a time performs the + # event waiting code. This at least guarantees that the first + # thread calling next_event() will get the next event, although + # no order is guaranteed among other threads calling next_event() + # while the first is blocking. + + self.event_queue_read_lock.acquire() + + # Lock event queue, so we can check if it is empty + self.event_queue_write_lock.acquire() + + # We have too loop until we get an event, as + # we might be woken up when there is no event. + + while not self.event_queue: + + # Lock send_recv so no send_and_receive + # can start or stop while we're checking + # whether there are one active. + self.send_recv_lock.acquire() + + # Release event queue to allow an send_and_recv to + # insert any now. + self.event_queue_write_lock.release() + + # Call send_and_recv, which will return when + # something has occured + self.send_and_recv(event = True) + + # Before looping around, lock the event queue against + # modifications. + self.event_queue_write_lock.acquire() + + # Whiew, we have an event! Remove it from + # the event queue and relaese its write lock. + + event = self.event_queue[0] + del self.event_queue[0] + self.event_queue_write_lock.release() + + # Finally, allow any other threads which have called next_event() + # while we were waiting to proceed. + + self.event_queue_read_lock.release() + + # And return the event! + return event + + def pending_events(self): + self.check_for_error() + + # Make a send_and_recv pass, receiving any events + self.send_recv_lock.acquire() + self.send_and_recv(recv = True) + + # Lock the queue, get the event count, and unlock again. + self.event_queue_write_lock.acquire() + count = len(self.event_queue) + self.event_queue_write_lock.release() + + return count + + def flush(self): + self.check_for_error() + self.send_recv_lock.acquire() + self.send_and_recv(flush = True) + + def close(self): + self.flush() + self.close_internal('client') + + def set_error_handler(self, handler): + self.error_handler = handler + + + def allocate_resource_id(self): + """id = d.allocate_resource_id() + + Allocate a new X resource id number ID. + + Raises ResourceIDError if there are no free resource ids. + """ + + self.resource_id_lock.acquire() + try: + i = self.last_resource_id + while i in self.resource_ids: + i = i + 1 + if i > self.info.resource_id_mask: + i = 0 + if i == self.last_resource_id: + raise error.ResourceIDError('out of resource ids') + + self.resource_ids[i] = None + self.last_resource_id = i + return self.info.resource_id_base | i + finally: + self.resource_id_lock.release() + + def free_resource_id(self, rid): + """d.free_resource_id(rid) + + Free resource id RID. Attempts to free a resource id which + isn't allocated by us are ignored. + """ + + self.resource_id_lock.acquire() + try: + i = rid & self.info.resource_id_mask + + # Attempting to free a resource id outside our range + if rid - i != self.info.resource_id_base: + return None + + try: + del self.resource_ids[i] + except KeyError: + pass + finally: + self.resource_id_lock.release() + + + + def get_resource_class(self, class_name, default = None): + """class = d.get_resource_class(class_name, default = None) + + Return the class to be used for X resource objects of type + CLASS_NAME, or DEFAULT if no such class is set. + """ + + return self.resource_classes.get(class_name, default) + + def set_extension_major(self, extname, major): + self.extension_major_opcodes[extname] = major + + def get_extension_major(self, extname): + return self.extension_major_opcodes[extname] + + def add_extension_event(self, code, evt, subcode=None): + if subcode == None: + self.event_classes[code] = evt + else: + if not code in self.event_classes: + self.event_classes[code] = {subcode: evt} + else: + self.event_classes[code][subcode] = evt + + def add_extension_error(self, code, err): + self.error_classes[code] = err + + + # + # Private functions + # + + def check_for_error(self): + self.socket_error_lock.acquire() + err = self.socket_error + self.socket_error_lock.release() + + if err: + raise err + + def send_request(self, request, wait_for_response): + if self.socket_error: + raise self.socket_error + + self.request_queue_lock.acquire() + + request._serial = self.request_serial + self.request_serial = (self.request_serial + 1) % 65536 + + self.request_queue.append((request, wait_for_response)) + qlen = len(self.request_queue) + + self.request_queue_lock.release() + +# if qlen > 10: +# self.flush() + + def close_internal(self, whom): + # Clear out data structures + self.request_queue = None + self.sent_requests = None + self.event_queue = None + self.data_send = None + self.data_recv = None + + # Close the connection + self.socket.close() + + # Set a connection closed indicator + self.socket_error_lock.acquire() + self.socket_error = error.ConnectionClosedError(whom) + self.socket_error_lock.release() + + + def send_and_recv(self, flush = False, event = False, request = None, recv = False): + """send_and_recv(flush = None, event = None, request = None, recv = None) + + Perform I/O, or wait for some other thread to do it for us. + + send_recv_lock MUST be LOCKED when send_and_recv is called. + It will be UNLOCKED at return. + + Exactly or one of the parameters flush, event, request and recv must + be set to control the return condition. + + To attempt to send all requests in the queue, flush should + be true. Will return immediately if another thread is + already doing send_and_recv. + + To wait for an event to be received, event should be true. + + To wait for a response to a certain request (either an error + or a response), request should be set to that request's + serial number. + + To just read any pending data from the server, recv should be true. + + It is not guaranteed that the return condition has been + fulfilled when the function returns, so the caller has to loop + until it is finished. + """ + + # We go to sleep if there is already a thread doing what we + # want to do: + + # If flushing, we want to send + # If waiting for a response to a request, we want to send + # (to ensure that the request was sent - we alway recv + # when we get to the main loop, but sending is the important + # thing here) + # If waiting for an event, we want to recv + # If just trying to receive anything we can, we want to recv + + # FIXME: It would be good if we could also sleep when we're waiting on + # a response to a request that has already been sent. + + if (((flush or request is not None) and self.send_active) + or ((event or recv) and self.recv_active)): + + # Signal that we are waiting for something. These locks + # together with the *_waiting variables are used as + # semaphores. When an event or a request response arrives, + # it will zero the *_waiting and unlock the lock. The + # locks will also be unlocked when an active send_and_recv + # finishes to signal the other waiting threads that one of + # them has to take over the send_and_recv function. + + # All this makes these locks and variables a part of the + # send_and_recv control logic, and hence must be modified + # only when we have the send_recv_lock locked. + if event: + wait_lock = self.event_wait_lock + if not self.event_waiting: + self.event_waiting = 1 + wait_lock.acquire() + + elif request is not None: + wait_lock = self.request_wait_lock + if not self.request_waiting: + self.request_waiting = 1 + wait_lock.acquire() + + # Release send_recv, allowing a send_and_recive + # to terminate or other threads to queue up + self.send_recv_lock.release() + + # Return immediately if flushing, even if that + # might mean that not necessarily all requests + # have been sent. + if flush or recv: + return + + # Wait for something to happen, as the wait locks are + # unlocked either when what we wait for has arrived (not + # necessarily the exact object we're waiting for, though), + # or when an active send_and_recv exits. + + # Release it immediately afterwards as we're only using + # the lock for synchonization. Since we're not modifying + # event_waiting or request_waiting here we don't have + # to lock send_and_recv_lock. In fact, we can't do that + # or we trigger a dead-lock. + + wait_lock.acquire() + wait_lock.release() + + # Return to caller to let it check whether it has + # got the data it was waiting for + return + + + # There's no thread doing what we need to do. Find out exactly + # what to do + + # There must always be some thread receiving data, but it must not + # necessarily be us + + if not self.recv_active: + receiving = 1 + self.recv_active = 1 + else: + receiving = 0 + + flush_bytes = None + sending = 0 + + # Loop, receiving and sending data. + while 1: + + # We might want to start sending data + if sending or not self.send_active: + + # Turn all requests on request queue into binary form + # and append them to self.data_send + + self.request_queue_lock.acquire() + for req, wait in self.request_queue: + self.data_send = self.data_send + req._binary + if wait: + self.sent_requests.append(req) + + del self.request_queue[:] + self.request_queue_lock.release() + + # If there now is data to send, mark us as senders + + if self.data_send: + self.send_active = 1 + sending = 1 + else: + self.send_active = 0 + sending = 0 + + # We've done all setup, so release the lock and start waiting + # for the network to fire up + self.send_recv_lock.release() + + # There's no longer anything useful we can do here. + if not (sending or receiving): + break + + # If we're flushing, figure out how many bytes we + # have to send so that we're not caught in an interminable + # loop if other threads continuously append requests. + if flush and flush_bytes is None: + flush_bytes = self.data_sent_bytes + len(self.data_send) + + + try: + # We're only checking for the socket to be writable + # if we're the sending thread. We always check for it + # to become readable: either we are the receiving thread + # and should take care of the data, or the receiving thread + # might finish receiving after having read the data + + if sending: + writeset = [self.socket] + else: + writeset = [] + + # Timeout immediately if we're only checking for + # something to read or if we're flushing, otherwise block + + if recv or flush: + timeout = 0 + else: + timeout = None + + rs, ws, es = select.select([self.socket], writeset, [], timeout) + + # Ignore errors caused by a signal received while blocking. + # All other errors are re-raised. + except select.error as err: + if isinstance(err, OSError): + code = err.errno + else: + code = err[0] + if code != errno.EINTR: + raise + + # We must lock send_and_recv before we can loop to + # the start of the loop + + self.send_recv_lock.acquire() + continue + + + # Socket is ready for sending data, send as much as possible. + if ws: + try: + i = self.socket.send(self.data_send) + except socket.error as err: + self.close_internal('server: %s' % err) + raise self.socket_error + + self.data_send = self.data_send[i:] + self.data_sent_bytes = self.data_sent_bytes + i + + + # There is data to read + gotreq = 0 + if rs: + + # We're the receiving thread, parse the data + if receiving: + try: + count = self.recv_packet_len - len(self.data_recv) + count = max(self.recv_buffer_size, count) + bytes_recv = self.socket.recv(count) + except socket.error as err: + self.close_internal('server: %s' % err) + raise self.socket_error + + if not bytes_recv: + # Clear up, set a connection closed indicator and raise it + self.close_internal('server') + raise self.socket_error + + self.data_recv = bytes(self.data_recv) + bytes_recv + gotreq = self.parse_response(request) + + # Otherwise return, allowing the calling thread to figure + # out if it has got the data it needs + else: + # We must be a sending thread if we're here, so reset + # that indicator. + self.send_recv_lock.acquire() + self.send_active = 0 + self.send_recv_lock.release() + + # And return to the caller + return + + + # There are three different end of send-recv-loop conditions. + # However, we don't leave the loop immediately, instead we + # try to send and receive any data that might be left. We + # do this by giving a timeout of 0 to select to poll + # the socket. + + # When flushing: all requests have been sent + if flush and flush_bytes >= self.data_sent_bytes: + break + + # When waiting for an event: an event has been read + if event and self.event_queue: + break + + # When processing a certain request: got its reply + if request is not None and gotreq: + break + + # Always break if we just want to receive as much as possible + if recv: + break + + # Else there's may still data which must be sent, or + # we haven't got the data we waited for. Lock and loop + + self.send_recv_lock.acquire() + + + # We have accomplished the callers request. + # Record that there are now no active send_and_recv, + # and wake up all waiting thread + + self.send_recv_lock.acquire() + + if sending: + self.send_active = 0 + if receiving: + self.recv_active = 0 + + if self.event_waiting: + self.event_waiting = 0 + self.event_wait_lock.release() + + if self.request_waiting: + self.request_waiting = 0 + self.request_wait_lock.release() + + self.send_recv_lock.release() + + + def parse_response(self, request): + """Internal method. + + Parse data received from server. If REQUEST is not None + true is returned if the request with that serial number + was received, otherwise false is returned. + + If REQUEST is -1, we're parsing the server connection setup + response. + """ + + if request == -1: + return self.parse_connection_setup() + + # Parse ordinary server response + gotreq = False + while True: + if self.data_recv: + # Check the first byte to find out what kind of response it is + rtype = byte2int(self.data_recv) + + # Are we're waiting for additional data for the current packet? + if self.recv_packet_len: + if len(self.data_recv) < self.recv_packet_len: + return gotreq + + if rtype == 1: + gotreq = self.parse_request_response(request) or gotreq + continue + elif rtype & 0x7f == ge.GenericEventCode: + self.parse_event_response(rtype) + continue + else: + raise AssertionError(rtype) + + # Every response is at least 32 bytes long, so don't bother + # until we have received that much + if len(self.data_recv) < 32: + return gotreq + + # Error response + if rtype == 0: + gotreq = self.parse_error_response(request) or gotreq + + # Request response or generic event. + elif rtype == 1 or rtype & 0x7f == ge.GenericEventCode: + # Set reply length, and loop around to see if + # we have got the full response + rlen = int(struct.unpack('=L', self.data_recv[4:8])[0]) + self.recv_packet_len = 32 + rlen * 4 + + # Else non-generic event + else: + self.parse_event_response(rtype) + + + def parse_error_response(self, request): + # Code is second byte + code = indexbytes(self.data_recv, 1) + + # Fetch error class + estruct = self.error_classes.get(code, error.XError) + + e = estruct(self, self.data_recv[:32]) + self.data_recv = bytesview(self.data_recv, 32) + + # print 'recv Error:', e + + req = self.get_waiting_request(e.sequence_number) + + # Error for a request whose response we are waiting for, + # or which have an error handler. However, if the error + # handler indicates that it hasn't taken care of the + # error, pass it on to the default error handler + + if req and req._set_error(e): + + # If this was a ReplyRequest, unlock any threads waiting + # for a request to finish + + if isinstance(req, rq.ReplyRequest): + self.send_recv_lock.acquire() + + if self.request_waiting: + self.request_waiting = 0 + self.request_wait_lock.release() + + self.send_recv_lock.release() + + return request == e.sequence_number + + # Else call the error handler + else: + if self.error_handler: + rq.call_error_handler(self.error_handler, e, None) + else: + self.default_error_handler(e) + + return False + + + def default_error_handler(self, err): + sys.stderr.write('X protocol error:\n%s\n' % err) + + + def parse_request_response(self, request): + req = self.get_waiting_replyrequest() + + # Sequence number is always data[2:4] + # Do sanity check before trying to parse the data + sno = struct.unpack('=H', self.data_recv[2:4])[0] + if sno != req._serial: + raise RuntimeError("Expected reply for request %s, but got %s. Can't happen!" + % (req._serial, sno)) + + req._parse_response(self.data_recv[:self.recv_packet_len]) + # print 'recv Request:', req + + self.data_recv = bytesview(self.data_recv, self.recv_packet_len) + self.recv_packet_len = 0 + + + # Unlock any response waiting threads + + self.send_recv_lock.acquire() + + if self.request_waiting: + self.request_waiting = 0 + self.request_wait_lock.release() + + self.send_recv_lock.release() + + + return req.sequence_number == request + + + def parse_event_response(self, etype): + # Skip bit 8, that is set if this event came from an SendEvent + etype = etype & 0x7f + + if etype == ge.GenericEventCode: + length = self.recv_packet_len + else: + length = 32 + + estruct = self.event_classes.get(etype, event.AnyEvent) + if type(estruct) == dict: + subcode = self.data_recv[1] + + # Python2 compatibility + if type(subcode) == str: + subcode = ord(subcode) + + # this etype refers to a set of sub-events with individual subcodes + estruct = estruct[subcode] + + e = estruct(display = self, binarydata = self.data_recv[:length]) + + if etype == ge.GenericEventCode: + self.recv_packet_len = 0 + + self.data_recv = bytesview(self.data_recv, length) + + # Drop all requests having an error handler, + # but which obviously succeded. + + # Decrement it by one, so that we don't remove the request + # that generated these events, if there is such a one. + # Bug reported by Ilpo Nyyssönen + # Note: not all events have a sequence_number field! + # (e.g. KeymapNotify). + if hasattr(e, 'sequence_number'): + self.get_waiting_request((e.sequence_number - 1) % 65536) + + # print 'recv Event:', e + + # Insert the event into the queue + self.event_queue_write_lock.acquire() + self.event_queue.append(e) + self.event_queue_write_lock.release() + + # Unlock any event waiting threads + self.send_recv_lock.acquire() + + if self.event_waiting: + self.event_waiting = 0 + self.event_wait_lock.release() + + self.send_recv_lock.release() + + + def get_waiting_request(self, sno): + if not self.sent_requests: + return None + + # Normalize sequence numbers, even if they have wrapped. + # This ensures that + # sno <= last_serial + # and + # self.sent_requests[0]._serial <= last_serial + + if self.sent_requests[0]._serial > self.request_serial: + last_serial = self.request_serial + 65536 + if sno < self.request_serial: + sno = sno + 65536 + + else: + last_serial = self.request_serial + if sno > self.request_serial: + sno = sno - 65536 + + # No matching events at all + if sno < self.sent_requests[0]._serial: + return None + + # Find last req <= sno + req = None + reqpos = len(self.sent_requests) + adj = 0 + last = 0 + + for i in range(0, len(self.sent_requests)): + rno = self.sent_requests[i]._serial + adj + + # Did serial numbers just wrap around? + if rno < last: + adj = 65536 + rno = rno + adj + + last = rno + + if sno == rno: + req = self.sent_requests[i] + reqpos = i + 1 + break + elif sno < rno: + req = None + reqpos = i + break + + # Delete all request such as req <= sno + del self.sent_requests[:reqpos] + + return req + + def get_waiting_replyrequest(self): + for i in range(0, len(self.sent_requests)): + if hasattr(self.sent_requests[i], '_reply'): + req = self.sent_requests[i] + del self.sent_requests[:i + 1] + return req + + # Reply for an unknown request? No, that can't happen. + else: + raise RuntimeError("Request reply to unknown request. Can't happen!") + + def parse_connection_setup(self): + """Internal function used to parse connection setup response. + """ + + # Only the ConnectionSetupRequest has been sent so far + r = self.sent_requests[0] + + while True: + # print 'data_send:', repr(self.data_send) + # print 'data_recv:', repr(self.data_recv) + + if r._data: + alen = r._data['additional_length'] * 4 + + # The full response haven't arrived yet + if len(self.data_recv) < alen: + return False + + # Connection failed or further authentication is needed. + # Set reason to the reason string + if r._data['status'] != 1: + r._data['reason'] = self.data_recv[:r._data['reason_length']] + + # Else connection succeeded, parse the reply + else: + x, d = r._success_reply.parse_binary(self.data_recv[:alen], + self, rawdict = True) + r._data.update(x) + + del self.sent_requests[0] + + self.data_recv = self.data_recv[alen:] + + return True + + else: + # The base reply is 8 bytes long + if len(self.data_recv) < 8: + return False + + r._data, d = r._reply.parse_binary(self.data_recv[:8], + self, rawdict = True) + self.data_recv = self.data_recv[8:] + + # Loop around to see if we have got the additional data + # already + + +PixmapFormat = rq.Struct( rq.Card8('depth'), + rq.Card8('bits_per_pixel'), + rq.Card8('scanline_pad'), + rq.Pad(5) + ) + +VisualType = rq.Struct ( rq.Card32('visual_id'), + rq.Card8('visual_class'), + rq.Card8('bits_per_rgb_value'), + rq.Card16('colormap_entries'), + rq.Card32('red_mask'), + rq.Card32('green_mask'), + rq.Card32('blue_mask'), + rq.Pad(4) + ) + +Depth = rq.Struct( rq.Card8('depth'), + rq.Pad(1), + rq.LengthOf('visuals', 2), + rq.Pad(4), + rq.List('visuals', VisualType) + ) + +Screen = rq.Struct( rq.Window('root'), + rq.Colormap('default_colormap'), + rq.Card32('white_pixel'), + rq.Card32('black_pixel'), + rq.Card32('current_input_mask'), + rq.Card16('width_in_pixels'), + rq.Card16('height_in_pixels'), + rq.Card16('width_in_mms'), + rq.Card16('height_in_mms'), + rq.Card16('min_installed_maps'), + rq.Card16('max_installed_maps'), + rq.Card32('root_visual'), + rq.Card8('backing_store'), + rq.Card8('save_unders'), + rq.Card8('root_depth'), + rq.LengthOf('allowed_depths', 1), + rq.List('allowed_depths', Depth) + ) + + +class ConnectionSetupRequest(rq.GetAttrData): + _request = rq.Struct( rq.Set('byte_order', 1, (0x42, 0x6c)), + rq.Pad(1), + rq.Card16('protocol_major'), + rq.Card16('protocol_minor'), + rq.LengthOf('auth_prot_name', 2), + rq.LengthOf('auth_prot_data', 2), + rq.Pad(2), + rq.String8('auth_prot_name'), + rq.String8('auth_prot_data') ) + + _reply = rq.Struct ( rq.Card8('status'), + rq.Card8('reason_length'), + rq.Card16('protocol_major'), + rq.Card16('protocol_minor'), + rq.Card16('additional_length') ) + + _success_reply = rq.Struct( rq.Card32('release_number'), + rq.Card32('resource_id_base'), + rq.Card32('resource_id_mask'), + rq.Card32('motion_buffer_size'), + rq.LengthOf('vendor', 2), + rq.Card16('max_request_length'), + rq.LengthOf('roots', 1), + rq.LengthOf('pixmap_formats', 1), + rq.Card8('image_byte_order'), + rq.Card8('bitmap_format_bit_order'), + rq.Card8('bitmap_format_scanline_unit'), + rq.Card8('bitmap_format_scanline_pad'), + rq.Card8('min_keycode'), + rq.Card8('max_keycode'), + rq.Pad(4), + rq.String8('vendor'), + rq.List('pixmap_formats', PixmapFormat), + rq.List('roots', Screen), + ) + + + def __init__(self, display, *args, **keys): + self._binary = self._request.to_binary(*args, **keys) + self._data = None + + # Don't bother about locking, since no other threads have + # access to the display yet + + display.request_queue.append((self, True)) + + # However, we must lock send_and_recv, but we don't have + # to loop. + + display.send_recv_lock.acquire() + display.send_and_recv(request = -1) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/event.py b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/event.py new file mode 100644 index 0000000..4524452 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/event.py @@ -0,0 +1,434 @@ +# Xlib.protocol.event -- definitions of core events +# +# Copyright (C) 2000-2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +# Xlib modules +from .. import X + +# Xlib.protocol modules +from . import rq + + +class AnyEvent(rq.Event): + _code = None + _fields = rq.Struct( rq.Card8('type'), + rq.Card8('detail'), + rq.Card16('sequence_number'), + rq.FixedBinary('data', 28), + ) + +class KeyButtonPointer(rq.Event): + _code = None + _fields = rq.Struct( rq.Card8('type'), + rq.Card8('detail'), + rq.Card16('sequence_number'), + rq.Card32('time'), + rq.Window('root'), + rq.Window('window'), + rq.Window('child', (X.NONE, )), + rq.Int16('root_x'), + rq.Int16('root_y'), + rq.Int16('event_x'), + rq.Int16('event_y'), + rq.Card16('state'), + rq.Card8('same_screen'), + rq.Pad(1), + ) + +class KeyPress(KeyButtonPointer): + _code = X.KeyPress + +class KeyRelease(KeyButtonPointer): + _code = X.KeyRelease + +class ButtonPress(KeyButtonPointer): + _code = X.ButtonPress + +class ButtonRelease(KeyButtonPointer): + _code = X.ButtonRelease + +class MotionNotify(KeyButtonPointer): + _code = X.MotionNotify + +class EnterLeave(rq.Event): + _code = None + _fields = rq.Struct( rq.Card8('type'), + rq.Card8('detail'), + rq.Card16('sequence_number'), + rq.Card32('time'), + rq.Window('root'), + rq.Window('window'), + rq.Window('child', (X.NONE, )), + rq.Int16('root_x'), + rq.Int16('root_y'), + rq.Int16('event_x'), + rq.Int16('event_y'), + rq.Card16('state'), + rq.Card8('mode'), + rq.Card8('flags'), + ) + +class EnterNotify(EnterLeave): + _code = X.EnterNotify + +class LeaveNotify(EnterLeave): + _code = X.LeaveNotify + + +class Focus(rq.Event): + _code = None + _fields = rq.Struct( rq.Card8('type'), + rq.Card8('detail'), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card8('mode'), + rq.Pad(23), + ) + +class FocusIn(Focus): + _code = X.FocusIn + +class FocusOut(Focus): + _code = X.FocusOut + +class Expose(rq.Event): + _code = X.Expose + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card16('x'), + rq.Card16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('count'), + rq.Pad(14), + ) + +class GraphicsExpose(rq.Event): + _code = X.GraphicsExpose + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Drawable('drawable'), + rq.Card16('x'), + rq.Card16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('minor_event'), + rq.Card16('count'), + rq.Card8('major_event'), + rq.Pad(11), + ) + +class NoExpose(rq.Event): + _code = X.NoExpose + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Drawable('window'), + rq.Card16('minor_event'), + rq.Card8('major_event'), + rq.Pad(21), + ) + +class VisibilityNotify(rq.Event): + _code = X.VisibilityNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card8('state'), + rq.Pad(23), + ) + +class CreateNotify(rq.Event): + _code = X.CreateNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('parent'), + rq.Window('window'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Card8('override'), + rq.Pad(9), + ) + +class DestroyNotify(rq.Event): + _code = X.DestroyNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Pad(20), + ) + +class UnmapNotify(rq.Event): + _code = X.UnmapNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Card8('from_configure'), + rq.Pad(19), + ) + +class MapNotify(rq.Event): + _code = X.MapNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Card8('override'), + rq.Pad(19), + ) + +class MapRequest(rq.Event): + _code = X.MapRequest + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('parent'), + rq.Window('window'), + rq.Pad(20), + ) + +class ReparentNotify(rq.Event): + _code = X.ReparentNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Window('parent'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card8('override'), + rq.Pad(11), + ) + +class ConfigureNotify(rq.Event): + _code = X.ConfigureNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Window('above_sibling', (X.NONE, )), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Card8('override'), + rq.Pad(5), + ) + +class ConfigureRequest(rq.Event): + _code = X.ConfigureRequest + _fields = rq.Struct( rq.Card8('type'), + rq.Card8('stack_mode'), + rq.Card16('sequence_number'), + rq.Window('parent'), + rq.Window('window'), + rq.Window('sibling', (X.NONE, )), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Card16('value_mask'), + rq.Pad(4), + ) + +class GravityNotify(rq.Event): + _code = X.GravityNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Int16('x'), + rq.Int16('y'), + rq.Pad(16), + ) + +class ResizeRequest(rq.Event): + _code = X.ResizeRequest + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card16('width'), + rq.Card16('height'), + rq.Pad(20), + ) + +class Circulate(rq.Event): + _code = None + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('event'), + rq.Window('window'), + rq.Pad(4), + rq.Card8('place'), + rq.Pad(15), + ) + +class CirculateNotify(Circulate): + _code = X.CirculateNotify + +class CirculateRequest(Circulate): + _code = X.CirculateRequest + +class PropertyNotify(rq.Event): + _code = X.PropertyNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card32('atom'), + rq.Card32('time'), + rq.Card8('state'), + rq.Pad(15), + ) + +class SelectionClear(rq.Event): + _code = X.SelectionClear + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Card32('time'), + rq.Window('window'), + rq.Card32('atom'), + rq.Pad(16), + ) + +class SelectionRequest(rq.Event): + _code = X.SelectionRequest + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Card32('time'), + rq.Window('owner'), + rq.Window('requestor'), + rq.Card32('selection'), + rq.Card32('target'), + rq.Card32('property'), + rq.Pad(4), + ) + +class SelectionNotify(rq.Event): + _code = X.SelectionNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Card32('time'), + rq.Window('requestor'), + rq.Card32('selection'), + rq.Card32('target'), + rq.Card32('property'), + rq.Pad(8), + ) + +class ColormapNotify(rq.Event): + _code = X.ColormapNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Colormap('colormap', (X.NONE, )), + rq.Card8('new'), + rq.Card8('state'), + rq.Pad(18), + ) + +class MappingNotify(rq.Event): + _code = X.MappingNotify + _fields = rq.Struct( rq.Card8('type'), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.Card8('request'), + rq.Card8('first_keycode'), + rq.Card8('count'), + rq.Pad(25), + ) + +class ClientMessage(rq.Event): + _code = X.ClientMessage + _fields = rq.Struct( rq.Card8('type'), + rq.Format('data', 1), + rq.Card16('sequence_number'), + rq.Window('window'), + rq.Card32('client_type'), + rq.FixedPropertyData('data', 20), + ) + +class KeymapNotify(rq.Event): + _code = X.KeymapNotify + _fields = rq.Struct( rq.Card8('type'), + rq.FixedList('data', 31, rq.Card8Obj, pad = 0) + ) + + +event_class = { + X.KeyPress: KeyPress, + X.KeyRelease: KeyRelease, + X.ButtonPress: ButtonPress, + X.ButtonRelease: ButtonRelease, + X.MotionNotify: MotionNotify, + X.EnterNotify: EnterNotify, + X.LeaveNotify: LeaveNotify, + X.FocusIn: FocusIn, + X.FocusOut: FocusOut, + X.KeymapNotify: KeymapNotify, + X.Expose: Expose, + X.GraphicsExpose: GraphicsExpose, + X.NoExpose: NoExpose, + X.VisibilityNotify: VisibilityNotify, + X.CreateNotify: CreateNotify, + X.DestroyNotify: DestroyNotify, + X.UnmapNotify: UnmapNotify, + X.MapNotify: MapNotify, + X.MapRequest: MapRequest, + X.ReparentNotify: ReparentNotify, + X.ConfigureNotify: ConfigureNotify, + X.ConfigureRequest: ConfigureRequest, + X.GravityNotify: GravityNotify, + X.ResizeRequest: ResizeRequest, + X.CirculateNotify: CirculateNotify, + X.CirculateRequest: CirculateRequest, + X.PropertyNotify: PropertyNotify, + X.SelectionClear: SelectionClear, + X.SelectionRequest: SelectionRequest, + X.SelectionNotify: SelectionNotify, + X.ColormapNotify: ColormapNotify, + X.ClientMessage: ClientMessage, + X.MappingNotify: MappingNotify, + } diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/request.py b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/request.py new file mode 100644 index 0000000..608a768 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/request.py @@ -0,0 +1,1900 @@ +# Xlib.protocol.request -- definitions of core requests +# +# Copyright (C) 2000-2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +# Xlib modules +from .. import X + +# Xlib.protocol modules +from . import rq +from . import structs + + +class CreateWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(1), + rq.Card8('depth'), + rq.RequestLength(), + rq.Window('wid'), + rq.Window('parent'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Set('window_class', 2, (X.CopyFromParent, X.InputOutput, X.InputOnly)), + rq.Card32('visual'), + structs.WindowValues('attrs'), + ) + +class ChangeWindowAttributes(rq.Request): + _request = rq.Struct( + rq.Opcode(2), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + structs.WindowValues('attrs'), + ) + +class GetWindowAttributes(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(3), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('backing_store'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('visual'), + rq.Card16('win_class'), + rq.Card8('bit_gravity'), + rq.Card8('win_gravity'), + rq.Card32('backing_bit_planes'), + rq.Card32('backing_pixel'), + rq.Card8('save_under'), + rq.Card8('map_is_installed'), + rq.Card8('map_state'), + rq.Card8('override_redirect'), + rq.Colormap('colormap', (X.NONE, )), + rq.Card32('all_event_masks'), + rq.Card32('your_event_mask'), + rq.Card16('do_not_propagate_mask'), + rq.Pad(2), + ) + +class DestroyWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(4), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class DestroySubWindows(rq.Request): + _request = rq.Struct( + rq.Opcode(5), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class ChangeSaveSet(rq.Request): + _request = rq.Struct( + rq.Opcode(6), + rq.Set('mode', 1, (X.SetModeInsert, X.SetModeDelete)), + rq.RequestLength(), + rq.Window('window'), + ) + +class ReparentWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(7), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.Window('parent'), + rq.Int16('x'), + rq.Int16('y'), + ) + +class MapWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(8), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class MapSubwindows(rq.Request): + _request = rq.Struct( + rq.Opcode(9), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class UnmapWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(10), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class UnmapSubwindows(rq.Request): + _request = rq.Struct( + rq.Opcode(11), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + +class ConfigureWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(12), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.ValueList( 'attrs', 2, 2, + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Int16('border_width'), + rq.Window('sibling'), + rq.Set('stack_mode', 1, + (X.Above, X.Below, X.TopIf, + X.BottomIf, X.Opposite)) + ) + ) + +class CirculateWindow(rq.Request): + _request = rq.Struct( + rq.Opcode(13), + rq.Set('direction', 1, (X.RaiseLowest, X.LowerHighest)), + rq.RequestLength(), + rq.Window('window'), + ) + +class GetGeometry(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(14), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable') + ) + + _reply = rq.Struct ( + rq.ReplyCode(), + rq.Card8('depth'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('root'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card16('border_width'), + rq.Pad(10) + ) + +class QueryTree(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(15), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('root'), + rq.Window('parent', (X.NONE, )), + rq.LengthOf('children', 2), + rq.Pad(14), + rq.List('children', rq.WindowObj), + ) + +class InternAtom(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(16), + rq.Bool('only_if_exists'), + rq.RequestLength(), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('atom'), + rq.Pad(20), + ) + + +class GetAtomName(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(17), + rq.Pad(1), + rq.RequestLength(), + rq.Card32('atom') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('name', 2), + rq.Pad(22), + rq.String8('name'), + ) + +class ChangeProperty(rq.Request): + _request = rq.Struct( + rq.Opcode(18), + rq.Set('mode', 1, (X.PropModeReplace, X.PropModePrepend, X.PropModeAppend)), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('property'), + rq.Card32('type'), + rq.Format('data', 1), + rq.Pad(3), + rq.LengthOf('data', 4), + rq.PropertyData('data'), + ) + +class DeleteProperty(rq.Request): + _request = rq.Struct( + rq.Opcode(19), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('property'), + ) + +class GetProperty(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(20), + rq.Bool('delete'), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('property'), + rq.Card32('type'), + rq.Card32('long_offset'), + rq.Card32('long_length'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Format('value', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('property_type'), + rq.Card32('bytes_after'), + rq.LengthOf('value', 4), + rq.Pad(12), + rq.PropertyData('value'), + ) + +class ListProperties(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(21), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('atoms', 2), + rq.Pad(22), + rq.List('atoms', rq.Card32Obj), + ) + +class SetSelectionOwner(rq.Request): + _request = rq.Struct( + rq.Opcode(22), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('selection'), + rq.Card32('time'), + ) + +class GetSelectionOwner(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(23), + rq.Pad(1), + rq.RequestLength(), + rq.Card32('selection') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('owner', (X.NONE, )), + rq.Pad(20), + ) + +class ConvertSelection(rq.Request): + _request = rq.Struct( + rq.Opcode(24), + rq.Pad(1), + rq.RequestLength(), + rq.Window('requestor'), + rq.Card32('selection'), + rq.Card32('target'), + rq.Card32('property'), + rq.Card32('time'), + ) + +class SendEvent(rq.Request): + _request = rq.Struct( + rq.Opcode(25), + rq.Bool('propagate'), + rq.RequestLength(), + rq.Window('destination'), + rq.Card32('event_mask'), + rq.EventField('event'), + ) + +class GrabPointer(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(26), + rq.Bool('owner_events'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card16('event_mask'), + rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Window('confine_to', (X.NONE, )), + rq.Cursor('cursor', (X.NONE, )), + rq.Card32('time'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + ) + +class UngrabPointer(rq.Request): + _request = rq.Struct( + rq.Opcode(27), + rq.Pad(1), + rq.RequestLength(), + rq.Card32('time') + ) + +class GrabButton(rq.Request): + _request = rq.Struct( + rq.Opcode(28), + rq.Bool('owner_events'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card16('event_mask'), + rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Window('confine_to', (X.NONE, )), + rq.Cursor('cursor', (X.NONE, )), + rq.Card8('button'), + rq.Pad(1), + rq.Card16('modifiers'), + ) + +class UngrabButton(rq.Request): + _request = rq.Struct( + rq.Opcode(29), + rq.Card8('button'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card16('modifiers'), + rq.Pad(2), + ) + +class ChangeActivePointerGrab(rq.Request): + _request = rq.Struct( + rq.Opcode(30), + rq.Pad(1), + rq.RequestLength(), + rq.Cursor('cursor'), + rq.Card32('time'), + rq.Card16('event_mask'), + rq.Pad(2), + ) + +class GrabKeyboard(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(31), + rq.Bool('owner_events'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card32('time'), + rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + ) + +class UngrabKeyboard(rq.Request): + _request = rq.Struct( + rq.Opcode(32), + rq.Pad(1), + rq.RequestLength(), + rq.Card32('time') + ) + +class GrabKey(rq.Request): + _request = rq.Struct( + rq.Opcode(33), + rq.Bool('owner_events'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card16('modifiers'), + rq.Card8('key'), + rq.Set('pointer_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Set('keyboard_mode', 1, (X.GrabModeSync, X.GrabModeAsync)), + rq.Pad(3), + ) + +class UngrabKey(rq.Request): + _request = rq.Struct( + rq.Opcode(34), + rq.Card8('key'), + rq.RequestLength(), + rq.Window('grab_window'), + rq.Card16('modifiers'), + rq.Pad(2), + ) + +class AllowEvents(rq.Request): + _request = rq.Struct( + rq.Opcode(35), + rq.Set('mode', 1, (X.AsyncPointer, + X.SyncPointer, + X.ReplayPointer, + X.AsyncKeyboard, + X.SyncKeyboard, + X.ReplayKeyboard, + X.AsyncBoth, + X.SyncBoth)), + rq.RequestLength(), + rq.Card32('time'), + ) + +class GrabServer(rq.Request): + _request = rq.Struct( + rq.Opcode(36), + rq.Pad(1), + rq.RequestLength(), + ) + +class UngrabServer(rq.Request): + _request = rq.Struct( + rq.Opcode(37), + rq.Pad(1), + rq.RequestLength(), + ) + +class QueryPointer(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(38), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('same_screen'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('root'), + rq.Window('child', (X.NONE, )), + rq.Int16('root_x'), + rq.Int16('root_y'), + rq.Int16('win_x'), + rq.Int16('win_y'), + rq.Card16('mask'), + rq.Pad(6), + ) + +class GetMotionEvents(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(39), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.Card32('start'), + rq.Card32('stop'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('events', 4), + rq.Pad(20), + rq.List('events', structs.TimeCoord), + ) + +class TranslateCoords(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(40), + rq.Pad(1), + rq.RequestLength(), + rq.Window('src_wid'), + rq.Window('dst_wid'), + rq.Int16('src_x'), + rq.Int16('src_y'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('same_screen'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('child', (X.NONE, )), + rq.Int16('x'), + rq.Int16('y'), + rq.Pad(16), + ) + +class WarpPointer(rq.Request): + _request = rq.Struct( + rq.Opcode(41), + rq.Pad(1), + rq.RequestLength(), + rq.Window('src_window'), + rq.Window('dst_window'), + rq.Int16('src_x'), + rq.Int16('src_y'), + rq.Card16('src_width'), + rq.Card16('src_height'), + rq.Int16('dst_x'), + rq.Int16('dst_y'), + ) + +class SetInputFocus(rq.Request): + _request = rq.Struct( + rq.Opcode(42), + rq.Set('revert_to', 1, (X.RevertToNone, X.RevertToPointerRoot, + X.RevertToParent)), + rq.RequestLength(), + rq.Window('focus'), + rq.Card32('time'), + ) + +class GetInputFocus(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(43), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('revert_to'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Window('focus', (X.NONE, X.PointerRoot)), + rq.Pad(20), + ) + +class QueryKeymap(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(44), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.FixedList('map', 32, rq.Card8Obj), + ) + + +class OpenFont(rq.Request): + _request = rq.Struct( + rq.Opcode(45), + rq.Pad(1), + rq.RequestLength(), + rq.Font('fid'), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + +class CloseFont(rq.Request): + _request = rq.Struct( + rq.Opcode(46), + rq.Pad(1), + rq.RequestLength(), + rq.Font('font') + ) + +class QueryFont(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(47), + rq.Pad(1), + rq.RequestLength(), + rq.Fontable('font') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Object('min_bounds', structs.CharInfo), + rq.Pad(4), + rq.Object('max_bounds', structs.CharInfo), + rq.Pad(4), + rq.Card16('min_char_or_byte2'), + rq.Card16('max_char_or_byte2'), + rq.Card16('default_char'), + rq.LengthOf('properties', 2), + rq.Card8('draw_direction'), + rq.Card8('min_byte1'), + rq.Card8('max_byte1'), + rq.Card8('all_chars_exist'), + rq.Int16('font_ascent'), + rq.Int16('font_descent'), + rq.LengthOf('char_infos', 4), + rq.List('properties', structs.FontProp), + rq.List('char_infos', structs.CharInfo), + ) + +class QueryTextExtents(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(48), + rq.OddLength('string'), + rq.RequestLength(), + rq.Fontable('font'), + rq.String16('string'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('draw_direction'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Int16('font_ascent'), + rq.Int16('font_descent'), + rq.Int16('overall_ascent'), + rq.Int16('overall_descent'), + rq.Int32('overall_width'), + rq.Int32('overall_left'), + rq.Int32('overall_right'), + rq.Pad(4), + ) + +class ListFonts(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(49), + rq.Pad(1), + rq.RequestLength(), + rq.Card16('max_names'), + rq.LengthOf('pattern', 2), + rq.String8('pattern'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('fonts', 2), + rq.Pad(22), + rq.List('fonts', rq.Str), + ) + + +class ListFontsWithInfo(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(50), + rq.Pad(1), + rq.RequestLength(), + rq.Card16('max_names'), + rq.LengthOf('pattern', 2), + rq.String8('pattern'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.LengthOf('name', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Object('min_bounds', structs.CharInfo), + rq.Pad(4), + rq.Object('max_bounds', structs.CharInfo), + rq.Pad(4), + rq.Card16('min_char_or_byte2'), + rq.Card16('max_char_or_byte2'), + rq.Card16('default_char'), + rq.LengthOf('properties', 2), + rq.Card8('draw_direction'), + rq.Card8('min_byte1'), + rq.Card8('max_byte1'), + rq.Card8('all_chars_exist'), + rq.Int16('font_ascent'), + rq.Int16('font_descent'), + rq.Card32('replies_hint'), + rq.List('properties', structs.FontProp), + rq.String8('name'), + ) + + + # Somebody must have smoked some really wicked weed when they + # defined the ListFontsWithInfo request: + # The server sends a reply for _each_ matching font... + # It then sends a special reply (name length == 0) to indicate + # that there are no more fonts in the reply. + + # This means that we have to do some special parsing to see if + # we have got the end-of-reply reply. If we haven't, we + # have to reinsert the request in the front of the + # display.sent_request queue to catch the next response. + + # Bastards. + + def __init__(self, *args, **keys): + self._fonts = [] + rq.ReplyRequest.__init__(self, *args, **keys) + + def _parse_response(self, data): + + if ord(data[1]) == 0: + self._response_lock.acquire() + self._data = self._fonts + del self._fonts + self._response_lock.release() + return + + r, d = self._reply.parse_binary(data) + self._fonts.append(r) + + self._display.sent_requests.insert(0, self) + + + # Override the default __getattr__, since it isn't usable for + # the list reply. Instead provide a __getitem__ and a __len__. + + def __getattr__(self, attr): + raise AttributeError(attr) + + def __getitem__(self, item): + return self._data[item] + + def __len__(self): + return len(self._data) + + +class SetFontPath(rq.Request): + _request = rq.Struct( + rq.Opcode(51), + rq.Pad(1), + rq.RequestLength(), + rq.LengthOf('path', 2), + rq.Pad(2), + rq.List('path', rq.Str), + ) + +class GetFontPath(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(52), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('paths', 2), + rq.Pad(22), + rq.List('paths', rq.Str), + ) + +class CreatePixmap(rq.Request): + _request = rq.Struct( + rq.Opcode(53), + rq.Card8('depth'), + rq.RequestLength(), + rq.Pixmap('pid'), + rq.Drawable('drawable'), + rq.Card16('width'), + rq.Card16('height'), + ) + +class FreePixmap(rq.Request): + _request = rq.Struct( + rq.Opcode(54), + rq.Pad(1), + rq.RequestLength(), + rq.Pixmap('pixmap') + ) + +class CreateGC(rq.Request): + _request = rq.Struct( + rq.Opcode(55), + rq.Pad(1), + rq.RequestLength(), + rq.GC('cid'), + rq.Drawable('drawable'), + structs.GCValues('attrs'), + ) + +class ChangeGC(rq.Request): + _request = rq.Struct( + rq.Opcode(56), + rq.Pad(1), + rq.RequestLength(), + rq.GC('gc'), + structs.GCValues('attrs'), + ) + +class CopyGC(rq.Request): + _request = rq.Struct( + rq.Opcode(57), + rq.Pad(1), + rq.RequestLength(), + rq.GC('src_gc'), + rq.GC('dst_gc'), + rq.Card32('mask'), + ) + +class SetDashes(rq.Request): + _request = rq.Struct( + rq.Opcode(58), + rq.Pad(1), + rq.RequestLength(), + rq.GC('gc'), + rq.Card16('dash_offset'), + rq.LengthOf('dashes', 2), + rq.List('dashes', rq.Card8Obj), + ) + +class SetClipRectangles(rq.Request): + _request = rq.Struct( + rq.Opcode(59), + rq.Set('ordering', 1, (X.Unsorted, X.YSorted, X.YXSorted, X.YXBanded)), + rq.RequestLength(), + rq.GC('gc'), + rq.Int16('x_origin'), + rq.Int16('y_origin'), + rq.List('rectangles', structs.Rectangle), + ) + +class FreeGC(rq.Request): + _request = rq.Struct( + rq.Opcode(60), + rq.Pad(1), + rq.RequestLength(), + rq.GC('gc') + ) + +class ClearArea(rq.Request): + _request = rq.Struct( + rq.Opcode(61), + rq.Bool('exposures'), + rq.RequestLength(), + rq.Window('window'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + ) + +class CopyArea(rq.Request): + _request = rq.Struct( + rq.Opcode(62), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('src_drawable'), + rq.Drawable('dst_drawable'), + rq.GC('gc'), + rq.Int16('src_x'), + rq.Int16('src_y'), + rq.Int16('dst_x'), + rq.Int16('dst_y'), + rq.Card16('width'), + rq.Card16('height'), + ) + +class CopyPlane(rq.Request): + _request = rq.Struct( + rq.Opcode(63), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('src_drawable'), + rq.Drawable('dst_drawable'), + rq.GC('gc'), + rq.Int16('src_x'), + rq.Int16('src_y'), + rq.Int16('dst_x'), + rq.Int16('dst_y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card32('bit_plane'), + ) + +class PolyPoint(rq.Request): + _request = rq.Struct( + rq.Opcode(64), + rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('points', structs.Point), + ) + +class PolyLine(rq.Request): + _request = rq.Struct( + rq.Opcode(65), + rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('points', structs.Point), + ) + + +class PolySegment(rq.Request): + _request = rq.Struct( + rq.Opcode(66), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('segments', structs.Segment), + ) + + +class PolyRectangle(rq.Request): + _request = rq.Struct( + rq.Opcode(67), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('rectangles', structs.Rectangle), + ) + +class PolyArc(rq.Request): + _request = rq.Struct( + rq.Opcode(68), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('arcs', structs.Arc), + ) + +class FillPoly(rq.Request): + _request = rq.Struct( + rq.Opcode(69), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Set('shape', 1, (X.Complex, X.Nonconvex, X.Convex)), + rq.Set('coord_mode', 1, (X.CoordModeOrigin, X.CoordModePrevious)), + rq.Pad(2), + rq.List('points', structs.Point), + ) + +class PolyFillRectangle(rq.Request): + _request = rq.Struct( + rq.Opcode(70), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('rectangles', structs.Rectangle), + ) + +class PolyFillArc(rq.Request): + _request = rq.Struct( + rq.Opcode(71), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.List('arcs', structs.Arc), + ) + +class PutImage(rq.Request): + _request = rq.Struct( + rq.Opcode(72), + rq.Set('format', 1, (X.XYBitmap, X.XYPixmap, X.ZPixmap)), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Card16('width'), + rq.Card16('height'), + rq.Int16('dst_x'), + rq.Int16('dst_y'), + rq.Card8('left_pad'), + rq.Card8('depth'), + rq.Pad(2), + rq.Binary('data'), + ) + +class GetImage(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(73), + rq.Set('format', 1, (X.XYPixmap, X.ZPixmap)), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Card32('plane_mask'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('depth'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('visual'), + rq.Pad(20), + rq.Binary('data'), + ) + +class PolyText8(rq.Request): + _request = rq.Struct( + rq.Opcode(74), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Int16('x'), + rq.Int16('y'), + rq.TextElements8('items'), + ) + +class PolyText16(rq.Request): + _request = rq.Struct( + rq.Opcode(75), + rq.Pad(1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Int16('x'), + rq.Int16('y'), + rq.TextElements16('items'), + ) + +class ImageText8(rq.Request): + _request = rq.Struct( + rq.Opcode(76), + rq.LengthOf('string', 1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Int16('x'), + rq.Int16('y'), + rq.String8('string'), + ) + +class ImageText16(rq.Request): + _request = rq.Struct( + rq.Opcode(77), + rq.LengthOf('string', 1), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.GC('gc'), + rq.Int16('x'), + rq.Int16('y'), + rq.String16('string'), + ) + +class CreateColormap(rq.Request): + _request = rq.Struct( + rq.Opcode(78), + rq.Set('alloc', 1, (X.AllocNone, X.AllocAll)), + rq.RequestLength(), + rq.Colormap('mid'), + rq.Window('window'), + rq.Card32('visual'), + ) + +class FreeColormap(rq.Request): + _request = rq.Struct( + rq.Opcode(79), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap') + ) + +class CopyColormapAndFree(rq.Request): + _request = rq.Struct( + rq.Opcode(80), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('mid'), + rq.Colormap('src_cmap'), + ) + +class InstallColormap(rq.Request): + _request = rq.Struct( + rq.Opcode(81), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap') + ) + +class UninstallColormap(rq.Request): + _request = rq.Struct( + rq.Opcode(82), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap') + ) + +class ListInstalledColormaps(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(83), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('cmaps', 2), + rq.Pad(22), + rq.List('cmaps', rq.ColormapObj), + ) + +class AllocColor(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(84), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.Card16('red'), + rq.Card16('green'), + rq.Card16('blue'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('red'), + rq.Card16('green'), + rq.Card16('blue'), + rq.Pad(2), + rq.Card32('pixel'), + rq.Pad(12), + ) + +class AllocNamedColor(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(85), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('pixel'), + rq.Card16('exact_red'), + rq.Card16('exact_green'), + rq.Card16('exact_blue'), + rq.Card16('screen_red'), + rq.Card16('screen_green'), + rq.Card16('screen_blue'), + rq.Pad(8), + ) + +class AllocColorCells(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(86), + rq.Bool('contiguous'), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.Card16('colors'), + rq.Card16('planes'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('pixels', 2), + rq.LengthOf('masks', 2), + rq.Pad(20), + rq.List('pixels', rq.Card32Obj), + rq.List('masks', rq.Card32Obj), + ) + +class AllocColorPlanes(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(87), + rq.Bool('contiguous'), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.Card16('colors'), + rq.Card16('red'), + rq.Card16('green'), + rq.Card16('blue'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('pixels', 2), + rq.Pad(2), + rq.Card32('red_mask'), + rq.Card32('green_mask'), + rq.Card32('blue_mask'), + rq.Pad(8), + rq.List('pixels', rq.Card32Obj), + ) + +class FreeColors(rq.Request): + _request = rq.Struct( + rq.Opcode(88), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.Card32('plane_mask'), + rq.List('pixels', rq.Card32Obj), + ) + +class StoreColors(rq.Request): + _request = rq.Struct( + rq.Opcode(89), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.List('items', structs.ColorItem), + ) + +class StoreNamedColor(rq.Request): + _request = rq.Struct( + rq.Opcode(90), + rq.Card8('flags'), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.Card32('pixel'), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + +class QueryColors(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(91), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.List('pixels', rq.Card32Obj), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('colors', 2), + rq.Pad(22), + rq.List('colors', structs.RGB), + ) + +class LookupColor(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(92), + rq.Pad(1), + rq.RequestLength(), + rq.Colormap('cmap'), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('exact_red'), + rq.Card16('exact_green'), + rq.Card16('exact_blue'), + rq.Card16('screen_red'), + rq.Card16('screen_green'), + rq.Card16('screen_blue'), + rq.Pad(12), + ) + + +class CreateCursor(rq.Request): + _request = rq.Struct( + rq.Opcode(93), + rq.Pad(1), + rq.RequestLength(), + rq.Cursor('cid'), + rq.Pixmap('source'), + rq.Pixmap('mask'), + rq.Card16('fore_red'), + rq.Card16('fore_green'), + rq.Card16('fore_blue'), + rq.Card16('back_red'), + rq.Card16('back_green'), + rq.Card16('back_blue'), + rq.Card16('x'), + rq.Card16('y'), + ) + +class CreateGlyphCursor(rq.Request): + _request = rq.Struct( + rq.Opcode(94), + rq.Pad(1), + rq.RequestLength(), + rq.Cursor('cid'), + rq.Font('source'), + rq.Font('mask'), + rq.Card16('source_char'), + rq.Card16('mask_char'), + rq.Card16('fore_red'), + rq.Card16('fore_green'), + rq.Card16('fore_blue'), + rq.Card16('back_red'), + rq.Card16('back_green'), + rq.Card16('back_blue'), + ) + +class FreeCursor(rq.Request): + _request = rq.Struct( + rq.Opcode(95), + rq.Pad(1), + rq.RequestLength(), + rq.Cursor('cursor') + ) + +class RecolorCursor(rq.Request): + _request = rq.Struct( + rq.Opcode(96), + rq.Pad(1), + rq.RequestLength(), + rq.Cursor('cursor'), + rq.Card16('fore_red'), + rq.Card16('fore_green'), + rq.Card16('fore_blue'), + rq.Card16('back_red'), + rq.Card16('back_green'), + rq.Card16('back_blue'), + ) + +class QueryBestSize(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(97), + rq.Set('item_class', 1, (X.CursorShape, X.TileShape, X.StippleShape)), + rq.RequestLength(), + rq.Drawable('drawable'), + rq.Card16('width'), + rq.Card16('height'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('width'), + rq.Card16('height'), + rq.Pad(20), + ) + +class QueryExtension(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(98), + rq.Pad(1), + rq.RequestLength(), + rq.LengthOf('name', 2), + rq.Pad(2), + rq.String8('name'), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card8('present'), + rq.Card8('major_opcode'), + rq.Card8('first_event'), + rq.Card8('first_error'), + rq.Pad(20), + ) + +class ListExtensions(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(99), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.LengthOf('names', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + rq.List('names', rq.Str), + ) + +class ChangeKeyboardMapping(rq.Request): + _request = rq.Struct( + rq.Opcode(100), + rq.LengthOf('keysyms', 1), + rq.RequestLength(), + rq.Card8('first_keycode'), + rq.Format('keysyms', 1), + rq.Pad(2), + rq.KeyboardMapping('keysyms'), + ) + +class GetKeyboardMapping(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(101), + rq.Pad(1), + rq.RequestLength(), + rq.Card8('first_keycode'), + rq.Card8('count'), + rq.Pad(2), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Format('keysyms', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + rq.KeyboardMapping('keysyms'), + ) + + +class ChangeKeyboardControl(rq.Request): + _request = rq.Struct( + rq.Opcode(102), + rq.Pad(1), + rq.RequestLength(), + rq.ValueList( 'attrs', 4, 0, + rq.Int8('key_click_percent'), + rq.Int8('bell_percent'), + rq.Int16('bell_pitch'), + rq.Int16('bell_duration'), + rq.Card8('led'), + rq.Set('led_mode', 1, (X.LedModeOff, X.LedModeOn)), + rq.Card8('key'), + rq.Set('auto_repeat_mode', 1, (X.AutoRepeatModeOff, + X.AutoRepeatModeOn, + X.AutoRepeatModeDefault)) + ) + ) + +class GetKeyboardControl(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(103), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('global_auto_repeat'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card32('led_mask'), + rq.Card8('key_click_percent'), + rq.Card8('bell_percent'), + rq.Card16('bell_pitch'), + rq.Card16('bell_duration'), + rq.Pad(2), + rq.FixedList('auto_repeats', 32, rq.Card8Obj), + ) + +class Bell(rq.Request): + _request = rq.Struct( + rq.Opcode(104), + rq.Int8('percent'), + rq.RequestLength(), + ) + +class ChangePointerControl(rq.Request): + _request = rq.Struct( + rq.Opcode(105), + rq.Pad(1), + rq.RequestLength(), + rq.Int16('accel_num'), + rq.Int16('accel_denum'), + rq.Int16('threshold'), + rq.Bool('do_accel'), + rq.Bool('do_thresh'), + ) + +class GetPointerControl(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(106), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('accel_num'), + rq.Card16('accel_denom'), + rq.Card16('threshold'), + rq.Pad(18), + ) + +class SetScreenSaver(rq.Request): + _request = rq.Struct( + rq.Opcode(107), + rq.Pad(1), + rq.RequestLength(), + rq.Int16('timeout'), + rq.Int16('interval'), + rq.Set('prefer_blank', 1, (X.DontPreferBlanking, + X.PreferBlanking, + X.DefaultBlanking)), + rq.Set('allow_exposures', 1, (X.DontAllowExposures, + X.AllowExposures, + X.DefaultExposures)), + rq.Pad(2), + ) + +class GetScreenSaver(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(108), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Pad(1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Card16('timeout'), + rq.Card16('interval'), + rq.Card8('prefer_blanking'), + rq.Card8('allow_exposures'), + rq.Pad(18), + ) + +class ChangeHosts(rq.Request): + _request = rq.Struct( + rq.Opcode(109), + rq.Set('mode', 1, (X.HostInsert, X.HostDelete)), + rq.RequestLength(), + rq.Set('host_family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos, + X.FamilyServerInterpreted, X.FamilyInternetV6)), + rq.Pad(1), + rq.LengthOf('host', 2), + rq.List('host', rq.Card8Obj) + ) + +class ListHosts(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(110), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('mode'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.LengthOf('hosts', 2), + rq.Pad(22), + rq.List('hosts', structs.Host), + ) + +class SetAccessControl(rq.Request): + _request = rq.Struct( + rq.Opcode(111), + rq.Set('mode', 1, (X.DisableAccess, X.EnableAccess)), + rq.RequestLength(), + ) + +class SetCloseDownMode(rq.Request): + _request = rq.Struct( + rq.Opcode(112), + rq.Set('mode', 1, (X.DestroyAll, X.RetainPermanent, X.RetainTemporary)), + rq.RequestLength(), + ) + +class KillClient(rq.Request): + _request = rq.Struct( + rq.Opcode(113), + rq.Pad(1), + rq.RequestLength(), + rq.Resource('resource') + ) + +class RotateProperties(rq.Request): + _request = rq.Struct( + rq.Opcode(114), + rq.Pad(1), + rq.RequestLength(), + rq.Window('window'), + rq.LengthOf('properties', 2), + rq.Int16('delta'), + rq.List('properties', rq.Card32Obj), + ) + +class ForceScreenSaver(rq.Request): + _request = rq.Struct( + rq.Opcode(115), + rq.Set('mode', 1, (X.ScreenSaverReset, X.ScreenSaverActive)), + rq.RequestLength(), + ) + +class SetPointerMapping(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(116), + rq.LengthOf('map', 1), + rq.RequestLength(), + rq.List('map', rq.Card8Obj), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + ) + +class GetPointerMapping(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(117), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.LengthOf('map', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + rq.List('map', rq.Card8Obj), + ) + +class SetModifierMapping(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(118), + rq.Format('keycodes', 1), + rq.RequestLength(), + rq.ModifierMapping('keycodes') + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Card8('status'), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + ) + +class GetModifierMapping(rq.ReplyRequest): + _request = rq.Struct( + rq.Opcode(119), + rq.Pad(1), + rq.RequestLength(), + ) + + _reply = rq.Struct( + rq.ReplyCode(), + rq.Format('keycodes', 1), + rq.Card16('sequence_number'), + rq.ReplyLength(), + rq.Pad(24), + rq.ModifierMapping('keycodes') + ) + +class NoOperation(rq.Request): + _request = rq.Struct( + rq.Opcode(127), + rq.Pad(1), + rq.RequestLength(), + ) + + +major_codes = { + 1: CreateWindow, + 2: ChangeWindowAttributes, + 3: GetWindowAttributes, + 4: DestroyWindow, + 5: DestroySubWindows, + 6: ChangeSaveSet, + 7: ReparentWindow, + 8: MapWindow, + 9: MapSubwindows, + 10: UnmapWindow, + 11: UnmapSubwindows, + 12: ConfigureWindow, + 13: CirculateWindow, + 14: GetGeometry, + 15: QueryTree, + 16: InternAtom, + 17: GetAtomName, + 18: ChangeProperty, + 19: DeleteProperty, + 20: GetProperty, + 21: ListProperties, + 22: SetSelectionOwner, + 23: GetSelectionOwner, + 24: ConvertSelection, + 25: SendEvent, + 26: GrabPointer, + 27: UngrabPointer, + 28: GrabButton, + 29: UngrabButton, + 30: ChangeActivePointerGrab, + 31: GrabKeyboard, + 32: UngrabKeyboard, + 33: GrabKey, + 34: UngrabKey, + 35: AllowEvents, + 36: GrabServer, + 37: UngrabServer, + 38: QueryPointer, + 39: GetMotionEvents, + 40: TranslateCoords, + 41: WarpPointer, + 42: SetInputFocus, + 43: GetInputFocus, + 44: QueryKeymap, + 45: OpenFont, + 46: CloseFont, + 47: QueryFont, + 48: QueryTextExtents, + 49: ListFonts, + 50: ListFontsWithInfo, + 51: SetFontPath, + 52: GetFontPath, + 53: CreatePixmap, + 54: FreePixmap, + 55: CreateGC, + 56: ChangeGC, + 57: CopyGC, + 58: SetDashes, + 59: SetClipRectangles, + 60: FreeGC, + 61: ClearArea, + 62: CopyArea, + 63: CopyPlane, + 64: PolyPoint, + 65: PolyLine, + 66: PolySegment, + 67: PolyRectangle, + 68: PolyArc, + 69: FillPoly, + 70: PolyFillRectangle, + 71: PolyFillArc, + 72: PutImage, + 73: GetImage, + 74: PolyText8, + 75: PolyText16, + 76: ImageText8, + 77: ImageText16, + 78: CreateColormap, + 79: FreeColormap, + 80: CopyColormapAndFree, + 81: InstallColormap, + 82: UninstallColormap, + 83: ListInstalledColormaps, + 84: AllocColor, + 85: AllocNamedColor, + 86: AllocColorCells, + 87: AllocColorPlanes, + 88: FreeColors, + 89: StoreColors, + 90: StoreNamedColor, + 91: QueryColors, + 92: LookupColor, + 93: CreateCursor, + 94: CreateGlyphCursor, + 95: FreeCursor, + 96: RecolorCursor, + 97: QueryBestSize, + 98: QueryExtension, + 99: ListExtensions, + 100: ChangeKeyboardMapping, + 101: GetKeyboardMapping, + 102: ChangeKeyboardControl, + 103: GetKeyboardControl, + 104: Bell, + 105: ChangePointerControl, + 106: GetPointerControl, + 107: SetScreenSaver, + 108: GetScreenSaver, + 109: ChangeHosts, + 110: ListHosts, + 111: SetAccessControl, + 112: SetCloseDownMode, + 113: KillClient, + 114: RotateProperties, + 115: ForceScreenSaver, + 116: SetPointerMapping, + 117: GetPointerMapping, + 118: SetModifierMapping, + 119: GetModifierMapping, + 127: NoOperation, + } diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/rq.py b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/rq.py new file mode 100644 index 0000000..c54804e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/rq.py @@ -0,0 +1,1463 @@ +# Xlib.protocol.rq -- structure primitives for request, events and errors +# +# Copyright (C) 2000-2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Standard modules +import sys +import traceback +import struct +from array import array + +# Python 2/3 compatibility. +from six import PY3, binary_type, byte2int, indexbytes, iterbytes + +# Xlib modules +from .. import X +from ..support import lock + + +def decode_string(bs): + return bs.decode('latin1') + +if PY3: + def encode_array(a): + return a.tobytes() +else: + def encode_array(a): + return a.tostring() + + +class BadDataError(Exception): pass + +# These are struct codes, we know their byte sizes + +signed_codes = { 1: 'b', 2: 'h', 4: 'l' } +unsigned_codes = { 1: 'B', 2: 'H', 4: 'L' } + + +# Unfortunately, we don't know the array sizes of B, H and L, since +# these use the underlying architecture's size for a char, short and +# long. Therefore we probe for their sizes, and additionally create +# a mapping that translates from struct codes to array codes. +# +# Bleah. + +array_unsigned_codes = { } +struct_to_array_codes = { } + +for c in 'bhil': + size = array(c).itemsize + array_unsigned_codes[size] = c.upper() + try: + struct_to_array_codes[signed_codes[size]] = c + struct_to_array_codes[unsigned_codes[size]] = c.upper() + except KeyError: + pass + +# print array_unsigned_codes, struct_to_array_codes + + +class Field(object): + """Field objects represent the data fields of a Struct. + + Field objects must have the following attributes: + + name -- the field name, or None + structcode -- the struct codes representing this field + structvalues -- the number of values encodes by structcode + + Additionally, these attributes should either be None or real methods: + + check_value -- check a value before it is converted to binary + parse_value -- parse a value after it has been converted from binary + + If one of these attributes are None, no check or additional + parsings will be done one values when converting to or from binary + form. Otherwise, the methods should have the following behaviour: + + newval = check_value(val) + Check that VAL is legal when converting to binary form. The + value can also be converted to another Python value. In any + case, return the possibly new value. NEWVAL should be a + single Python value if structvalues is 1, a tuple of + structvalues elements otherwise. + + newval = parse_value(val, display) + VAL is an unpacked Python value, which now can be further + refined. DISPLAY is the current Display object. Return the + new value. VAL will be a single value if structvalues is 1, + a tuple of structvalues elements otherwise. + + If `structcode' is None the Field must have the method + f.parse_binary_value() instead. See its documentation string for + details. + """ + name = None + default = None + + structcode = None + structvalues = 0 + + check_value = None + parse_value = None + + keyword_args = False + + def __init__(self): + pass + + def parse_binary_value(self, data, display, length, format): + """value, remaindata = f.parse_binary_value(data, display, length, format) + + Decode a value for this field from the binary string DATA. + If there are a LengthField and/or a FormatField connected to this + field, their values will be LENGTH and FORMAT, respectively. If + there are no such fields the parameters will be None. + + DISPLAY is the display involved, which is really only used by + the Resource fields. + + The decoded value is returned as VALUE, and the remaining part + of DATA shold be returned as REMAINDATA. + """ + raise RuntimeError('Neither structcode or parse_binary_value ' \ + 'provided for {0}'.format(self)) + + +class Pad(Field): + def __init__(self, size): + self.size = size + self.value = b'\0' * size + self.structcode = '{0}x'.format(size) + self.structvalues = 0 + + +class ConstantField(Field): + def __init__(self, value): + self.value = value + + +class Opcode(ConstantField): + structcode = 'B' + structvalues = 1 + +class ReplyCode(ConstantField): + structcode = 'B' + structvalues = 1 + + def __init__(self): + self.value = 1 + +class LengthField(Field): + """A LengthField stores the length of some other Field whose size + may vary, e.g. List and String8. + + Its name should be the same as the name of the field whose size + it stores. The other_fields attribute can be used to specify the + names of other fields whose sizes are stored by this field, so + a single length field can set the length of multiple fields. + + The lf.get_binary_value() method of LengthFields is not used, instead + a lf.get_binary_length() should be provided. + + Unless LengthField.get_binary_length() is overridden in child classes, + there should also be a lf.calc_length(). + """ + structcode = 'L' + structvalues = 1 + other_fields = None + + def calc_length(self, length): + """newlen = lf.calc_length(length) + + Return a new length NEWLEN based on the provided LENGTH. + """ + + return length + + +class TotalLengthField(LengthField): + pass + +class RequestLength(TotalLengthField): + structcode = 'H' + structvalues = 1 + + def calc_length(self, length): + return length // 4 + +class ReplyLength(TotalLengthField): + structcode = 'L' + structvalues = 1 + + def calc_length(self, length): + return (length - 32) // 4 + + +class LengthOf(LengthField): + def __init__(self, name, size): + if isinstance(name, (list, tuple)): + self.name = name[0] + self.other_fields = name[1:] + else: + self.name = name + self.structcode = unsigned_codes[size] + + +class OddLength(LengthField): + structcode = 'B' + structvalues = 1 + + def __init__(self, name): + self.name = name + + def calc_length(self, length): + return length % 2 + + def parse_value(self, value, display): + if value == 0: + return 'even' + else: + return 'odd' + + +class FormatField(Field): + """A FormatField encodes the format of some other field, in a manner + similar to LengthFields. + + The ff.get_binary_value() method is not used, replaced by + ff.get_binary_format(). + """ + + structvalues = 1 + + def __init__(self, name, size): + self.name = name + self.structcode = unsigned_codes[size] + +Format = FormatField + + +class ValueField(Field): + def __init__(self, name, default = None): + self.name = name + self.default = default + + +class Int8(ValueField): + structcode = 'b' + structvalues = 1 + +class Int16(ValueField): + structcode = 'h' + structvalues = 1 + +class Int32(ValueField): + structcode = 'l' + structvalues = 1 + +class Card8(ValueField): + structcode = 'B' + structvalues = 1 + +class Card16(ValueField): + structcode = 'H' + structvalues = 1 + +class Card32(ValueField): + structcode = 'L' + structvalues = 1 + + +class Resource(Card32): + cast_function = '__resource__' + class_name = 'resource' + + def __init__(self, name, codes = (), default = None): + Card32.__init__(self, name, default) + self.codes = codes + + def check_value(self, value): + if hasattr(value, self.cast_function): + return getattr(value, self.cast_function)() + else: + return value + + def parse_value(self, value, display): + # if not display: + # return value + if value in self.codes: + return value + + c = display.get_resource_class(self.class_name) + if c: + return c(display, value) + else: + return value + +class Window(Resource): + cast_function = '__window__' + class_name = 'window' + +class Pixmap(Resource): + cast_function = '__pixmap__' + class_name = 'pixmap' + +class Drawable(Resource): + cast_function = '__drawable__' + class_name = 'drawable' + +class Fontable(Resource): + cast_function = '__fontable__' + class_name = 'fontable' + +class Font(Resource): + cast_function = '__font__' + class_name = 'font' + +class GC(Resource): + cast_function = '__gc__' + class_name = 'gc' + +class Colormap(Resource): + cast_function = '__colormap__' + class_name = 'colormap' + +class Cursor(Resource): + cast_function = '__cursor__' + class_name = 'cursor' + + +class Bool(ValueField): + structvalues = 1 + structcode = 'B' + + def check_value(self, value): + return not not value + +class Set(ValueField): + structvalues = 1 + + def __init__(self, name, size, values, default = None): + ValueField.__init__(self, name, default) + self.structcode = unsigned_codes[size] + self.values = values + + def check_value(self, val): + if val not in self.values: + raise ValueError('field %s: argument %s not in %s' + % (self.name, val, self.values)) + + return val + +class Gravity(Set): + def __init__(self, name): + Set.__init__(self, name, 1, (X.ForgetGravity, X.StaticGravity, + X.NorthWestGravity, X.NorthGravity, + X.NorthEastGravity, X.WestGravity, + X.CenterGravity, X.EastGravity, + X.SouthWestGravity, X.SouthGravity, + X.SouthEastGravity)) + + +class FixedBinary(ValueField): + structvalues = 1 + + def __init__(self, name, size): + ValueField.__init__(self, name) + self.structcode = '{0}s'.format(size) + + +class Binary(ValueField): + structcode = None + + def __init__(self, name, pad = 1): + ValueField.__init__(self, name) + self.pad = pad + + def pack_value(self, val): + val_bytes = val + slen = len(val_bytes) + + if self.pad: + return val_bytes + b'\0' * ((4 - slen % 4) % 4), slen, None + else: + return val_bytes, slen, None + + def parse_binary_value(self, data, display, length, format): + if length is None: + return data, b'' + + if self.pad: + slen = length + ((4 - length % 4) % 4) + else: + slen = length + + return data[:length], data[slen:] + + +class String8(ValueField): + structcode = None + + def __init__(self, name, pad = 1): + ValueField.__init__(self, name) + self.pad = pad + + def pack_value(self, val): + if isinstance(val, bytes): + val_bytes = val + else: + val_bytes = val.encode() + slen = len(val_bytes) + + if self.pad: + return val_bytes + b'\0' * ((4 - slen % 4) % 4), slen, None + else: + return val_bytes, slen, None + + def parse_binary_value(self, data, display, length, format): + if length is None: + return decode_string(data), b'' + + if self.pad: + slen = length + ((4 - length % 4) % 4) + else: + slen = length + + data_str = decode_string(data[:length]) + + return data_str, data[slen:] + + +class String16(ValueField): + structcode = None + + def __init__(self, name, pad = 1): + ValueField.__init__(self, name) + self.pad = pad + + def pack_value(self, val): + """Convert 8-byte string into 16-byte list""" + if isinstance(val, bytes): + val = list(iterbytes(val)) + + slen = len(val) + + if self.pad: + pad = b'\0\0' * (slen % 2) + else: + pad = b'' + + return struct.pack('>' + 'H' * slen, *val) + pad, slen, None + + def parse_binary_value(self, data, display, length, format): + if length == 'odd': + length = len(data) // 2 - 1 + elif length == 'even': + length = len(data) // 2 + + if self.pad: + slen = length + (length % 2) + else: + slen = length + + return struct.unpack('>' + 'H' * length, data[:length * 2]), data[slen * 2:] + + + +class List(ValueField): + """The List, FixedList and Object fields store compound data objects. + The type of data objects must be provided as an object with the + following attributes and methods: + + ... + + """ + + structcode = None + + def __init__(self, name, type, pad = 1): + ValueField.__init__(self, name) + self.type = type + self.pad = pad + + def parse_binary_value(self, data, display, length, format): + if length is None: + ret = [] + if self.type.structcode is None: + while data: + val, data = self.type.parse_binary(data, display) + ret.append(val) + else: + scode = '=' + self.type.structcode + slen = struct.calcsize(scode) + pos = 0 + while pos + slen <= len(data): + v = struct.unpack(scode, data[pos: pos + slen]) + + if self.type.structvalues == 1: + v = v[0] + + if self.type.parse_value is None: + ret.append(v) + else: + ret.append(self.type.parse_value(v, display)) + + pos = pos + slen + + data = data[pos:] + + else: + ret = [None] * int(length) + + if self.type.structcode is None: + for i in range(0, length): + ret[i], data = self.type.parse_binary(data, display) + else: + scode = '=' + self.type.structcode + slen = struct.calcsize(scode) + pos = 0 + for i in range(0, length): + v = struct.unpack(scode, data[pos: pos + slen]) + + if self.type.structvalues == 1: + v = v[0] + + if self.type.parse_value is None: + ret[i] = v + else: + ret[i] = self.type.parse_value(v, display) + + pos = pos + slen + + data = data[pos:] + + if self.pad: + data = data[len(data) % 4:] + + return ret, data + + def pack_value(self, val): + # Single-char values, we'll assume that means integer lists. + if self.type.structcode and len(self.type.structcode) == 1: + if self.type.check_value is not None: + val = [self.type.check_value(v) for v in val] + a = array(struct_to_array_codes[self.type.structcode], val) + data = encode_array(a) + else: + data = [] + for v in val: + data.append(self.type.pack_value(v)) + + data = b''.join(data) + + if self.pad: + dlen = len(data) + data = data + b'\0' * ((4 - dlen % 4) % 4) + + return data, len(val), None + + +class FixedList(List): + def __init__(self, name, size, type, pad = 1): + List.__init__(self, name, type, pad) + self.size = size + + def parse_binary_value(self, data, display, length, format): + return List.parse_binary_value(self, data, display, self.size, format) + + def pack_value(self, val): + if len(val) != self.size: + raise BadDataError('length mismatch for FixedList %s' % self.name) + return List.pack_value(self, val) + + +class Object(ValueField): + def __init__(self, name, type, default = None): + ValueField.__init__(self, name, default) + self.type = type + self.structcode = self.type.structcode + self.structvalues = self.type.structvalues + + def parse_binary_value(self, data, display, length, format): + return self.type.parse_binary(data, display) + + def parse_value(self, val, display): + return self.type.parse_value(val, display) + + def pack_value(self, val): + return self.type.pack_value(val) + + def check_value(self, val): + if isinstance(val, tuple): + vals = [] + i = 0 + for f in self.type.fields: + if f.name: + if f.check_value is None: + v = val[i] + else: + v = f.check_value(val[i]) + if f.structvalues == 1: + vals.append(v) + else: + vals.extend(v) + i = i + 1 + return vals + + if isinstance(val, dict): + data = val + elif isinstance(val, DictWrapper): + data = val._data + else: + raise TypeError('Object value must be tuple, dictionary or DictWrapper: %s' % val) + + vals = [] + for f in self.type.fields: + if f.name: + if f.check_value is None: + v = data[f.name] + else: + v = f.check_value(data[f.name]) + if f.structvalues == 1: + vals.append(v) + else: + vals.extend(v) + + return vals + + +class PropertyData(ValueField): + structcode = None + + def parse_binary_value(self, data, display, length, format): + if length is None: + length = len(data) // (format // 8) + else: + length = int(length) + + if format == 0: + ret = None + + elif format == 8: + ret = (8, data[:length]) + data = data[length + ((4 - length % 4) % 4):] + + elif format == 16: + ret = (16, array(array_unsigned_codes[2], data[:2 * length])) + data = data[2 * (length + length % 2):] + + elif format == 32: + ret = (32, array(array_unsigned_codes[4], data[:4 * length])) + data = data[4 * length:] + + return ret, data + + def pack_value(self, value): + fmt, val = value + + if fmt not in (8, 16, 32): + raise BadDataError('Invalid property data format {0}'.format(fmt)) + + if isinstance(val, binary_type): + size = fmt // 8 + vlen = len(val) + if vlen % size: + vlen = vlen - vlen % size + data = val[:vlen] + else: + data = val + + dlen = vlen // size + + else: + if isinstance(val, tuple): + val = list(val) + + size = fmt // 8 + a = array(array_unsigned_codes[size], val) + data = encode_array(a) + dlen = len(val) + + dl = len(data) + data = data + b'\0' * ((4 - dl % 4) % 4) + + return data, dlen, fmt + + +class FixedPropertyData(PropertyData): + def __init__(self, name, size): + PropertyData.__init__(self, name) + self.size = size + + def parse_binary_value(self, data, display, length, format): + return PropertyData.parse_binary_value(self, data, display, + self.size // (format // 8), format) + + def pack_value(self, value): + data, dlen, fmt = PropertyData.pack_value(self, value) + + if len(data) != self.size: + raise BadDataError('Wrong data length for FixedPropertyData: %s' + % (value, )) + + return data, dlen, fmt + + +class ValueList(Field): + structcode = None + keyword_args = True + default = 'usekeywords' + + def __init__(self, name, mask, pad, *fields): + self.name = name + self.maskcode = '={0}{1}x'.format(unsigned_codes[mask], pad).encode() + self.maskcodelen = struct.calcsize(self.maskcode) + self.fields = [] + + flag = 1 + for f in fields: + if f.name: + self.fields.append((f, flag)) + flag = flag << 1 + + def pack_value(self, arg, keys): + mask = 0 + data = b'' + + if arg == self.default: + arg = keys + + for field, flag in self.fields: + if field.name in arg: + mask = mask | flag + + val = arg[field.name] + if field.check_value is not None: + val = field.check_value(val) + + d = struct.pack('=' + field.structcode, val) + data = data + d + b'\0' * (4 - len(d)) + + return struct.pack(self.maskcode, mask) + data, None, None + + def parse_binary_value(self, data, display, length, format): + r = {} + + mask = int(struct.unpack(self.maskcode, data[:self.maskcodelen])[0]) + data = data[self.maskcodelen:] + + for field, flag in self.fields: + if mask & flag: + if field.structcode: + vals = struct.unpack('=' + field.structcode, + data[:struct.calcsize('=' + field.structcode)]) + if field.structvalues == 1: + vals = vals[0] + + if field.parse_value is not None: + vals = field.parse_value(vals, display) + + else: + vals, d = field.parse_binary_value(data[:4], display, None, None) + + r[field.name] = vals + data = data[4:] + + return DictWrapper(r), data + + +class KeyboardMapping(ValueField): + structcode = None + + def parse_binary_value(self, data, display, length, format): + if length is None: + dlen = len(data) + else: + dlen = 4 * length * format + + a = array(array_unsigned_codes[4], bytes(data[:dlen])) + + ret = [] + for i in range(0, len(a), format): + ret.append(a[i : i + format]) + + return ret, data[dlen:] + + def pack_value(self, value): + keycodes = 0 + for v in value: + keycodes = max(keycodes, len(v)) + + a = array(array_unsigned_codes[4]) + + for v in value: + for k in v: + a.append(k) + for i in range(len(v), keycodes): + a.append(X.NoSymbol) + + return encode_array(a), len(value), keycodes + + +class ModifierMapping(ValueField): + structcode = None + + def parse_binary_value(self, data, display, length, format): + a = array(array_unsigned_codes[1], data[:8 * format]) + + ret = [] + for i in range(0, 8): + ret.append(a[i * format : (i + 1) * format]) + + return ret, data[8 * format:] + + def pack_value(self, value): + if len(value) != 8: + raise BadDataError('ModifierMapping list should have eight elements') + + keycodes = 0 + for v in value: + keycodes = max(keycodes, len(v)) + + a = array(array_unsigned_codes[1]) + + for v in value: + for k in v: + a.append(k) + for i in range(len(v), keycodes): + a.append(0) + + return encode_array(a), len(value), keycodes + +class EventField(ValueField): + structcode = None + + def pack_value(self, value): + if not isinstance(value, Event): + raise BadDataError('%s is not an Event for field %s' % (value, self.name)) + + return value._binary, None, None + + def parse_binary_value(self, data, display, length, format): + from . import event + + estruct = display.event_classes.get(byte2int(data) & 0x7f, event.AnyEvent) + if type(estruct) == dict: + # this etype refers to a set of sub-events with individual subcodes + estruct = estruct[indexbytes(data, 1)] + + return estruct(display = display, binarydata = data[:32]), data[32:] + + +# +# Objects usable for List and FixedList fields. +# Struct is also usable. +# + +class ScalarObj(object): + def __init__(self, code): + self.structcode = code + self.structvalues = 1 + self.parse_value = None + self.check_value = None + +Card8Obj = ScalarObj('B') +Card16Obj = ScalarObj('H') +Card32Obj = ScalarObj('L') + +class ResourceObj(object): + structcode = 'L' + structvalues = 1 + + def __init__(self, class_name): + self.class_name = class_name + self.check_value = None + + def parse_value(self, value, display): + # if not display: + # return value + c = display.get_resource_class(self.class_name) + if c: + return c(display, value) + else: + return value + +WindowObj = ResourceObj('window') +ColormapObj = ResourceObj('colormap') + +class StrClass(object): + structcode = None + + def pack_value(self, val): + return (chr(len(val)) + val).encode() + + def parse_binary(self, data, display): + slen = byte2int(data) + 1 + return decode_string(data[1:slen]), data[slen:] + +Str = StrClass() + + +class Struct(object): + + """Struct objects represents a binary data structure. It can + contain both fields with static and dynamic sizes. However, all + static fields must appear before all dynamic fields. + + Fields are represented by various subclasses of the abstract base + class Field. The fields of a structure are given as arguments + when instantiating a Struct object. + + Struct objects have two public methods: + + to_binary() -- build a binary representation of the structure + with the values given as arguments + parse_binary() -- convert a binary (string) representation into + a Python dictionary or object. + + These functions will be generated dynamically for each Struct + object to make conversion as fast as possible. They are + generated the first time the methods are called. + """ + + def __init__(self, *fields): + self.fields = fields + + # Structures for to_binary, parse_value and parse_binary + self.static_codes = '=' + self.static_values = 0 + self.static_fields = [] + self.static_size = None + self.var_fields = [] + + for f in self.fields: + # Append structcode if there is one and we haven't + # got any varsize fields yet. + if f.structcode is not None: + assert not self.var_fields + + self.static_codes = self.static_codes + f.structcode + + # Only store fields with values + if f.structvalues > 0: + self.static_fields.append(f) + self.static_values = self.static_values + f.structvalues + + # If we have got one varsize field, all the rest must + # also be varsize fields. + else: + self.var_fields.append(f) + + self.static_size = struct.calcsize(self.static_codes) + if self.var_fields: + self.structcode = None + self.structvalues = 0 + else: + self.structcode = self.static_codes[1:] + self.structvalues = self.static_values + + + # These functions get called only once, as they will override + # themselves with dynamically created functions in the Struct + # object + + def to_binary(self, *varargs, **keys): + """data = s.to_binary(...) + + Convert Python values into the binary representation. The + arguments will be all value fields with names, in the order + given when the Struct object was instantiated. With one + exception: fields with default arguments will be last. + + Returns the binary representation as the string DATA. + """ + # Emulate Python function argument handling with our field names + names = [f.name for f in self.fields \ + if isinstance(f, ValueField) and f.name] + field_args = dict(zip(names, varargs)) + if set(field_args).intersection(keys): + dupes = ", ".join(set(field_args).intersection(keys)) + raise TypeError("{0} arguments were passed both positionally and by keyword".format(dupes)) + field_args.update(keys) + for f in self.fields: + if f.name and (f.name not in field_args): + if f.default is None: + raise TypeError("Missing required argument {0}".format(f.name)) + field_args[f.name] = f.default + # /argument handling + + # First pack all varfields so their lengths and formats are + # available when we pack their static LengthFields and + # FormatFields + + total_length = self.static_size + var_vals = {} + lengths = {} + formats = {} + + for f in self.var_fields: + if f.keyword_args: + v, l, fm = f.pack_value(field_args[f.name], keys) + else: + v, l, fm = f.pack_value(field_args[f.name]) + var_vals[f.name] = v + lengths[f.name] = l + formats[f.name] = fm + + total_length += len(v) + + + # Construct item list for struct.pack call, packing all static fields. + pack_items = [] + + for f in self.static_fields: + if isinstance(f, LengthField): + + # If this is a total length field, insert + # the calculated field value here + if isinstance(f, TotalLengthField): + pack_items.append(f.calc_length(total_length)) + else: + pack_items.append(f.calc_length(lengths[f.name])) + + # Format field, just insert the value we got previously + elif isinstance(f, FormatField): + pack_items.append(formats[f.name]) + + # A constant field, insert its value directly + elif isinstance(f, ConstantField): + pack_items.append(f.value) + + # Value fields + else: + if f.structvalues == 1: + # If there's a value check/convert function, call it + if f.check_value is not None: + pack_items.append(f.check_value(field_args[f.name])) + # Else just use the argument as provided + else: + pack_items.append(field_args[f.name]) + + # Multivalue field. Handled like single valuefield, + # but the value are tuple unpacked into separate arguments + # which are appended to pack_items + else: + if f.check_value is not None: + pack_items.extend(f.check_value(field_args[f.name])) + else: + pack_items.extend(field_args[f.name]) + + static_part = struct.pack(self.static_codes, *pack_items) + var_parts = [var_vals[f.name] for f in self.var_fields] + return static_part + b''.join(var_parts) + + + def pack_value(self, value): + + """ This function allows Struct objects to be used in List and + Object fields. Each item represents the arguments to pass to + to_binary, either a tuple, a dictionary or a DictWrapper. + + """ + + if type(value) is tuple: + return self.to_binary(*value) + elif isinstance(value, dict): + return self.to_binary(**value) + elif isinstance(value, DictWrapper): + return self.to_binary(**value._data) + else: + raise BadDataError('%s is not a tuple or a list' % (value)) + + + def parse_value(self, val, display, rawdict = False): + + """This function is used by List and Object fields to convert + Struct objects with no var_fields into Python values. + + """ + ret = {} + vno = 0 + for f in self.static_fields: + # Fields without names should be ignored, and there should + # not be any length or format fields if this function + # ever gets called. (If there were such fields, there should + # be a matching field in var_fields and then parse_binary + # would have been called instead. + + if not f.name: + pass + + elif isinstance(f, LengthField): + pass + + elif isinstance(f, FormatField): + pass + + # Value fields + else: + # If this field has a parse_value method, call it, otherwise + # use the unpacked value as is. + if f.structvalues == 1: + field_val = val[vno] + else: + field_val = val[vno:vno+f.structvalues] + + if f.parse_value is not None: + field_val = f.parse_value(field_val, display, rawdict=rawdict) + ret[f.name] = field_val + + vno = vno + f.structvalues + + if not rawdict: + return DictWrapper(ret) + return ret + + def parse_binary(self, data, display, rawdict = False): + + """values, remdata = s.parse_binary(data, display, rawdict = False) + + Convert a binary representation of the structure into Python values. + + DATA is a string or a buffer containing the binary data. + DISPLAY should be a Xlib.protocol.display.Display object if + there are any Resource fields or Lists with ResourceObjs. + + The Python values are returned as VALUES. If RAWDICT is true, + a Python dictionary is returned, where the keys are field + names and the values are the corresponding Python value. If + RAWDICT is false, a DictWrapper will be returned where all + fields are available as attributes. + + REMDATA are the remaining binary data, unused by the Struct object. + + """ + ret = {} + val = struct.unpack(self.static_codes, data[:self.static_size]) + lengths = {} + formats = {} + + vno = 0 + for f in self.static_fields: + + # Fields without name should be ignored. This is typically + # pad and constant fields + + if not f.name: + pass + + # Store index in val for Length and Format fields, to be used + # when treating varfields. + + elif isinstance(f, LengthField): + f_names = [f.name] + if f.other_fields: + f_names.extend(f.other_fields) + field_val = val[vno] + if f.parse_value is not None: + field_val = f.parse_value(field_val, display) + for f_name in f_names: + lengths[f_name] = field_val + + elif isinstance(f, FormatField): + formats[f.name] = val[vno] + + # Treat value fields the same was as in parse_value. + else: + if f.structvalues == 1: + field_val = val[vno] + else: + field_val = val[vno:vno+f.structvalues] + + if f.parse_value is not None: + field_val = f.parse_value(field_val, display) + ret[f.name] = field_val + + vno = vno + f.structvalues + + data = data[self.static_size:] + + # Call parse_binary_value for each var_field, passing the + # length and format values from the unpacked val. + + for f in self.var_fields: + ret[f.name], data = f.parse_binary_value(data, display, + lengths.get(f.name), + formats.get(f.name), + ) + + if not rawdict: + ret = DictWrapper(ret) + return ret, data + + +class TextElements8(ValueField): + string_textitem = Struct( LengthOf('string', 1), + Int8('delta'), + String8('string', pad = 0) ) + + def pack_value(self, value): + data = b'' + args = {} + + for v in value: + # Let values be simple strings, meaning a delta of 0 + if type(v) in (str, bytes): + v = (0, v) + + # A tuple, it should be (delta, string) + # Encode it as one or more textitems + + if isinstance(v, (tuple, dict, DictWrapper)): + + if isinstance(v, tuple): + delta, m_str = v + else: + delta = v['delta'] + m_str = v['string'] + + while delta or m_str: + args['delta'] = delta + args['string'] = m_str[:254] + + data = data + self.string_textitem.to_binary(*(), **args) + + delta = 0 + m_str = m_str[254:] + + # Else an integer, i.e. a font change + else: + # Use fontable cast function if instance + if isinstance(v, Fontable): + v = v.__fontable__() + + data = data + struct.pack('>BL', 255, v) + + # Pad out to four byte length + dlen = len(data) + return data + b'\0' * ((4 - dlen % 4) % 4), None, None + + def parse_binary_value(self, data, display, length, format): + values = [] + while 1: + if len(data) < 2: + break + + # font change + if byte2int(data) == 255: + values.append(struct.unpack('>L', bytes(data[1:5]))[0]) + data = data[5:] + + # skip null strings + elif byte2int(data) == 0 and indexbytes(data, 1) == 0: + data = data[2:] + + # string with delta + else: + v, data = self.string_textitem.parse_binary(data, display) + values.append(v) + + return values, '' + + + +class TextElements16(TextElements8): + string_textitem = Struct( LengthOf('string', 1), + Int8('delta'), + String16('string', pad = 0) ) + + + +class GetAttrData(object): + def __getattr__(self, attr): + try: + if self._data: + return self._data[attr] + else: + raise AttributeError(attr) + except KeyError: + raise AttributeError(attr) + +class DictWrapper(GetAttrData): + def __init__(self, dict): + self.__dict__['_data'] = dict + + def __getitem__(self, key): + return self._data[key] + + def __setitem__(self, key, value): + self._data[key] = value + + def __delitem__(self, key): + del self._data[key] + + def __setattr__(self, key, value): + self._data[key] = value + + def __delattr__(self, key): + del self._data[key] + + def __str__(self): + return str(self._data) + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, repr(self._data)) + + def __lt__(self, other): + if isinstance(other, DictWrapper): + return self._data < other._data + else: + return self._data < other + + def __gt__(self, other): + if isinstance(other, DictWrapper): + return self._data > other._data + else: + return self._data > other + + def __eq__(self, other): + if isinstance(other, DictWrapper): + return self._data == other._data + else: + return self._data == other + + +class Request(object): + def __init__(self, display, onerror = None, *args, **keys): + self._errorhandler = onerror + self._binary = self._request.to_binary(*args, **keys) + self._serial = None + display.send_request(self, onerror is not None) + + def _set_error(self, error): + if self._errorhandler is not None: + return call_error_handler(self._errorhandler, error, self) + else: + return 0 + +class ReplyRequest(GetAttrData): + def __init__(self, display, defer = False, *args, **keys): + self._display = display + self._binary = self._request.to_binary(*args, **keys) + self._serial = None + self._data = None + self._error = None + + self._response_lock = lock.allocate_lock() + + self._display.send_request(self, True) + if not defer: + self.reply() + + def reply(self): + # Send request and wait for reply if we hasn't + # already got one. This means that reply() can safely + # be called more than one time. + + self._response_lock.acquire() + while self._data is None and self._error is None: + self._display.send_recv_lock.acquire() + self._response_lock.release() + + self._display.send_and_recv(request = self._serial) + self._response_lock.acquire() + + self._response_lock.release() + self._display = None + + # If error has been set, raise it + if self._error: + raise self._error + + def _parse_response(self, data): + self._response_lock.acquire() + self._data, d = self._reply.parse_binary(data, self._display, rawdict = True) + self._response_lock.release() + + def _set_error(self, error): + self._response_lock.acquire() + self._error = error + self._response_lock.release() + return 1 + + def __repr__(self): + return '<%s serial = %s, data = %s, error = %s>' % (self.__class__.__name__, self._serial, self._data, self._error) + + +class Event(GetAttrData): + def __init__(self, binarydata = None, display = None, + **keys): + if binarydata: + self._binary = binarydata + self._data, data = self._fields.parse_binary(binarydata, display, + rawdict = True) + # split event type into type and send_event bit + self._data['send_event'] = not not self._data['type'] & 0x80 + self._data['type'] = self._data['type'] & 0x7f + else: + if self._code: + keys['type'] = self._code + + keys['sequence_number'] = 0 + + self._binary = self._fields.to_binary(**keys) + + keys['send_event'] = 0 + self._data = keys + + def __repr__(self): + kwlist = [] + for kw, val in self._data.items(): + if kw == 'send_event': + continue + if kw == 'type' and self._data['send_event']: + val = val | 0x80 + kwlist.append('%s = %s' % (kw, repr(val))) + + kws = ', '.join(kwlist) + return '%s(%s)' % (self.__class__.__name__, kws) + + def __lt__(self, other): + if isinstance(other, Event): + return self._data < other._data + else: + return self._data < other + + def __gt__(self, other): + if isinstance(other, Event): + return self._data > other._data + else: + return self._data > other + + def __eq__(self, other): + if isinstance(other, Event): + return self._data == other._data + else: + return self._data == other + + +def call_error_handler(handler, error, request): + try: + return handler(error, request) + except: + sys.stderr.write('Exception raised by error handler.\n') + traceback.print_exc() + return 0 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/structs.py b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/structs.py new file mode 100644 index 0000000..2cbe18b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/protocol/structs.py @@ -0,0 +1,161 @@ +# Xlib.protocol.structs -- some common request structures +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +# Xlib modules +from .. import X + +# Xlib.protocol modules +from . import rq + +def WindowValues(arg): + return rq.ValueList( arg, 4, 0, + rq.Pixmap('background_pixmap'), + rq.Card32('background_pixel'), + rq.Pixmap('border_pixmap'), + rq.Card32('border_pixel'), + rq.Gravity('bit_gravity'), + rq.Gravity('win_gravity'), + rq.Set('backing_store', 1, + (X.NotUseful, X.WhenMapped, X.Always)), + rq.Card32('backing_planes'), + rq.Card32('backing_pixel'), + rq.Bool('override_redirect'), + rq.Bool('save_under'), + rq.Card32('event_mask'), + rq.Card32('do_not_propagate_mask'), + rq.Colormap('colormap'), + rq.Cursor('cursor'), + ) + +def GCValues(arg): + return rq.ValueList( arg, 4, 0, + rq.Set('function', 1, + (X.GXclear, X.GXand, X.GXandReverse, + X.GXcopy, X.GXandInverted, X.GXnoop, + X.GXxor, X.GXor, X.GXnor, X.GXequiv, + X.GXinvert, X.GXorReverse, X.GXcopyInverted, + X.GXorInverted, X.GXnand, X.GXset)), + rq.Card32('plane_mask'), + rq.Card32('foreground'), + rq.Card32('background'), + rq.Card16('line_width'), + rq.Set('line_style', 1, + (X.LineSolid, X.LineOnOffDash, X.LineDoubleDash)), + rq.Set('cap_style', 1, + (X.CapNotLast, X.CapButt, + X.CapRound, X.CapProjecting)), + rq.Set('join_style', 1, + (X.JoinMiter, X.JoinRound, X.JoinBevel)), + rq.Set('fill_style', 1, + (X.FillSolid, X.FillTiled, + X.FillStippled, X.FillOpaqueStippled)), + rq.Set('fill_rule', 1, + (X.EvenOddRule, X.WindingRule)), + rq.Pixmap('tile'), + rq.Pixmap('stipple'), + rq.Int16('tile_stipple_x_origin'), + rq.Int16('tile_stipple_y_origin'), + rq.Font('font'), + rq.Set('subwindow_mode', 1, + (X.ClipByChildren, X.IncludeInferiors)), + rq.Bool('graphics_exposures'), + rq.Int16('clip_x_origin'), + rq.Int16('clip_y_origin'), + rq.Pixmap('clip_mask'), + rq.Card16('dash_offset'), + rq.Card8('dashes'), + rq.Set('arc_mode', 1, (X.ArcChord, X.ArcPieSlice)) + ) + + + +TimeCoord = rq.Struct( + rq.Card32('time'), + rq.Int16('x'), + rq.Int16('y'), + ) + +Host = rq.Struct( + rq.Set('family', 1, (X.FamilyInternet, X.FamilyDECnet, X.FamilyChaos)), + rq.Pad(1), + rq.LengthOf('name', 2), + rq.List('name', rq.Card8Obj) + ) + +CharInfo = rq.Struct( + rq.Int16('left_side_bearing'), + rq.Int16('right_side_bearing'), + rq.Int16('character_width'), + rq.Int16('ascent'), + rq.Int16('descent'), + rq.Card16('attributes'), + ) + +FontProp = rq.Struct( + rq.Card32('name'), + rq.Card32('value'), + ) + +ColorItem = rq.Struct( + rq.Card32('pixel'), + rq.Card16('red'), + rq.Card16('green'), + rq.Card16('blue'), + rq.Card8('flags'), + rq.Pad(1), + ) + + +RGB = rq.Struct( + rq.Card16('red'), + rq.Card16('green'), + rq.Card16('blue'), + rq.Pad(2), + ) + + +Point = rq.Struct( + rq.Int16('x'), + rq.Int16('y'), + ) + +Segment = rq.Struct( + rq.Int16('x1'), + rq.Int16('y1'), + rq.Int16('x2'), + rq.Int16('y2'), + ) + +Rectangle = rq.Struct( + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + ) + +Arc = rq.Struct( + rq.Int16('x'), + rq.Int16('y'), + rq.Card16('width'), + rq.Card16('height'), + rq.Int16('angle1'), + rq.Int16('angle2'), + ) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/rdb.py b/CLI/venv/lib/python3.12/site-packages/Xlib/rdb.py new file mode 100644 index 0000000..8670b30 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/rdb.py @@ -0,0 +1,712 @@ +# Xlib.rdb -- X resource database implementation +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + + +# See end of file for an explanation of the algorithm and +# data structures used. + + +# Standard modules +import re +import sys + +# Xlib modules +from .support import lock + +# Set up a few regexpes for parsing string representation of resources + +comment_re = re.compile(r'^\s*!') +resource_spec_re = re.compile(r'^\s*([-_a-zA-Z0-9?.*]+)\s*:\s*(.*)$') +value_escape_re = re.compile('\\\\([ \tn\\\\]|[0-7]{3,3})') +resource_parts_re = re.compile(r'([.*]+)') + +# Constants used for determining which match is best + +NAME_MATCH = 0 +CLASS_MATCH = 2 +WILD_MATCH = 4 +MATCH_SKIP = 6 + +# Option error class +class OptionError(Exception): + pass + + +class ResourceDB(object): + def __init__(self, file = None, string = None, resources = None): + self.db = {} + self.lock = lock.allocate_lock() + + if file is not None: + self.insert_file(file) + if string is not None: + self.insert_string(string) + if resources is not None: + self.insert_resources(resources) + + def insert_file(self, file): + """insert_file(file) + + Load resources entries from FILE, and insert them into the + database. FILE can be a filename (a string)or a file object. + + """ + + if type(file) is bytes: + file = open(file, 'r') + + self.insert_string(file.read()) + + + def insert_string(self, data): + """insert_string(data) + + Insert the resources entries in the string DATA into the + database. + + """ + + # First split string into lines + lines = data.split('\n') + + while lines: + line = lines[0] + del lines[0] + + # Skip empty line + if not line: + continue + + # Skip comments + if comment_re.match(line): + continue + + # Handle continued lines + while line[-1] == '\\': + if lines: + line = line[:-1] + lines[0] + del lines[0] + else: + line = line[:-1] + break + + # Split line into resource and value + m = resource_spec_re.match(line) + + # Bad line, just ignore it silently + if not m: + continue + + res, value = m.group(1, 2) + + # Convert all escape sequences in value + splits = value_escape_re.split(value) + + for i in range(1, len(splits), 2): + s = splits[i] + if len(s) == 3: + splits[i] = chr(int(s, 8)) + elif s == 'n': + splits[i] = '\n' + + # strip the last value part to get rid of any + # unescaped blanks + splits[-1] = splits[-1].rstrip() + + value = ''.join(splits) + + self.insert(res, value) + + + def insert_resources(self, resources): + """insert_resources(resources) + + Insert all resources entries in the list RESOURCES into the + database. Each element in RESOURCES should be a tuple: + + (resource, value) + + Where RESOURCE is a string and VALUE can be any Python value. + + """ + + for res, value in resources: + self.insert(res, value) + + def insert(self, resource, value): + """insert(resource, value) + + Insert a resource entry into the database. RESOURCE is a + string and VALUE can be any Python value. + + """ + + # Split res into components and bindings + parts = resource_parts_re.split(resource) + + # If the last part is empty, this is an invalid resource + # which we simply ignore + if parts[-1] == '': + return + + self.lock.acquire() + + db = self.db + for i in range(1, len(parts), 2): + + # Create a new mapping/value group + if parts[i - 1] not in db: + db[parts[i - 1]] = ({}, {}) + + # Use second mapping if a loose binding, first otherwise + if '*' in parts[i]: + db = db[parts[i - 1]][1] + else: + db = db[parts[i - 1]][0] + + # Insert value into the derived db + if parts[-1] in db: + db[parts[-1]] = db[parts[-1]][:2] + (value, ) + else: + db[parts[-1]] = ({}, {}, value) + + self.lock.release() + + def __getitem__(self, keys_tuple): + """db[name, class] + + Return the value matching the resource identified by NAME and + CLASS. If no match is found, KeyError is raised. + """ + + # Split name and class into their parts + name, cls = keys_tuple + + namep = name.split('.') + clsp = cls.split('.') + + # It is an error for name and class to have different number + # of parts + + if len(namep) != len(clsp): + raise ValueError('Different number of parts in resource name/class: %s/%s' % (name, cls)) + + complen = len(namep) + matches = [] + + # Lock database and wrap the lookup code in a try-finally + # block to make sure that it is unlocked. + + self.lock.acquire() + try: + + # Precedence order: name -> class -> ? + + if namep[0] in self.db: + bin_insert(matches, _Match((NAME_MATCH, ), self.db[namep[0]])) + + if clsp[0] in self.db: + bin_insert(matches, _Match((CLASS_MATCH, ), self.db[clsp[0]])) + + if '?' in self.db: + bin_insert(matches, _Match((WILD_MATCH, ), self.db['?'])) + + + # Special case for the unlikely event that the resource + # only has one component + if complen == 1 and matches: + x = matches[0] + if x.final(complen): + return x.value() + else: + raise KeyError((name, cls)) + + + # Special case for resources which begins with a loose + # binding, e.g. '*foo.bar' + if '' in self.db: + bin_insert(matches, _Match((), self.db[''][1])) + + + # Now iterate over all components until we find the best match. + + # For each component, we choose the best partial match among + # the mappings by applying these rules in order: + + # Rule 1: If the current group contains a match for the + # name, class or '?', we drop all previously found loose + # binding mappings. + + # Rule 2: A matching name has precedence over a matching + # class, which in turn has precedence over '?'. + + # Rule 3: Tight bindings have precedence over loose + # bindings. + + while matches: + + # Work on the first element == the best current match + + x = matches[0] + del matches[0] + + # print 'path: ', x.path + # if x.skip: + # print 'skip: ', x.db + # else: + # print 'group: ', x.group + # print + + i = x.match_length() + + for part, score in ((namep[i], NAME_MATCH), + (clsp[i], CLASS_MATCH), + ('?', WILD_MATCH)): + + # Attempt to find a match in x + match = x.match(part, score) + if match: + # Hey, we actually found a value! + if match.final(complen): + return match.value() + + # Else just insert the new match + else: + bin_insert(matches, match) + + # Generate a new loose match + match = x.skip_match(complen) + if match: + bin_insert(matches, match) + + # Oh well, nothing matched + raise KeyError((name, cls)) + + finally: + self.lock.release() + + def get(self, res, cls, default = None): + """get(name, class [, default]) + + Return the value matching the resource identified by NAME and + CLASS. If no match is found, DEFAULT is returned, or None if + DEFAULT isn't specified. + + """ + + try: + return self[(res, cls)] + except KeyError: + return default + + def update(self, db): + """update(db) + + Update this database with all resources entries in the resource + database DB. + + """ + + self.lock.acquire() + update_db(self.db, db.db) + self.lock.release() + + def output(self): + """output() + + Return the resource database in text representation. + """ + + self.lock.acquire() + text = output_db('', self.db) + self.lock.release() + return text + + def getopt(self, name, argv, opts): + """getopt(name, argv, opts) + + Parse X command line options, inserting the recognised options + into the resource database. + + NAME is the application name, and will be prepended to all + specifiers. ARGV is the list of command line arguments, + typically sys.argv[1:]. + + OPTS is a mapping of options to resource specifiers. The key is + the option flag (with leading -), and the value is an instance of + some Option subclass: + + NoArg(specifier, value): set resource to value. + IsArg(specifier): set resource to option itself + SepArg(specifier): value is next argument + ResArg: resource and value in next argument + SkipArg: ignore this option and next argument + SkipLine: ignore rest of arguments + SkipNArgs(count): ignore this option and count arguments + + The remaining, non-option, oparguments is returned. + + rdb.OptionError is raised if there is an error in the argument list. + """ + + while argv and argv[0] and argv[0][0] == '-': + try: + argv = opts[argv[0]].parse(name, self, argv) + except KeyError: + raise OptionError('unknown option: %s' % argv[0]) + except IndexError: + raise OptionError('missing argument to option: %s' % argv[0]) + + return argv + + +class _Match(object): + def __init__(self, path, dbs): + self.path = path + + if type(dbs) is tuple: + self.skip = 0 + self.group = dbs + + else: + self.skip = 1 + self.db = dbs + + def __lt__(self, other): + return self.path < other.path + + def __gt__(self, other): + return self.path > other.path + + def __eq__(self, other): + return self.path == other.path + + def match_length(self): + return len(self.path) + + def match(self, part, score): + if self.skip: + if part in self.db: + return _Match(self.path + (score, ), self.db[part]) + else: + return None + else: + if part in self.group[0]: + return _Match(self.path + (score, ), self.group[0][part]) + elif part in self.group[1]: + return _Match(self.path + (score + 1, ), self.group[1][part]) + else: + return None + + def skip_match(self, complen): + # Can't make another skip if we have run out of components + if len(self.path) + 1 >= complen: + return None + + # If this already is a skip match, clone a new one + if self.skip: + if self.db: + return _Match(self.path + (MATCH_SKIP, ), self.db) + else: + return None + + # Only generate a skip match if the loose binding mapping + # is non-empty + elif self.group[1]: + return _Match(self.path + (MATCH_SKIP, ), self.group[1]) + + # This is a dead end match + else: + return None + + def final(self, complen): + if not self.skip and len(self.path) == complen and len(self.group) > 2: + return 1 + else: + return 0 + + def value(self): + return self.group[2] + + +# +# Helper function for ResourceDB.__getitem__() +# + +def bin_insert(list, element): + """bin_insert(list, element) + + Insert ELEMENT into LIST. LIST must be sorted, and ELEMENT will + be inserted to that LIST remains sorted. If LIST already contains + ELEMENT, it will not be duplicated. + + """ + + if not list: + list.append(element) + return + + lower = 0 + upper = len(list) - 1 + + while lower <= upper: + center = (lower + upper) // 2 + if element < list[center]: + upper = center - 1 + elif element > list[center]: + lower = center + 1 + elif element == list[center]: + return + + if element < list[upper]: + list.insert(upper, element) + elif element > list[upper]: + list.insert(upper + 1, element) + + +# +# Helper functions for ResourceDB.update() +# + +def update_db(dest, src): + for comp, group in src.items(): + + # DEST already contains this component, update it + if comp in dest: + + # Update tight and loose binding databases + update_db(dest[comp][0], group[0]) + update_db(dest[comp][1], group[1]) + + # If a value has been set in SRC, update + # value in DEST + + if len(group) > 2: + dest[comp] = dest[comp][:2] + group[2:] + + # COMP not in src, make a deep copy + else: + dest[comp] = copy_group(group) + +def copy_group(group): + return (copy_db(group[0]), copy_db(group[1])) + group[2:] + +def copy_db(db): + newdb = {} + for comp, group in db.items(): + newdb[comp] = copy_group(group) + + return newdb + + +# +# Helper functions for output +# + +def output_db(prefix, db): + res = '' + for comp, group in db.items(): + + # There's a value for this component + if len(group) > 2: + res = res + '%s%s: %s\n' % (prefix, comp, output_escape(group[2])) + + # Output tight and loose bindings + res = res + output_db(prefix + comp + '.', group[0]) + res = res + output_db(prefix + comp + '*', group[1]) + + return res + +def output_escape(value): + value = str(value) + if not value: + return value + + for char, esc in (('\\', '\\\\'), + ('\000', '\\000'), + ('\n', '\\n')): + + value = value.replace(char, esc) + + # If first or last character is space or tab, escape them. + if value[0] in ' \t': + value = '\\' + value + if value[-1] in ' \t' and value[-2:-1] != '\\': + value = value[:-1] + '\\' + value[-1] + + return value + + +# +# Option type definitions +# + +class Option(object): + def __init__(self): + pass + + def parse(self, name, db, args): + pass + +class NoArg(Option): + """Value is provided to constructor.""" + def __init__(self, specifier, value): + self.specifier = specifier + self.value = value + + def parse(self, name, db, args): + db.insert(name + self.specifier, self.value) + return args[1:] + +class IsArg(Option): + """Value is the option string itself.""" + def __init__(self, specifier): + self.specifier = specifier + + def parse(self, name, db, args): + db.insert(name + self.specifier, args[0]) + return args[1:] + +class SepArg(Option): + """Value is the next argument.""" + def __init__(self, specifier): + self.specifier = specifier + + def parse(self, name, db, args): + db.insert(name + self.specifier, args[1]) + return args[2:] + +class ResArgClass(Option): + """Resource and value in the next argument.""" + def parse(self, name, db, args): + db.insert_string(args[1]) + return args[2:] + +ResArg = ResArgClass() + +class SkipArgClass(Option): + """Ignore this option and next argument.""" + def parse(self, name, db, args): + return args[2:] + +SkipArg = SkipArgClass() + +class SkipLineClass(Option): + """Ignore rest of the arguments.""" + def parse(self, name, db, args): + return [] + +SkipLine = SkipLineClass() + +class SkipNArgs(Option): + """Ignore this option and the next COUNT arguments.""" + def __init__(self, count): + self.count = count + + def parse(self, name, db, args): + return args[1 + self.count:] + + + +def get_display_opts(options, argv = sys.argv): + """display, name, db, args = get_display_opts(options, [argv]) + + Parse X OPTIONS from ARGV (or sys.argv if not provided). + + Connect to the display specified by a *.display resource if one is + set, or to the default X display otherwise. Extract the + RESOURCE_MANAGER property and insert all resources from ARGV. + + The four return values are: + DISPLAY -- the display object + NAME -- the application name (the filname of ARGV[0]) + DB -- the created resource database + ARGS -- any remaining arguments + """ + + from Xlib import display, Xatom + import os + + name = os.path.splitext(os.path.basename(argv[0]))[0] + + optdb = ResourceDB() + leftargv = optdb.getopt(name, argv[1:], options) + + dname = optdb.get(name + '.display', name + '.Display', None) + d = display.Display(dname) + + rdbstring = d.screen(0).root.get_full_property(Xatom.RESOURCE_MANAGER, + Xatom.STRING) + if rdbstring: + data = rdbstring.value + else: + data = None + + db = ResourceDB(string = data) + db.update(optdb) + + return d, name, db, leftargv + + +# Common X options +stdopts = {'-bg': SepArg('*background'), + '-background': SepArg('*background'), + '-fg': SepArg('*foreground'), + '-foreground': SepArg('*foreground'), + '-fn': SepArg('*font'), + '-font': SepArg('*font'), + '-name': SepArg('.name'), + '-title': SepArg('.title'), + '-synchronous': NoArg('*synchronous', 'on'), + '-xrm': ResArg, + '-display': SepArg('.display'), + '-d': SepArg('.display'), + } + + +# Notes on the implementation: + +# Resource names are split into their components, and each component +# is stored in a mapping. The value for a component is a tuple of two +# or three elements: + +# (tightmapping, loosemapping [, value]) + +# tightmapping contains the next components which are connected with a +# tight binding (.). loosemapping contains the ones connected with +# loose binding (*). If value is present, then this component is the +# last component for some resource which that value. + +# The top level components are stored in the mapping r.db, where r is +# the resource object. + +# Example: Inserting "foo.bar*gazonk: yep" into an otherwise empty +# resource database would give the following structure: + +# { 'foo': ( { 'bar': ( { }, +# { 'gazonk': ( { }, +# { }, +# 'yep') +# } +# ) +# }, +# {}) +# } diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/__init__.py b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__init__.py new file mode 100644 index 0000000..d6c1746 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__init__.py @@ -0,0 +1,26 @@ +# Xlib.support.__init__ -- support code package +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +__all__ = [ + 'lock', + 'connect' + # The platform specific modules should not be listed here + ] diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c0269eba5f94fa00317501e47f7eea584132492 GIT binary patch literal 231 zcmX@j%ge<81O=Z?W!z$BV0aATzyK4J@tFt6n9h*GkiwYG6va@4#(%X)VFmFeeXCg~ScmSp7T8S5Du=@(~~r0NzVCTAz6rxxo+fMknH3kvd!O7!F7 zGxIV_;^XxSDt~d<5An}2jk&*F(9s?`)4Hn)HtSsDYjqF8i GKnVcH+Cg6c literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/connect.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/connect.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5756f2518e025f68725e00c2d2f3ccf4fdb7edc9 GIT binary patch literal 2834 zcmbuB&2JM&6u@`=6~~U9grqHy6b1stuAI0~pag}W$cYMSh!IJv;2x}vcN}l9ciow> zgOOAD&`QmTsuyzTfl574<$|jI740RFk%G3|dg?7odg9dgW_R;}(q34}Z{NJxH}m$* z@4fXOu~3zbVXOoO3t~fIaT-RenZXq^gzz<>H*M$ zt{wutgDOis-g5i*rM`XL)AZoF>gc%$jp)h=805lVM)c4(N-nB*fb7!4AY*zb$aq6d zM*c>J8M`A}rREoRX6;@Z*@-^0Ny+jsJG79Ua>UjP1gta&)rlFaycL2jsQn5#kx(zMmu!^2}bkR#egH*_x_% z-YdSQZz<~8_wP-`djis|YQI9pWa?6+$}C|Ota6H!EG|++H?0)m1xBe!ZjePP^18vR zWv!8L@5xAnz;#z+oRZ1gvv;Q_?i0fl7BK`T1q)8jq^95_gxoIfKfuWh*i)p&sq_~m zN_1M(YGpy(mBC{Utc;2pGf7=5*C;0%qt~4s37MRkxHE;D4-XUcFV@Os&zT?zB*6tU z%*CYK0)o7koy%sj)1HI(vIL@qKu7{(B1VyDHDOiYfD4}It?cX^?&Nu5at>_)nX@=I z7Rn7mD^=0(94BY8(hnWo_abJkvOpP0K$hqtW!|H+nR`=HGtM4fD%{K;>5&ZCG4C|6 z9=Pp?^RdHlI-+Q?irt@gmpS;9MAeQSI7uk54mUK0tk`~B4Ecjt7<4X$^?TwvDEuQ3 zE#;q+O84Ma{Pbr0^v~fJAC9-%W0XVP=)kTA zevw%fqCtJqx?$CzvNV7lwmoo=iR6e=8uy%%nayTCo0?03mr0k2`+nBK60~qAOxemI zLO1kz!YQj$HX=g-wz~3;heV6@!XdF^And+9s`lp{s3I7PV+8-8OdjCqb`(2+MPvJ+ zqe#ryyRaHZ3IH>>9MVqWJ}9Pf7F#Nic1-CW*ovRpjGy}P;fv&0JAUI$(#BWE*UmpZ z{_OJezIOD=M&OFWTM+!cs{<6t+t;AH6>q@=j;w}Pl&}B;U z^94tQs;&vm+0~ez^G&#E|&NL93ZYj_x}pozSyHOl9#E%4t0RZ-aRJ0S%=6l5{af{haJFl zvH>`JHi+VV6sJ&N({pG6!^b^5fo=o$Vv;sht?2wC|}i> z;PQ=}PArQAqxwaW3(L}Z9Ugqe=$}f@c0>urzgyY% z`+7sI*mhVs{=tUQza8?dJ)u??Sl>Ipq4e!r;gOIBi52Yth{ttTTQ5J9h1GU>zPtIhMlxE<~%$tulznOWz%H<_M3Qm5uALao5 z(q%^3sgg8M8G{Bd!G;moOu%6#^|hD=f*no+Tbiwnpq1%o>bflB=kUK|qVy zfYFSiCpkLh#7lfV>UR50-|ASi97?5Xbdu-D#xQ^#l#BF%4S>(HCO2&sgPtj3fIb|s zO)Pflycp-6?+0<-w00v$ia0NYD@-NgoQqI|U1zbbg!^96^R=_LM%N3Cb?NlPn(@Yw ze&B>nGxDsqkj9JVE2Ag8p5Z!MM$ix2zIVTIZ_Q9nDDDQP)iJk)GTxC_MM2=p(4ZoX zpdS}FcRVNLeDBIRw#Ll3g0 z1l%*bf^*y;@A`J+l3wC`H!|JSBTE=7@r!}15Tn#dHA#z^uqrBw>?1hQirHr@xyG`U zG?IcWJaeK=kTF?CHimHSc%Al#D=TuFeiNthE)Y@Ns<2q6U2W2 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/unix_connect.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/unix_connect.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4def218249cf2a5b903410df9f2f45fb5001e6c8 GIT binary patch literal 6879 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 %*Ul~^F!(TeT41EcOfpyxucs5VB=4kJ_uW6C| z*z~}ZYmOIu6FJ(mY4v6<-yfPA%K0V>)?2ftZ9_fLu^lET!n$qIvU(_m2`}+IV*6wZ hQMY}G*iSTUbs>xI4)^W$dkkvmA&P-Ill^=X{a=gyjrjlo literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/vms_connect.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/support/__pycache__/vms_connect.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fd8b38052ecc7e2ccfc704d4cbce91e0097c803 GIT binary patch literal 1770 zcmZ`(%}*Og6rb4-d;PJd7y^iXq-`APCACe`R#Ayde(vE)1e$D~#7g;z&H-+OnSXcuRkYE9%8Z%5myrv3NkxtPNP(TKG9DkN1 z`XOxSQmn*$4N@+N#oR5qFy|Jb;65PcqyQ~eMo2|V!l&W8kxXPM5lIb2-j1ec28H49 zT`bOA62hNE9Z`5UBsMeK`B}_Ky~jbUT>~a4!$oM=Cc^U0Sy~!^eVp1#(1iLqgXFL& z?{cKm`P6$EnxI6PFz-3FI+8@Sa?&QPQxaXG4WDCuMhxS`ICF`4h9}$dU`-bJ+cLLV z6iRZHSd)@~Nt=wx-eV_$;7$tc5;Hs$9ZFiBf+}VTSyeX>g-f&90cj>89XKGm1I953 zF3T(BbghtCOe5K1iy1@ABGOLlxv_>mnJLQSuupv8fzVwVZJ)GpC4I8O26#-Hgr4%6zPl z`z)p{8d+6&BYOEtOwSo|M9YZxGqbWD`-oWeIZacM5t}dSX;D=aSu~>BqUD>FjdZgl zbPjL(A|CoTn3chy7jPZruXa14kGbFu*SE#>t@mzouapyeKL4XY*G?d`6$ouiZwDfE zF0$_nmd6fVz|U8&R<71AuMU^T_Iw??9sMiJV=upwsm@krYnj#jYOFlE%Ll5{mFe1t ztEuw!JvaZTv%7ZZ+vh8;{m$TuYv0#V>#iB=lN$qdU%1YMk8wRfB<**|jRhOpejC~z zV6=drcYNCBHqeusJVR~P_C15N8m%Xjx4)gI)0@EH9gW!nv{TbE{%}g{m+S&u0AJ7_g9Rv1$(+^;Ft{l;xZJVD$a;w9N&~z!eh(P6tYkx#(~xSY zqFO+mxF!_D%!0Z_&u0p4m_^-0?dq*pBSMxM_4RB z1t{#-02D#M8o<9Wl@uro-wu&YYPuvgkFezk!EN zevdNP_jRHkED0WqLNX#%SqyoXjqc;SC~CQaj0hC$XK1&~&Vnuy9SOGgIN{<&Rhlcv zBj^&=5!CBLnBnt6c>Fqm-ai5VH|W{tdsl8(Q +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +import sys +import importlib + +# List the modules which contain the corresponding functions + +_display_mods = { + 'OpenVMS': 'vms_connect', + } + +_default_display_mod = 'unix_connect' + +_socket_mods = { + 'OpenVMS': 'vms_connect' + } + +_default_socket_mod = 'unix_connect' + +_auth_mods = { + 'OpenVMS': 'vms_connect' + } + +_default_auth_mod = 'unix_connect' + + +# Figure out which OS we're using. +# sys.platform is either "OS-ARCH" or just "OS". + +_parts = sys.platform.split('-') +platform = _parts[0] +del _parts + + +def _relative_import(modname): + return importlib.import_module('..' + modname, __name__) + + +def get_display(display): + """dname, protocol, host, dno, screen = get_display(display) + + Parse DISPLAY into its components. If DISPLAY is None, use + the default display. The return values are: + + DNAME -- the full display name (string) + PROTOCOL -- the protocol to use (None if automatic) + HOST -- the host name (string, possibly empty) + DNO -- display number (integer) + SCREEN -- default screen number (integer) + """ + + modname = _display_mods.get(platform, _default_display_mod) + mod = _relative_import(modname) + return mod.get_display(display) + + +def get_socket(dname, protocol, host, dno): + """socket = get_socket(dname, protocol, host, dno) + + Connect to the display specified by DNAME, PROTOCOL, HOST and DNO, which + are the corresponding values from a previous call to get_display(). + + Return SOCKET, a new socket object connected to the X server. + """ + + modname = _socket_mods.get(platform, _default_socket_mod) + mod = _relative_import(modname) + return mod.get_socket(dname, protocol, host, dno) + + +def get_auth(sock, dname, protocol, host, dno): + """auth_name, auth_data = get_auth(sock, dname, protocol, host, dno) + + Return authentication data for the display on the other side of + SOCK, which was opened with DNAME, HOST and DNO, using PROTOCOL. + + Return AUTH_NAME and AUTH_DATA, two strings to be used in the + connection setup request. + """ + + modname = _auth_mods.get(platform, _default_auth_mod) + mod = _relative_import(modname) + return mod.get_auth(sock, dname, protocol, host, dno) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/lock.py b/CLI/venv/lib/python3.12/site-packages/Xlib/support/lock.py new file mode 100644 index 0000000..29289b6 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/support/lock.py @@ -0,0 +1,44 @@ +# Xlib.support.lock -- allocate a lock +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +class _DummyLock(object): + def __init__(self): + + # This might be nerdy, but by assigning methods like this + # instead of defining them all, we create a single bound + # method object once instead of one each time one of the + # methods is called. + + # This gives some speed improvements which should reduce the + # impact of the threading infrastructure in the regular code, + # when not using threading. + + self.acquire = self.release = self.locked = self.__noop + + def __noop(self, *args): + return + + +# More optimisations: we use a single lock for all lock instances +_dummy_lock = _DummyLock() + +def allocate_lock(): + return _dummy_lock diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/unix_connect.py b/CLI/venv/lib/python3.12/site-packages/Xlib/support/unix_connect.py new file mode 100644 index 0000000..aee6dd9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/support/unix_connect.py @@ -0,0 +1,217 @@ +# Xlib.support.unix_connect -- Unix-type display connection functions +# +# Copyright (C) 2000,2002 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +import re +import os +import platform +import socket +from Xlib import error, xauth + + +SUPPORTED_PROTOCOLS = (None, 'tcp', 'unix') + +# Darwin funky socket. +uname = platform.uname() +if (uname[0] == 'Darwin') and ([int(x) for x in uname[2].split('.')] >= [9, 0]): + SUPPORTED_PROTOCOLS += ('darwin',) + DARWIN_DISPLAY_RE = re.compile(r'^/private/tmp/[-:a-zA-Z0-9._]*:(?P[0-9]+)(\.(?P[0-9]+))?$') + +DISPLAY_RE = re.compile(r'^((?Ptcp|unix)/)?(?P[-:a-zA-Z0-9._]*):(?P[0-9]+)(\.(?P[0-9]+))?$') + + +def get_display(display): + # Use $DISPLAY if display isn't provided + if display is None: + display = os.environ.get('DISPLAY', '') + + re_list = [(DISPLAY_RE, {})] + + if 'darwin' in SUPPORTED_PROTOCOLS: + re_list.insert(0, (DARWIN_DISPLAY_RE, {'protocol': 'darwin'})) + + for re, defaults in re_list: + m = re.match(display) + if m is not None: + protocol, host, dno, screen = [ + m.groupdict().get(field, defaults.get(field)) + for field in ('proto', 'host', 'dno', 'screen') + ] + break + else: + raise error.DisplayNameError(display) + + if protocol == 'tcp' and not host: + # Host is mandatory when protocol is TCP. + raise error.DisplayNameError(display) + + dno = int(dno) + if screen: + screen = int(screen) + else: + screen = 0 + + return display, protocol, host, dno, screen + + +def _get_tcp_socket(host, dno): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((host, 6000 + dno)) + return s + + +def _get_unix_socket(address): + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(address) + return s + + +def get_socket(dname, protocol, host, dno): + assert protocol in SUPPORTED_PROTOCOLS + try: + # Darwin funky socket. + if protocol == 'darwin': + s = _get_unix_socket(dname) + + # TCP socket, note the special case: `unix:0.0` is equivalent to `:0.0`. + elif (protocol is None or protocol != 'unix') and host and host != 'unix': + s = _get_tcp_socket(host, dno) + + # Unix socket. + else: + address = '/tmp/.X11-unix/X%d' % dno + if not os.path.exists(address): + # Use abstract address. + address = '\0' + address + try: + s = _get_unix_socket(address) + except socket.error: + if not protocol and not host: + # If no protocol/host was specified, fallback to TCP. + s = _get_tcp_socket(host, dno) + else: + raise + except socket.error as val: + raise error.DisplayConnectionError(dname, str(val)) + + # Make sure that the connection isn't inherited in child processes. + _ensure_not_inheritable(s) + + return s + + +def _ensure_not_inheritable(sock): + # According to PEP446, in Python 3.4 and above, + # it is not inherited in child processes by default. + # However, just in case, we explicitly make it non-inheritable. + # Also, we don't use the code like the following, + # because there would be no possibility of backporting to past versions. + # if sys.version_info.major == 3 and sys.version_info.minor >= 4: + # sock.set_inheritable(False) + # return + # We just check if the socket has `set_inheritable`. + if hasattr(sock, 'set_inheritable'): + sock.set_inheritable(False) + return + + # On Windows, + # Python doesn't support fcntl module because Windows doesn't have fcntl API. + # At least by not importing fcntl, we will be able to import python-xlib on Windows. + if platform.system() == 'Windows': + # so.. unfortunately, for Python 3.3 and below, on Windows, + # we can't make sure that the connection isn't inherited in child processes for now. + return + + import fcntl + fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC) + + +def new_get_auth(sock, dname, protocol, host, dno): + assert protocol in SUPPORTED_PROTOCOLS + # Translate socket address into the xauth domain + if protocol == 'darwin': + family = xauth.FamilyLocal + addr = socket.gethostname() + + elif protocol == 'tcp': + family = xauth.FamilyInternet + + # Convert the prettyprinted IP number into 4-octet string. + # Sometimes these modules are too damn smart... + octets = sock.getpeername()[0].split('.') + addr = bytearray(int(x) for x in octets) + else: + family = xauth.FamilyLocal + addr = socket.gethostname().encode() + + try: + au = xauth.Xauthority() + except error.XauthError: + return b'', b'' + + while 1: + try: + return au.get_best_auth(family, addr, dno) + except error.XNoAuthError: + pass + + # We need to do this to handle ssh's X forwarding. It sets + # $DISPLAY to localhost:10, but stores the xauth cookie as if + # DISPLAY was :10. Hence, if localhost and not found, try + # again as a Unix socket. + if family == xauth.FamilyInternet and addr == b'\x7f\x00\x00\x01': + family = xauth.FamilyLocal + addr = socket.gethostname().encode() + else: + return b'', b'' + + +def old_get_auth(sock, dname, host, dno): + # Find authorization cookie + auth_name = auth_data = b'' + + try: + # We could parse .Xauthority, but xauth is simpler + # although more inefficient + data = os.popen('xauth list %s 2>/dev/null' % dname).read() + + # If there's a cookie, it is of the format + # DISPLAY SCHEME COOKIE + # We're interested in the two last parts for the + # connection establishment + lines = data.split('\n') + if len(lines) >= 1: + parts = lines[0].split(None, 2) + if len(parts) == 3: + auth_name = parts[1] + hexauth = parts[2] + auth = b'' + + # Translate hexcode into binary + for i in range(0, len(hexauth), 2): + auth = auth + chr(int(hexauth[i:i+2], 16)) + + auth_data = auth + except os.error: + pass + + return auth_name, auth_data + +get_auth = new_get_auth diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/support/vms_connect.py b/CLI/venv/lib/python3.12/site-packages/Xlib/support/vms_connect.py new file mode 100644 index 0000000..2799bfa --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/support/vms_connect.py @@ -0,0 +1,74 @@ +# Xlib.support.vms_connect -- VMS-type display connection functions +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +import re +import socket + +from Xlib import error + +display_re = re.compile(r'^([-a-zA-Z0-9._]*):([0-9]+)(\.([0-9]+))?$') + +def get_display(display): + + # Use dummy display if none is set. We really should + # check DECW$DISPLAY instead, but that has to wait + + if display is None: + return ':0.0', None, 'localhost', 0, 0 + + m = display_re.match(display) + if not m: + raise error.DisplayNameError(display) + + name = display + + # Always return a host, since we don't have AF_UNIX sockets + host = m.group(1) + if not host: + host = 'localhost' + + dno = int(m.group(2)) + screen = m.group(4) + if screen: + screen = int(screen) + else: + screen = 0 + + return name, None, host, dno, screen + + +def get_socket(dname, protocol, host, dno): + try: + # Always use TCP/IP sockets. Later it would be nice to + # be able to use DECNET och LOCAL connections. + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((host, 6000 + dno)) + + except socket.error as val: + raise error.DisplayConnectionError(dname, str(val)) + + return s + + +def get_auth(sock, dname, host, dno): + # VMS doesn't have xauth + return '', '' diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/threaded.py b/CLI/venv/lib/python3.12/site-packages/Xlib/threaded.py new file mode 100644 index 0000000..5fdf016 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/threaded.py @@ -0,0 +1,28 @@ +# Xlib.threaded -- Import this module to enable threading +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from six.moves import _thread + +# We change the allocate_lock function in Xlib.support.lock to +# return a basic Python lock, instead of the default dummy lock + +from Xlib.support import lock +lock.allocate_lock = _thread.allocate_lock diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xauth.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xauth.py new file mode 100644 index 0000000..8651448 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xauth.py @@ -0,0 +1,134 @@ +# Xlib.xauth -- ~/.Xauthority access +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +import os +import struct + +from Xlib import X, error + +FamilyInternet = X.FamilyInternet +FamilyDECnet = X.FamilyDECnet +FamilyChaos = X.FamilyChaos +FamilyServerInterpreted = X.FamilyServerInterpreted +FamilyInternetV6 = X.FamilyInternetV6 +FamilyLocal = 256 + +class Xauthority(object): + def __init__(self, filename = None): + if filename is None: + filename = os.environ.get('XAUTHORITY') + + if filename is None: + try: + filename = os.path.join(os.environ['HOME'], '.Xauthority') + except KeyError: + raise error.XauthError( + '$HOME not set, cannot find ~/.Xauthority') + + try: + with open(filename, 'rb') as fp: + raw = fp.read() + except IOError as err: + raise error.XauthError('could not read from {0}: {1}'.format(filename, err)) + + self.entries = [] + + # entry format (all shorts in big-endian) + # short family; + # short addrlen; + # char addr[addrlen]; + # short numlen; + # char num[numlen]; + # short namelen; + # char name[namelen]; + # short datalen; + # char data[datalen]; + + n = 0 + try: + while n < len(raw): + family, = struct.unpack('>H', raw[n:n+2]) + n = n + 2 + + length, = struct.unpack('>H', raw[n:n+2]) + n = n + length + 2 + addr = raw[n - length : n] + + length, = struct.unpack('>H', raw[n:n+2]) + n = n + length + 2 + num = raw[n - length : n] + + length, = struct.unpack('>H', raw[n:n+2]) + n = n + length + 2 + name = raw[n - length : n] + + length, = struct.unpack('>H', raw[n:n+2]) + n = n + length + 2 + data = raw[n - length : n] + + if len(data) != length: + break + + self.entries.append((family, addr, num, name, data)) + except struct.error: + print("Xlib.xauth: warning, failed to parse part of xauthority file {0}, aborting all further parsing".format(filename)) + + if len(self.entries) == 0: + print("Xlib.xauth: warning, no xauthority details available") + # raise an error? this should get partially caught by the XNoAuthError in get_best_auth.. + + def __len__(self): + return len(self.entries) + + def __getitem__(self, i): + return self.entries[i] + + def get_best_auth(self, family, address, dispno, + types = ( b"MIT-MAGIC-COOKIE-1", )): + + """Find an authentication entry matching FAMILY, ADDRESS and + DISPNO. + + The name of the auth scheme must match one of the names in + TYPES. If several entries match, the first scheme in TYPES + will be choosen. + + If an entry is found, the tuple (name, data) is returned, + otherwise XNoAuthError is raised. + """ + + num = str(dispno).encode() + + matches = {} + + for efam, eaddr, enum, ename, edata in self.entries: + if enum == b'' and ename not in matches: + enum = num + if efam == family and eaddr == address and num == enum: + matches[ename] = edata + + for t in types: + try: + return (t, matches[t]) + except KeyError: + pass + + raise error.XNoAuthError((family, address, dispno)) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__init__.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__init__.py new file mode 100644 index 0000000..6fb3bc9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__init__.py @@ -0,0 +1,29 @@ +# Xlib.xobject.__init__ -- glue for Xlib.xobject package +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +__all__ = [ + 'colormap', + 'cursor', + 'drawable', + 'fontable', + 'icccm', + 'resource', + ] diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..442f23a52d4b7485e3248169522d6330350762e8 GIT binary patch literal 265 zcmXw#u};G<5QgnmBo@#Ii3GJMD`J5KsbXS4T`b2r8iQk77blRBr(kE}Rp1T0GO?j{ z>qLy;lTP}6{ln?*V>a6-BYyK#t897wrRs|#Ty&=CF&j){6?em zIxJ;pRSn25mRGz7+jFB!?uSr2dpbW^@Ky&n_EJ5_HMIOTwNI|R2Nk#w+Ug+0+z&f; c*0`!OaE|E+I!>G9drB$Y9OVbubB^f)Klg-Cq5uE@ literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/colormap.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/colormap.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ba0e4a3f1e93ab60239be6463d19cebf45d0b89 GIT binary patch literal 6719 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/cursor.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/cursor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cf5a683b0a00af4679a95ef3ee6995413d6af9f GIT binary patch literal 1472 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 YM+O#obilLG*h;s!tn4xx`2i{a58(^R#sB~S literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/fontable.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/fontable.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9079a4c2c27c0f8ae54e0097203ee968e43dcdb2 GIT binary patch literal 4636 zcmds4O>7&-6`tk(aF-HE*>o)VCoW}6k!bzUw3Rr5)u4e?DQQ&|aeN4bpe(h!q9{{b zWp-tW0#)eXgM4xd6i|J#bg3*jfZ9`0pg`~Kr9@h2yJ&#`MGv_Nq3lC|0)200S0Y(C z1%&p}0r}?5%$u3F-@KohKSZMu0%h^5-_QNCjgY@%BPg=Z)P4fYCNYR16v=`xEeOO2 z8DcTCAWn;nmw=b1C4q#<1To}?#86Ceo~;}##_Q)Iucs9z83sw!RE~PXtXG5HNL{a5 zZb`L%i4#+T7pCSXOQ!97De$&RP1{7zC>+{>U`I+$CU*SWN3QeU#Uf3wui^W{olV(Aaltgh~Py1lWq-E5NBJ^IUU;rqR zZ5C&3R3`cLbb6uWq{nFCfq651uRyKEf-{+0D(Q13O^;5#pMGGL9;Azfne<}WnX^i_ z1~WI)cEK?R7IXUjT;8fn?csT0{hxmfvl6i z#?SA^lht_g+0fp|?ugslzZc#OABsX-=70!VrUp_(ug3}vkRdt^%zqQniU646%1}6_ zB7=;!K!>N;4lR`O0jzBd)_dlP^W7E4EIBq8je=+@L}O6V1P~iFPbO&`D(@`&_^bny zvhc@QtCt#)X&6L=>~0`FOg+_j&o8@v-T$k8H+^ewd3V{(+&+{;ZNmp7qz%(EAUT!N zJT;pw>bq3e`> zh(0KQCx#6XY87e;Y7J@`>Il>d)GcKprFx->(WwSwLdU}6t^J58a4Po{PIk~r2+YZM zXMvQNlSq)xjiL8MNhhKmTeoYG#Qwc zqO&Qh+QjG}XZv8-z6JygM~&~R9aXhsYiMU=d&IqV-Mw=4Y5qyx?d*OT7PTIBrn;{u zOd%u;f84-7lv80MR=x=pKZgXU$oyNAuqU_~)w6(#V%QGW(n8L@AAqBbT8rfdXe16z z4@{*gB)Eu;Ujy*?ZYSw5Yc-7M0CN)sx_~fj9>*TVw$ANb-oEU1_PWV8++^2IcsmRj zz0@SF>wg8#i4h$jLz8(mIJ6Vg_F9abJ(sm+XKm8~n4n=ES&#Oi>5Q?SI`iQec?zFG z2Vs$uV2Z$cS-#wA6u>%e4kKi51d#2k7pm%ot+AcS?Mb(*&;8c5r^`>4-QGd>S_(ny zSUcDANp*w~>4s$z>#% zw|P>4sgDBo9nK!=${<29b(#OzR zQ`W+3YDH$ewia1y0Uraw<}!~no62*)z1HgB(Xn#UOXK7fE3MFf!fOe$SVgQTm2gF^ zXq8B%1!6@jU!BDYf2aCt9&v9fM#%AJ5i*b8-c*9u&ssD@D$!TzXo#Olb$5CheU?3g zM7?0ZWrIBu+0DUg;f*X@p{S?fwS%+jtVJ=%7+!>Nc?cjSPh7J+7QVG5TRpUJU9!h*4$t02=Aeln)LnIh7 zJW(&&Hl6^>W=Dj-X%ae9Gn+>}v;3*O+QA*+-$(GtX8#PxI{D)IP*v^OP(Qu?^MYH) ze-S(TxcI2JA4^wb>Ca=C4Ut`8>r!BEpWBz-yS;ncO%1p=?zn@uc^0f^UbMGp!v_~h zJi!+msKy4K&HYySUGz86&tu~o;$PxtKONc}`RT}3;#uxb@f&|sZ}9l}4rrIs{zG7g zC)OQc(2qe5LI$xhcpZp>AiU@&!qtC} r^M51f4yA}Nys^U7Iwa6Iyx1+IH#!apREKwk*M-c++b;-IOvQfz)pmW( literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/icccm.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/icccm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a917a136e64d7509430f2572a6c0a197708afde GIT binary patch literal 2902 zcmb`JPfXiZ9LH@Zad1Ky$w>GU2!(c3(I{5K#-DEM)OFK9<4=K&glG~nwjqzkcIr6% zS+$AX;8f5K1ntmlmr*fk969d1olqhXJ!w*NDSM@IE=%Sn1IJ|frt~hs)?jcu*dBs zRf}Xg>vzrGc+sXR&US=fLD)^=h|tNn^U^HMI#qq;9A*s7)9j}T;m8YwRi#c2`@X@f z;cxq)>Y`kAQSQ2^#=0m^4b@WBzA@#RcqjJ?>e8kgv@Wfv-@?Wd< z9VqlRj5HnRJS0l`tWzp9$@vyXto6T4K_?5z?*AjhOCrWrWHov&()tIbOTlr7gJzEU{Z!ao}9D}No{4rxNkyA(*l!z z2pe?-#g{TE=+MGJyShFV4nTV>36^B_Wh-kbJgOc@$&wuPD!%BB*%cLq@it&S71{VC<#tx*2Ous7wFar zLyV(J0ILh~f!-S#)!TALC-pe?sp+W?Ad))gicYF-bKo=n8CFI$VlSe!AS(3xGFamy z^v6J!Qb3ttG9sJcW%~ZaIK9S;Ycy((PHid)NgN!w9ih`e;culF_93&vr)jlydPCA0 zp#jUX!a!>CMZ?>I#ATBFU3nPgQU5BWzeW37vf()XM?Z#l{DO5pr+nMKC+$1!yJNfW z?T_t^Wk309Iv2~$ei!>DcDRy%Z75HTY?05K+joh5YLCi}W+P8W4@Ps*eDGE=*n`y2 z!BDRE>pR8ZbtFa(MsgpW+%5#)spyH5dxhZLivG9jH;mMu9uNIEUkFYVgS8g3hL>|r zp3D@2?^bHib-CT+?b`B`LYTW{yZ1?WC%n6`JG;NIw~$@W`)?NgAyXaq6#Q=#{XwMX z_vW+HhchJ?)_vnF6gdq=ilOUgA^J2#|1~K&h^|P9#BTPV^$nl)4gc2_xal+AQetF;no5RQ$g<@fQ4Vm3zGI)-7kLuhP%FQSpbl z8LhfY>Mh%Bfx%KkrO35I?+<}zf!yP~f3QqBw9w61Q|tEZlZBmyER`jmQU_G-^?chv bv8~5Y{rNV!qW;-h*-bWeeCd+kL}&F+?ml2! literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/resource.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/__pycache__/resource.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0386907f902e7f9c8c3b9e57cff0f59c5af441f6 GIT binary patch literal 2060 zcma)7O>7%Q6rR~1dt)bYo79*lAvJ`UIHcLoASHsTQYb${L^+TikQHg=?rxJ!oLy&j z6UXUF^pHa;KqTVeA}W!bqAEQjIB|!IgOF;iI3U4=8%kOZy}*0BUgH>p7-`?kym@ct zz3=_(_g!5v0;72H-O`^CLVm$bIK=wmGy{tY(TGM1WR>P9B^-H&Xxui@c%3`q1GyYu z7P8`RxXDs4%Jj8$-FDRAFrZw0bNU)ADnutas*xP0b!c>(=6Jj@CulrSQ4@ehG!bZ2 zivX3hm?nW#M>(2}d(!*5ZLKp^SB0hr@P4%Bblkt+r7lq#$1Vpu8g5-4cA-6_Odim= zEbm1%!!8!`Wsfs7Pqa#=&a#3h*m~g>lR(wunV~U+%*J=qFrMb*Rnw8*WX6VmMZRG$ zt7tg0`E^rW(wTgH_FZ{HH#g*haZ@gqoh8eh9Dn7CY#WY#xtLd1@{77He}Jc(*3D&I zb!1leY`j?ZBtv2^P$7zA?qSqkpgmu)KY^x!pEJpo+M1sTC#6P_#}1;M?`Hn z3>#eg@btl=LR_*8bL*HVEDF3VWgRd*pezoPjjCzZ1=QWJA$L??u}QEOHCl#C+i_P$2w@jN1CqLR zfJPfGYRr=|bI}=qPnG~c&Ii!rA-XoY zlCHxTQ51a*08BIih>Yh!#(oRP9r9B=xvSov{xSX{g6Q6L@7Z78{`~e2iP2iBzf#&O z?GGJh4l>87k?OgTpHlP$Gw?qXXc-vqYXaj-LSwUa4EXd3C{b0 ze?V9gO=z*z)LU#t#wZHnJrL&J)V;~Q*LOawN`t|pjcCF-KIlI>28%P1Cd>8s!a-w% z7>BvYdAwmdKA!A6NHwP;l*m%vUTP_kfOQ#V&jA4}6Fs}HR;Ko*K60y4|9@CG3*yl1 zpmnsXj&|0z&&ylf7G&8xfehJ-Umdp76Pv>m)0@|z%XBD;TFBeBqF{lW`Bi}OU!7xm zk+nD%uqM#CwC`LkF|aQjb{}*3f9r@p@MZR(p;_0r67Vx}t1_|DFqsXWY4KOPIP zXpYDK_Ya$EyE=ME!yf{LwhG>7`Ji=1E$F7qVxAQCiLAiT2ru@YQ7Bw57&^olyR45z zHYgl61dKDu7+(Qt01(BuE;OpAi93lZX&?}GDe*|^JC^$PZyYWhEYya_YMIf)#e>B^ zM6N^jk%3N!DHwFU7(+cTrYNhHwqAh1V82^i&ll=p!faX+g|n|dm97R3Tw^c8i&%^HGeCalDWy-w2z}wPFi7Q{jVA;q H-`c+bEsd8* literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/colormap.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/colormap.py new file mode 100644 index 0000000..8ba2fce --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/colormap.py @@ -0,0 +1,141 @@ +# Xlib.xobject.colormap -- colormap object +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib import error +from Xlib.protocol import request + +from . import resource + +import re + +rgb_res = [ + re.compile(r'\Argb:([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})/([0-9a-fA-F]{1,4})\Z'), + re.compile(r'\A#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\Z'), + re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])\Z'), + re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])\Z'), + re.compile(r'\A#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])\Z'), + ] + +class Colormap(resource.Resource): + __colormap__ = resource.Resource.__resource__ + + def free(self, onerror = None): + request.FreeColormap(display = self.display, + onerror = onerror, + cmap = self.id) + + self.display.free_resource_id(self.id) + + def copy_colormap_and_free(self, scr_cmap): + mid = self.display.allocate_resource_id() + request.CopyColormapAndFree(display = self.display, + mid = mid, + src_cmap = src_cmap) + + cls = self.display.get_resource_class('colormap', Colormap) + return cls(self.display, mid, owner = 1) + + def install_colormap(self, onerror = None): + request.InstallColormap(display = self.display, + onerror = onerror, + cmap = self.id) + + def uninstall_colormap(self, onerror = None): + request.UninstallColormap(display = self.display, + onerror = onerror, + cmap = self.id) + + def alloc_color(self, red, green, blue): + return request.AllocColor(display = self.display, + cmap = self.id, + red = red, + green = green, + blue = blue) + + def alloc_named_color(self, name): + for r in rgb_res: + m = r.match(name) + if m: + rs = m.group(1) + r = int(rs + '0' * (4 - len(rs)), 16) + + gs = m.group(2) + g = int(gs + '0' * (4 - len(gs)), 16) + + bs = m.group(3) + b = int(bs + '0' * (4 - len(bs)), 16) + + return self.alloc_color(r, g, b) + + try: + return request.AllocNamedColor(display = self.display, + cmap = self.id, + name = name) + except error.BadName: + return None + + def alloc_color_cells(self, contiguous, colors, planes): + return request.AllocColorCells(display = self.display, + contiguous = contiguous, + cmap = self.id, + colors = colors, + planes = planes) + + def alloc_color_planes(self, contiguous, colors, red, green, blue): + return request.AllocColorPlanes(display = self.display, + contiguous = contiguous, + cmap = self.id, + colors = colors, + red = red, + green = green, + blue = blue) + + def free_colors(self, pixels, plane_mask, onerror = None): + request.FreeColors(display = self.display, + onerror = onerror, + cmap = self.id, + plane_mask = plane_mask, + pixels = pixels) + + def store_colors(self, items, onerror = None): + request.StoreColors(display = self.display, + onerror = onerror, + cmap = self.id, + items = items) + + def store_named_color(self, name, pixel, flags, onerror = None): + request.StoreNamedColor(display = self.display, + onerror = onerror, + flags = flags, + cmap = self.id, + pixel = pixel, + name = name) + + def query_colors(self, pixels): + r = request.QueryColors(display = self.display, + cmap = self.id, + pixels = pixels) + return r.colors + + def lookup_color(self, name): + return request.LookupColor(display = self.display, + cmap = self.id, + name = name) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/cursor.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/cursor.py new file mode 100644 index 0000000..2d49bbb --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/cursor.py @@ -0,0 +1,47 @@ +# Xlib.xobject.cursor -- cursor object +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib.protocol import request + +from . import resource + +class Cursor(resource.Resource): + __cursor__ = resource.Resource.__resource__ + + def free(self, onerror = None): + request.FreeCursor(display = self.display, + onerror = onerror, + cursor = self.id) + self.display.free_resource_id(self.id) + + def recolor(self, foreground, background, onerror=None): + fore_red, fore_green, fore_blue = foreground + back_red, back_green, back_blue = background + + request.RecolorCursor(display = self.display, + onerror = onerror, + cursor = self.id, + fore_red = fore_red, + fore_green = fore_green, + fore_blue = fore_blue, + back_red = back_red, + back_green = back_green, + back_blue = back_blue) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/drawable.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/drawable.py new file mode 100644 index 0000000..c47b91b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/drawable.py @@ -0,0 +1,835 @@ +# Xlib.xobject.drawable -- drawable objects (window and pixmap) +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib import X, Xatom +from Xlib.protocol import request, rq + +# Other X resource objects +from . import resource +from . import colormap +from . import cursor +from . import fontable + +# Inter-client communication conventions +from . import icccm + +class Drawable(resource.Resource): + __drawable__ = resource.Resource.__resource__ + + def get_geometry(self): + return request.GetGeometry(display = self.display, + drawable = self) + + def create_pixmap(self, width, height, depth): + pid = self.display.allocate_resource_id() + request.CreatePixmap(display = self.display, + depth = depth, + pid = pid, + drawable = self.id, + width = width, + height = height) + + cls = self.display.get_resource_class('pixmap', Pixmap) + return cls(self.display, pid, owner = 1) + + def create_gc(self, **keys): + cid = self.display.allocate_resource_id() + request.CreateGC(display = self.display, + cid = cid, + drawable = self.id, + attrs = keys) + + cls = self.display.get_resource_class('gc', fontable.GC) + return cls(self.display, cid, owner = 1) + + def copy_area(self, gc, src_drawable, src_x, src_y, width, height, dst_x, dst_y, onerror = None): + request.CopyArea(display = self.display, + onerror = onerror, + src_drawable = src_drawable, + dst_drawable = self.id, + gc = gc, + src_x = src_x, + src_y = src_y, + dst_x = dst_x, + dst_y = dst_y, + width = width, + height = height) + + def copy_plane(self, gc, src_drawable, src_x, src_y, width, height, + dst_x, dst_y, bit_plane, onerror = None): + request.CopyPlane(display = self.display, + onerror = onerror, + src_drawable = src_drawable, + dst_drawable = self.id, + gc = gc, + src_x = src_x, + src_y = src_y, + dst_x = dst_x, + dst_y = dst_y, + width = width, + height = height, + bit_plane = bit_plane) + + def poly_point(self, gc, coord_mode, points, onerror = None): + request.PolyPoint(display = self.display, + onerror = onerror, + coord_mode = coord_mode, + drawable = self.id, + gc = gc, + points = points) + + def point(self, gc, x, y, onerror = None): + request.PolyPoint(display = self.display, + onerror = onerror, + coord_mode = X.CoordModeOrigin, + drawable = self.id, + gc = gc, + points = [(x, y)]) + + def poly_line(self, gc, coord_mode, points, onerror = None): + request.PolyLine(display = self.display, + onerror = onerror, + coord_mode = coord_mode, + drawable = self.id, + gc = gc, + points = points) + + def line(self, gc, x1, y1, x2, y2, onerror = None): + request.PolySegment(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + segments = [(x1, y1, x2, y2)]) + + def poly_segment(self, gc, segments, onerror = None): + request.PolySegment(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + segments = segments) + + def poly_rectangle(self, gc, rectangles, onerror = None): + request.PolyRectangle(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + rectangles = rectangles) + + def rectangle(self, gc, x, y, width, height, onerror = None): + request.PolyRectangle(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + rectangles = [(x, y, width, height)]) + + + def poly_arc(self, gc, arcs, onerror = None): + request.PolyArc(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + arcs = arcs) + + def arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): + request.PolyArc(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + arcs = [(x, y, width, height, angle1, angle2)]) + + def fill_poly(self, gc, shape, coord_mode, points, onerror = None): + request.FillPoly(display = self.display, + onerror = onerror, + shape = shape, + coord_mode = coord_mode, + drawable = self.id, + gc = gc, + points = points) + + def poly_fill_rectangle(self, gc, rectangles, onerror = None): + request.PolyFillRectangle(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + rectangles = rectangles) + + def fill_rectangle(self, gc, x, y, width, height, onerror = None): + request.PolyFillRectangle(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + rectangles = [(x, y, width, height)]) + + def poly_fill_arc(self, gc, arcs, onerror = None): + request.PolyFillArc(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + arcs = arcs) + + def fill_arc(self, gc, x, y, width, height, angle1, angle2, onerror = None): + request.PolyFillArc(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + arcs = [(x, y, width, height, angle1, angle2)]) + + + def put_image(self, gc, x, y, width, height, format, + depth, left_pad, data, onerror = None): + request.PutImage(display = self.display, + onerror = onerror, + format = format, + drawable = self.id, + gc = gc, + width = width, + height = height, + dst_x = x, + dst_y = y, + left_pad = left_pad, + depth = depth, + data = data) + + # Trivial little method for putting PIL images. Will break on anything + # but depth 1 or 24... + def put_pil_image(self, gc, x, y, image, onerror = None): + width, height = image.size + if image.mode == '1': + format = X.XYBitmap + depth = 1 + if self.display.info.bitmap_format_bit_order == 0: + rawmode = '1;R' + else: + rawmode = '1' + pad = self.display.info.bitmap_format_scanline_pad + stride = roundup(width, pad) >> 3 + elif image.mode == 'RGB': + format = X.ZPixmap + depth = 24 + if self.display.info.image_byte_order == 0: + rawmode = 'BGRX' + else: + rawmode = 'RGBX' + pad = self.display.info.bitmap_format_scanline_pad + unit = self.display.info.bitmap_format_scanline_unit + stride = roundup(width * unit, pad) >> 3 + else: + raise ValueError('Unknown data format') + + maxlen = (self.display.info.max_request_length << 2) \ + - request.PutImage._request.static_size + split = maxlen // stride + + x1 = 0 + x2 = width + y1 = 0 + + while y1 < height: + h = min(height, split) + if h < height: + subimage = image.crop((x1, y1, x2, y1 + h)) + else: + subimage = image + w, h = subimage.size + data = subimage.tobytes("raw", rawmode, stride, 0) + self.put_image(gc, x, y, w, h, format, depth, 0, data) + y1 = y1 + h + y = y + h + + + def get_image(self, x, y, width, height, format, plane_mask): + return request.GetImage(display = self.display, + format = format, + drawable = self.id, + x = x, + y = y, + width = width, + height = height, + plane_mask = plane_mask) + + def draw_text(self, gc, x, y, text, onerror = None): + request.PolyText8(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + x = x, + y = y, + items = [text]) + + def poly_text(self, gc, x, y, items, onerror = None): + request.PolyText8(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + x = x, + y = y, + items = items) + + def poly_text_16(self, gc, x, y, items, onerror = None): + request.PolyText16(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + x = x, + y = y, + items = items) + + def image_text(self, gc, x, y, string, onerror = None): + request.ImageText8(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + x = x, + y = y, + string = string) + + def image_text_16(self, gc, x, y, string, onerror = None): + request.ImageText16(display = self.display, + onerror = onerror, + drawable = self.id, + gc = gc, + x = x, + y = y, + string = string) + + def query_best_size(self, item_class, width, height): + return request.QueryBestSize(display = self.display, + item_class = item_class, + drawable = self.id, + width = width, + height = height) + +class Window(Drawable): + __window__ = resource.Resource.__resource__ + + _STRING_ENCODING = 'ISO-8859-1' + _UTF8_STRING_ENCODING = 'UTF-8' + + def create_window(self, x, y, width, height, border_width, depth, + window_class = X.CopyFromParent, + visual = X.CopyFromParent, + onerror = None, + **keys): + + wid = self.display.allocate_resource_id() + request.CreateWindow(display = self.display, + onerror = onerror, + depth = depth, + wid = wid, + parent = self.id, + x = x, + y = y, + width = width, + height = height, + border_width = border_width, + window_class = window_class, + visual = visual, + attrs = keys) + + cls = self.display.get_resource_class('window', Window) + return cls(self.display, wid, owner = 1) + + def change_attributes(self, onerror = None, **keys): + request.ChangeWindowAttributes(display = self.display, + onerror = onerror, + window = self.id, + attrs = keys) + + def get_attributes(self): + return request.GetWindowAttributes(display = self.display, + window = self.id) + + def destroy(self, onerror = None): + request.DestroyWindow(display = self.display, + onerror = onerror, + window = self.id) + + self.display.free_resource_id(self.id) + + def destroy_sub_windows(self, onerror = None): + request.DestroySubWindows(display = self.display, + onerror = onerror, + window = self.id) + + + def change_save_set(self, mode, onerror = None): + request.ChangeSaveSet(display = self.display, + onerror = onerror, + mode = mode, + window = self.id) + + def reparent(self, parent, x, y, onerror = None): + request.ReparentWindow(display = self.display, + onerror = onerror, + window = self.id, + parent = parent, + x = x, + y = y) + + def map(self, onerror = None): + request.MapWindow(display = self.display, + onerror = onerror, + window = self.id) + + def map_sub_windows(self, onerror = None): + request.MapSubwindows(display = self.display, + onerror = onerror, + window = self.id) + + def unmap(self, onerror = None): + request.UnmapWindow(display = self.display, + onerror = onerror, + window = self.id) + + def unmap_sub_windows(self, onerror = None): + request.UnmapSubwindows(display = self.display, + onerror = onerror, + window = self.id) + + def configure(self, onerror = None, **keys): + request.ConfigureWindow(display = self.display, + onerror = onerror, + window = self.id, + attrs = keys) + + def circulate(self, direction, onerror = None): + request.CirculateWindow(display = self.display, + onerror = onerror, + direction = direction, + window = self.id) + + def raise_window(self, onerror = None): + """alias for raising the window to the top - as in XRaiseWindow""" + self.configure(onerror, stack_mode = X.Above) + + def query_tree(self): + return request.QueryTree(display = self.display, + window = self.id) + + def change_property(self, property, property_type, format, data, + mode = X.PropModeReplace, onerror = None): + + request.ChangeProperty(display = self.display, + onerror = onerror, + mode = mode, + window = self.id, + property = property, + type = property_type, + data = (format, data)) + + def change_text_property(self, property, property_type, data, + mode = X.PropModeReplace, onerror = None): + if not isinstance(data, bytes): + if property_type == Xatom.STRING: + data = data.encode(self._STRING_ENCODING) + elif property_type == self.display.get_atom('UTF8_STRING'): + data = data.encode(self._UTF8_STRING_ENCODING) + self.change_property(property, property_type, 8, data, + mode=mode, onerror=onerror) + + def delete_property(self, property, onerror = None): + request.DeleteProperty(display = self.display, + onerror = onerror, + window = self.id, + property = property) + + def get_property(self, property, property_type, offset, length, delete = False): + r = request.GetProperty(display = self.display, + delete = delete, + window = self.id, + property = property, + type = property_type, + long_offset = offset, + long_length = length) + + if r.property_type: + fmt, value = r.value + r.format = fmt + r.value = value + return r + else: + return None + + def get_full_property(self, property, property_type, sizehint = 10): + prop = self.get_property(property, property_type, 0, sizehint) + if prop: + val = prop.value + if prop.bytes_after: + prop = self.get_property(property, property_type, sizehint, + prop.bytes_after // 4 + 1) + val = val + prop.value + + prop.value = val + return prop + else: + return None + + def get_full_text_property(self, property, property_type=X.AnyPropertyType, sizehint = 10): + prop = self.get_full_property(property, property_type, + sizehint=sizehint) + if prop is None or prop.format != 8: + return None + if prop.property_type == Xatom.STRING: + prop.value = prop.value.decode(self._STRING_ENCODING) + elif prop.property_type == self.display.get_atom('UTF8_STRING'): + prop.value = prop.value.decode(self._UTF8_STRING_ENCODING) + # FIXME: at least basic support for compound text would be nice. + # elif prop.property_type == self.display.get_atom('COMPOUND_TEXT'): + return prop.value + + def list_properties(self): + r = request.ListProperties(display = self.display, + window = self.id) + return r.atoms + + def set_selection_owner(self, selection, time, onerror = None): + request.SetSelectionOwner(display = self.display, + onerror = onerror, + window = self.id, + selection = selection, + time = time) + + def convert_selection(self, selection, target, property, time, onerror = None): + request.ConvertSelection(display = self.display, + onerror = onerror, + requestor = self.id, + selection = selection, + target = target, + property = property, + time = time) + + def send_event(self, event, event_mask = 0, propagate = False, onerror = None): + request.SendEvent(display = self.display, + onerror = onerror, + propagate = propagate, + destination = self.id, + event_mask = event_mask, + event = event) + + def grab_pointer(self, owner_events, event_mask, + pointer_mode, keyboard_mode, + confine_to, cursor, time): + + r = request.GrabPointer(display = self.display, + owner_events = owner_events, + grab_window = self.id, + event_mask = event_mask, + pointer_mode = pointer_mode, + keyboard_mode = keyboard_mode, + confine_to = confine_to, + cursor = cursor, + time = time) + return r.status + + def grab_button(self, button, modifiers, owner_events, event_mask, + pointer_mode, keyboard_mode, + confine_to, cursor, onerror = None): + + request.GrabButton(display = self.display, + onerror = onerror, + owner_events = owner_events, + grab_window = self.id, + event_mask = event_mask, + pointer_mode = pointer_mode, + keyboard_mode = keyboard_mode, + confine_to = confine_to, + cursor = cursor, + button = button, + modifiers = modifiers) + + def ungrab_button(self, button, modifiers, onerror = None): + request.UngrabButton(display = self.display, + onerror = onerror, + button = button, + grab_window = self.id, + modifiers = modifiers) + + + def grab_keyboard(self, owner_events, pointer_mode, keyboard_mode, time): + r = request.GrabKeyboard(display = self.display, + owner_events = owner_events, + grab_window = self.id, + time = time, + pointer_mode = pointer_mode, + keyboard_mode = keyboard_mode) + + return r.status + + def grab_key(self, key, modifiers, owner_events, pointer_mode, keyboard_mode, onerror = None): + request.GrabKey(display = self.display, + onerror = onerror, + owner_events = owner_events, + grab_window = self.id, + modifiers = modifiers, + key = key, + pointer_mode = pointer_mode, + keyboard_mode = keyboard_mode) + + def ungrab_key(self, key, modifiers, onerror = None): + request.UngrabKey(display = self.display, + onerror = onerror, + key = key, + grab_window = self.id, + modifiers = modifiers) + + def query_pointer(self): + return request.QueryPointer(display = self.display, + window = self.id) + + def get_motion_events(self, start, stop): + r = request.GetMotionEvents(display = self.display, + window = self.id, + start = start, + stop = stop) + return r.events + + def translate_coords(self, src_window, src_x, src_y): + return request.TranslateCoords(display = self.display, + src_wid = src_window, + dst_wid = self.id, + src_x = src_x, + src_y = src_y) + + def warp_pointer(self, x, y, src_window = 0, src_x = 0, src_y = 0, + src_width = 0, src_height = 0, onerror = None): + + request.WarpPointer(display = self.display, + onerror = onerror, + src_window = src_window, + dst_window = self.id, + src_x = src_x, + src_y = src_y, + src_width = src_width, + src_height = src_height, + dst_x = x, + dst_y = y) + + def set_input_focus(self, revert_to, time, onerror = None): + request.SetInputFocus(display = self.display, + onerror = onerror, + revert_to = revert_to, + focus = self.id, + time = time) + + def clear_area(self, x = 0, y = 0, width = 0, height = 0, exposures = False, onerror = None): + request.ClearArea(display = self.display, + onerror = onerror, + exposures = exposures, + window = self.id, + x = x, + y = y, + width = width, + height = height) + + def create_colormap(self, visual, alloc): + mid = self.display.allocate_resource_id() + request.CreateColormap(display = self.display, + alloc = alloc, + mid = mid, + window = self.id, + visual = visual) + cls = self.display.get_resource_class('colormap', colormap.Colormap) + return cls(self.display, mid, owner = 1) + + def list_installed_colormaps(self): + r = request.ListInstalledColormaps(display = self.display, + window = self.id) + return r.cmaps + + def rotate_properties(self, properties, delta, onerror = None): + request.RotateProperties(display = self.display, + onerror = onerror, + window = self.id, + delta = delta, + properties = properties) + + def set_wm_name(self, name, onerror = None): + self.change_text_property(Xatom.WM_NAME, Xatom.STRING, name, + onerror = onerror) + + def get_wm_name(self): + return self.get_full_text_property(Xatom.WM_NAME, Xatom.STRING) + + def set_wm_icon_name(self, name, onerror = None): + self.change_text_property(Xatom.WM_ICON_NAME, Xatom.STRING, name, + onerror = onerror) + + def get_wm_icon_name(self): + return self.get_full_text_property(Xatom.WM_ICON_NAME, Xatom.STRING) + + def set_wm_class(self, inst, cls, onerror = None): + self.change_text_property(Xatom.WM_CLASS, Xatom.STRING, + '%s\0%s\0' % (inst, cls), + onerror = onerror) + + def get_wm_class(self): + value = self.get_full_text_property(Xatom.WM_CLASS, Xatom.STRING) + if value is None: + return None + parts = value.split('\0') + if len(parts) < 2: + return None + else: + return parts[0], parts[1] + + def set_wm_transient_for(self, window, onerror = None): + self.change_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, + 32, [window.id], + onerror = onerror) + + def get_wm_transient_for(self): + d = self.get_property(Xatom.WM_TRANSIENT_FOR, Xatom.WINDOW, 0, 1) + if d is None or d.format != 32 or len(d.value) < 1: + return None + else: + cls = self.display.get_resource_class('window', Window) + return cls(self.display, d.value[0]) + + + def set_wm_protocols(self, protocols, onerror = None): + self.change_property(self.display.get_atom('WM_PROTOCOLS'), + Xatom.ATOM, 32, protocols, + onerror = onerror) + + def get_wm_protocols(self): + d = self.get_full_property(self.display.get_atom('WM_PROTOCOLS'), Xatom.ATOM) + if d is None or d.format != 32: + return [] + else: + return d.value + + def set_wm_colormap_windows(self, windows, onerror = None): + self.change_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), + Xatom.WINDOW, 32, + map(lambda w: w.id, windows), + onerror = onerror) + + def get_wm_colormap_windows(self): + d = self.get_full_property(self.display.get_atom('WM_COLORMAP_WINDOWS'), + Xatom.WINDOW) + if d is None or d.format != 32: + return [] + else: + cls = self.display.get_resource_class('window', Window) + return map(lambda i, d = self.display, c = cls: c(d, i), + d.value) + + + def set_wm_client_machine(self, name, onerror = None): + self.change_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING, name, + onerror = onerror) + + def get_wm_client_machine(self): + return self.get_full_text_property(Xatom.WM_CLIENT_MACHINE, Xatom.STRING) + + def set_wm_normal_hints(self, hints = {}, onerror = None, **keys): + self._set_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS, + icccm.WMNormalHints, hints, keys, onerror) + + def get_wm_normal_hints(self): + return self._get_struct_prop(Xatom.WM_NORMAL_HINTS, Xatom.WM_SIZE_HINTS, + icccm.WMNormalHints) + + def set_wm_hints(self, hints = {}, onerror = None, **keys): + self._set_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS, + icccm.WMHints, hints, keys, onerror) + + def get_wm_hints(self): + return self._get_struct_prop(Xatom.WM_HINTS, Xatom.WM_HINTS, + icccm.WMHints) + + def set_wm_state(self, hints = {}, onerror = None, **keys): + atom = self.display.get_atom('WM_STATE') + self._set_struct_prop(atom, atom, icccm.WMState, hints, keys, onerror) + + def get_wm_state(self): + atom = self.display.get_atom('WM_STATE') + return self._get_struct_prop(atom, atom, icccm.WMState) + + def set_wm_icon_size(self, hints = {}, onerror = None, **keys): + self._set_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE, + icccm.WMIconSize, hints, keys, onerror) + + def get_wm_icon_size(self): + return self._get_struct_prop(Xatom.WM_ICON_SIZE, Xatom.WM_ICON_SIZE, + icccm.WMIconSize) + + # Helper function for getting structured properties. + # pname and ptype are atoms, and pstruct is a Struct object. + # Returns a DictWrapper, or None + + def _get_struct_prop(self, pname, ptype, pstruct): + r = self.get_property(pname, ptype, 0, pstruct.static_size // 4) + if r and r.format == 32: + value = rq.encode_array(r.value) + if len(value) == pstruct.static_size: + return pstruct.parse_binary(value, self.display)[0] + + return None + + # Helper function for setting structured properties. + # pname and ptype are atoms, and pstruct is a Struct object. + # hints is a mapping or a DictWrapper, keys is a mapping. keys + # will be modified. onerror is the error handler. + + def _set_struct_prop(self, pname, ptype, pstruct, hints, keys, onerror): + if isinstance(hints, rq.DictWrapper): + keys.update(hints._data) + else: + keys.update(hints) + + value = pstruct.to_binary(*(), **keys) + + self.change_property(pname, ptype, 32, value, onerror = onerror) + + +class Pixmap(Drawable): + __pixmap__ = resource.Resource.__resource__ + + def free(self, onerror = None): + request.FreePixmap(display = self.display, + onerror = onerror, + pixmap = self.id) + + self.display.free_resource_id(self.id) + + def create_cursor(self, mask, foreground, background, x, y): + fore_red, fore_green, fore_blue = foreground + back_red, back_green, back_blue = background + cid = self.display.allocate_resource_id() + request.CreateCursor(display = self.display, + cid = cid, + source = self.id, + mask = mask, + fore_red = fore_red, + fore_green = fore_green, + fore_blue = fore_blue, + back_red = back_red, + back_green = back_green, + back_blue = back_blue, + x = x, + y = y) + cls = self.display.get_resource_class('cursor', cursor.Cursor) + return cls(self.display, cid, owner = 1) + + +def roundup(value, unit): + return (value + (unit - 1)) & ~(unit - 1) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/fontable.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/fontable.py new file mode 100644 index 0000000..4a33890 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/fontable.py @@ -0,0 +1,110 @@ +# Xlib.xobject.fontable -- fontable objects (GC, font) +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib.protocol import request + +from . import resource +from . import cursor + +class Fontable(resource.Resource): + __fontable__ = resource.Resource.__resource__ + + def query(self): + return request.QueryFont(display = self.display, + font = self.id) + + def query_text_extents(self, string): + return request.QueryTextExtents(display = self.display, + font = self.id, + string = string) + + +class GC(Fontable): + __gc__ = resource.Resource.__resource__ + + def change(self, onerror = None, **keys): + request.ChangeGC(display = self.display, + onerror = onerror, + gc = self.id, + attrs = keys) + + + def copy(self, src_gc, mask, onerror = None): + request.CopyGC(display = self.display, + onerror = onerror, + src_gc = src_gc, + dst_gc = self.id, + mask = mask) + + def set_dashes(self, offset, dashes, onerror = None): + request.SetDashes(display = self.display, + onerror = onerror, + gc = self.id, + dash_offset = offset, + dashes = dashes) + + def set_clip_rectangles(self, x_origin, y_origin, rectangles, ordering, onerror = None): + request.SetClipRectangles(display = self.display, + onerror = onerror, + ordering = ordering, + gc = self.id, + x_origin = x_origin, + y_origin = y_origin, + rectangles = rectangles) + def free(self, onerror = None): + request.FreeGC(display = self.display, + onerror = onerror, + gc = self.id) + + self.display.free_resource_id(self.id) + + + +class Font(Fontable): + __font__ = resource.Resource.__resource__ + + def close(self, onerror = None): + request.CloseFont(display = self.display, + onerror = onerror, + font = self.id) + self.display.free_resource_id(self.id) + + def create_glyph_cursor(self, mask, source_char, mask_char, + foreground, background): + fore_red, fore_green, fore_blue = foreground + back_red, back_green, back_blue = background + + cid = self.display.allocate_resource_id() + request.CreateGlyphCursor(display = self.display, + cid = cid, + source = self.id, + mask = mask, + source_char = source_char, + mask_char = mask_char, + fore_red = fore_red, + fore_green = fore_green, + fore_blue = fore_blue, + back_red = back_red, + back_green = back_green, + back_blue = back_blue) + + cls = self.display.get_resource_class('cursor', cursor.Cursor) + return cls(self.display, cid, owner = 1) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/icccm.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/icccm.py new file mode 100644 index 0000000..a328925 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/icccm.py @@ -0,0 +1,75 @@ +# Xlib.xobject.icccm -- ICCCM structures +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib import X, Xutil +from Xlib.protocol import rq + +Aspect = rq.Struct( rq.Int32('num'), rq.Int32('denum') ) + +WMNormalHints = rq.Struct( rq.Card32('flags'), + rq.Pad(16), + rq.Int32('min_width', default = 0), + rq.Int32('min_height', default = 0), + rq.Int32('max_width', default = 0), + rq.Int32('max_height', default = 0), + rq.Int32('width_inc', default = 0), + rq.Int32('height_inc', default = 0), + rq.Object('min_aspect', Aspect, default = (0, 0)), + rq.Object('max_aspect', Aspect, default = (0, 0)), + rq.Int32('base_width', default = 0), + rq.Int32('base_height', default = 0), + rq.Int32('win_gravity', default = 0), + ) + +WMHints = rq.Struct( rq.Card32('flags'), + rq.Card32('input', default = 0), + rq.Set('initial_state', 4, + # withdrawn is totally bogus according to + # ICCCM, but some window managers seem to + # use this value to identify dockapps. + # Oh well. + ( Xutil.WithdrawnState, + Xutil.NormalState, + Xutil.IconicState ), + default = Xutil.NormalState), + rq.Pixmap('icon_pixmap', default = 0), + rq.Window('icon_window', default = 0), + rq.Int32('icon_x', default = 0), + rq.Int32('icon_y', default = 0), + rq.Pixmap('icon_mask', default = 0), + rq.Window('window_group', default = 0), + ) + +WMState = rq.Struct( rq.Set('state', 4, + ( Xutil.WithdrawnState, + Xutil.NormalState, + Xutil.IconicState )), + rq.Window('icon', ( X.NONE, )), + ) + + +WMIconSize = rq.Struct( rq.Card32('min_width'), + rq.Card32('min_height'), + rq.Card32('max_width'), + rq.Card32('max_height'), + rq.Card32('width_inc'), + rq.Card32('height_inc'), + ) diff --git a/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/resource.py b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/resource.py new file mode 100644 index 0000000..460b1f0 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/Xlib/xobject/resource.py @@ -0,0 +1,54 @@ +# Xlib.xobject.resource -- any X resource object +# +# Copyright (C) 2000 Peter Liljenberg +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 +# of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., +# 59 Temple Place, +# Suite 330, +# Boston, MA 02111-1307 USA + +from Xlib.protocol import request + +class Resource(object): + def __init__(self, display, rid, owner = 0): + self.display = display + self.id = rid + self.owner = owner + + def __resource__(self): + return self.id + + def __eq__(self, obj): + if isinstance(obj, Resource): + if self.display == obj.display: + return self.id == obj.id + else: + return False + else: + return id(self) == id(obj) + + def __ne__(self, obj): + return not self == obj + + def __hash__(self): + return int(self.id) + + def __repr__(self): + return '<%s 0x%08x>' % (self.__class__.__name__, self.id) + + def kill_client(self, onerror = None): + request.KillClient(display = self.display, + onerror = onerror, + resource = self.id) diff --git a/CLI/venv/lib/python3.12/site-packages/__pycache__/six.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/__pycache__/six.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d775edccb3107d3951796c0175ded8197883d98f GIT binary patch literal 41405 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/METADATA new file mode 100644 index 0000000..f78425a --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/METADATA @@ -0,0 +1,97 @@ +Metadata-Version: 2.4 +Name: argumentparser +Version: 1.2.1 +Summary: Python 2/3 compatible commandline argument parser +Author: Tim Savannah +Author-email: kata198@gmail.com +Maintainer: Tim Savannah +Maintainer-email: kata198@gmail.com +License: LGPLv3 +Keywords: argument parser,argumentparser,argument,parser,argv,sys.argv,commandline,cmd,args +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: keywords +Dynamic: license +Dynamic: maintainer +Dynamic: maintainer-email +Dynamic: summary + + +A utility class for parsing command-line arguments. + +Constructor: + + | @param names list - This is a list of "names" which should reflect each argument. + | @param shortOptions list - This is a list of short (-x val) options. Length should match names. If no short option is available, use 'None'. Omit the leading - + | @param longOptions list - This is a list of long (--xyz val or --xyz= val) options. If no long option is available, use 'None'. Omit the leading -- + | @param staticOptions list - This is a list of static options (arguments that have meaning just being present, without taking an additional value). + | Any members of this list will be present in the results of #parse, set to True is present, otherwise False. + | @param multipleStaticOptions - A dictionary for multiple static arguments that resolve to one value. Key is the "name", values are all potential values. Ex: {'cheese' : ['--cheddar', 'gouda'] } presence of either 'gouda' or '--cheddar' in results would set cheese to True, otherwise False. + | @param allowOtherArguments default False - if False, consider non-specified arguments as errors. Regardless of value, unmatched params will be in 'unmatched' key of return value. + +Functions: + + | def parse(args) + | parse - Parses provided arguments and returns information on them. If using sys.argv, omit the first argument. + + | @return - dict keys are + | 'result' => dictionary of result name->value + | 'errors' => list of strings of errors or empty list + | 'warnings' => list of strings of warnings, or empty list + | 'unmatched' => list of strings of unmatched params, in order + +Example: + + | In [1]: from ArgumentParser import ArgumentParser + | In [2]: parser = ArgumentParser(['firstName', 'lastName', 'birthday'], + | ...: ['f', 'l', 'b'], + | ...: ['first-name', 'last-name', 'birthday'], + | ...: ['--citizen'] + | ) + | + | In [3]: parser.parse('-f Tim --last-name=savannah --birthday 6/28'.split(' ')) + | Out[3]: + | {'errors': [], + | 'result': {'--citizen': False, + | 'birthday': '6/28', + | 'firstName': 'Tim', + | 'lastName': 'savannah'}, + | 'warnings': [], + | 'unmatched' : []} + | + | In [4]: parser.parse('-f Tim --last-name=savannah --citizen'.split(' ')) + | Out[4]: + | {'errors': [], + | 'result': {'--citizen': True, 'firstName': 'Tim', 'lastName': 'savannah'}, + | 'warnings': [], + | 'unmatched': []} + +Example2: + + | >>> from ArgumentParser import ArgumentParser + | >>> parser = ArgumentParser(['name'], ['n'], ['name'], None, False) + | >>> parser.parse('-n hello some other args'.split(' ')) + | {'errors': ["Unknown argument 'some' (at position 2)", "Unknown argument 'other' (at position 3)", "Unknown argument 'args' (at position 4)"], 'result': {'name': 'hello'}, 'unmatched': ['some', 'other', 'args'], 'warnings': []} + | >>> parser = ArgumentParser(['name'], ['n'], ['name'], None, True) + | >>> parser.parse('-n hello some other args'.split(' ')) + | {'errors': [], 'result': {'name': 'hello'}, 'unmatched': ['some', 'other', 'args'], 'warnings': []} + +Example3: + + | >>> import ArgumentParser + | >>> parser = ArgumentParser.ArgumentParser( ('one', 'two'), ('o', 't'), ('uno', 'dos'), ('x'), {'cheese' : ['cheddar', 'gouda'], 'baby' : {'child', 'infant'}} ) + | >>> parser.parse(['-o', '1', 'cheddar']) + | {'errors': [], 'result': {'baby': False, 'cheese': True, 'x': False, 'one': '1'}, 'unmatched': [], 'warnings': []} + diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/RECORD new file mode 100644 index 0000000..8ed7002 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/RECORD @@ -0,0 +1,8 @@ +ArgumentParser/__init__.py,sha256=-fR5C77JVecO_hP9wn83B2AoFFEEsQoH9nxy1XJ-rXc,6693 +ArgumentParser/__pycache__/__init__.cpython-312.pyc,, +argumentparser-1.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +argumentparser-1.2.1.dist-info/METADATA,sha256=cS5iYhVP0mnAv9wR5MNzVWs51TLS8Sp9ubjIdCVRRLc,4603 +argumentparser-1.2.1.dist-info/RECORD,, +argumentparser-1.2.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +argumentparser-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +argumentparser-1.2.1.dist-info/top_level.txt,sha256=S_4po3BtGX5FpNaUyW2aepvzYtCMOQmj_NI6NyfwS18,15 diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/REQUESTED b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/top_level.txt new file mode 100644 index 0000000..94e360d --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/argumentparser-1.2.1.dist-info/top_level.txt @@ -0,0 +1 @@ +ArgumentParser diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/METADATA new file mode 100644 index 0000000..6eeadf9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.4 +Name: evdev +Version: 1.9.2 +Summary: Bindings to the Linux input handling subsystem +Author-email: Georgi Valkov +Maintainer-email: Tobi +License: Copyright (c) 2012-2025 Georgi Valkov. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. Neither the name of author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Project-URL: Homepage, https://github.com/gvalkov/python-evdev +Keywords: evdev,input,uinput +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 3 +Classifier: Operating System :: POSIX :: Linux +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Libraries +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python :: Implementation :: CPython +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +License-File: LICENSE +Dynamic: license-file + +# evdev + +

+ pypi version + License + Packaging status +

+ +This package provides bindings to the generic input event interface in Linux. +The *evdev* interface serves the purpose of passing events generated in the +kernel directly to userspace through character devices that are typically +located in `/dev/input/`. + +This package also comes with bindings to *uinput*, the userspace input +subsystem. *Uinput* allows userspace programs to create and handle input devices +that can inject events directly into the input subsystem. + +***Documentation:*** +https://python-evdev.readthedocs.io/en/latest/ + +***Development:*** +https://github.com/gvalkov/python-evdev + +***Package:*** +https://pypi.python.org/pypi/evdev + +***Changelog:*** +https://python-evdev.readthedocs.io/en/latest/changelog.html diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/RECORD new file mode 100644 index 0000000..3264e4f --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/RECORD @@ -0,0 +1,38 @@ +evdev-1.9.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +evdev-1.9.2.dist-info/METADATA,sha256=SFlJ2PoLjy17pdWwoYfIG4NuNvjRVyuSDDa1jeOpz8Y,3700 +evdev-1.9.2.dist-info/RECORD,, +evdev-1.9.2.dist-info/WHEEL,sha256=6TsICjgOR7isz_jYr-ssV7RSRmh1_0Z7_b5ESlzfzVY,104 +evdev-1.9.2.dist-info/licenses/LICENSE,sha256=1FVJYNZJYVDIjB_QLXlzEhqaV7lh6lj-NJ-_ito4FrI,1507 +evdev-1.9.2.dist-info/top_level.txt,sha256=tgRM-peDJTah3Is39Micsqkx31ek4FTHG4usyN23Xsk,6 +evdev/__init__.py,sha256=cu0Qu3CK4loreHKefFqudMmHQP-P-rkXSjrzjxHUCbw,1011 +evdev/__pycache__/__init__.cpython-312.pyc,, +evdev/__pycache__/device.cpython-312.pyc,, +evdev/__pycache__/ecodes.cpython-312.pyc,, +evdev/__pycache__/ecodes_runtime.cpython-312.pyc,, +evdev/__pycache__/eventio.cpython-312.pyc,, +evdev/__pycache__/eventio_async.cpython-312.pyc,, +evdev/__pycache__/events.cpython-312.pyc,, +evdev/__pycache__/evtest.cpython-312.pyc,, +evdev/__pycache__/ff.cpython-312.pyc,, +evdev/__pycache__/genecodes_c.cpython-312.pyc,, +evdev/__pycache__/genecodes_py.cpython-312.pyc,, +evdev/__pycache__/uinput.cpython-312.pyc,, +evdev/__pycache__/util.cpython-312.pyc,, +evdev/_ecodes.cpython-312-x86_64-linux-gnu.so,sha256=JkDf05hHVtLHsFxnBCobL_p6m2Zf1-SDRHhSMZ0oY2I,86304 +evdev/_input.cpython-312-x86_64-linux-gnu.so,sha256=f1GoZ6TGw851VjD5gukUnC4jdBKrygQ72Lbmwg08_f0,51824 +evdev/_uinput.cpython-312-x86_64-linux-gnu.so,sha256=bdxkVZ9XF2Gg5LB9byH-uQgStXixFvNe0OHHcuW5KAM,37352 +evdev/device.py,sha256=8sKHGmZh3DF1lJpsIy0pF1R9L5qGzazFGretaysu1Os,12959 +evdev/ecodes.py,sha256=_AVTtsN9w5f4M74FQgbxwAQPOedmCqVts0TCX4AE6Yw,98110 +evdev/ecodes_runtime.py,sha256=_QR3aSjX3pbwrk0f1dA-tXjiECKtV_uPpUtXpWP_cTI,2838 +evdev/eventio.py,sha256=4SnIINjPJadQChUEy_1lbTzuTORsydDC7zL2qkegTIY,4422 +evdev/eventio_async.py,sha256=B1qaEKYoiiop8YpG0AFf0lu2Im3CvW50dRPLug40xWA,3078 +evdev/events.py,sha256=_0vXzjv8yFtJR9drfwhmBZl9w4ZmfwQhgCo3WcrWi-Q,5905 +evdev/evtest.py,sha256=u0umJIV_HQUDlbBhLvXEKZ87UZqNIhk0XJRcm5VYIzg,5543 +evdev/ff.py,sha256=1B1VJ8TJ_CpJ01Qi4tUym1p8qZK_HKQSZvvhA8ROoJY,4961 +evdev/genecodes_c.py,sha256=_AhMK1iOQlkykOSzkbCbCJfZTk_dDU-jLsL_7FhYUqM,3618 +evdev/genecodes_py.py,sha256=-FuU-qy4-C_q7xkSwJICwMbCmAxyvezwSU4L2SRqwAs,1996 +evdev/input.c,sha256=omyOdIW51ZwmbcEGYO5_0viY93BX5AYaQ4PQS7s3z1E,16061 +evdev/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +evdev/uinput.c,sha256=9CkdJwL57R-qxaBS3T6vCJq9rC2KrRQK7BTHforK4XI,10188 +evdev/uinput.py,sha256=vJb5E0ThptDo6HeB0mc74zFXkh3_oW7a5amn-jhWo9U,13363 +evdev/util.py,sha256=WzgxwgjBuCE25n6UNPk91Bg2_j6weGUv1VO3vfyX8xU,4409 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/WHEEL new file mode 100644 index 0000000..8de3dd0 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: false +Tag: cp312-cp312-linux_x86_64 + diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/licenses/LICENSE b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/licenses/LICENSE new file mode 100644 index 0000000..8482b07 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/licenses/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2012-2025 Georgi Valkov. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. Neither the name of author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/top_level.txt new file mode 100644 index 0000000..97a5e58 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev-1.9.2.dist-info/top_level.txt @@ -0,0 +1 @@ +evdev diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__init__.py b/CLI/venv/lib/python3.12/site-packages/evdev/__init__.py new file mode 100644 index 0000000..bae0fec --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/__init__.py @@ -0,0 +1,39 @@ +# -------------------------------------------------------------------------- +# Gather everything into a single, convenient namespace. +# -------------------------------------------------------------------------- + +# The superfluous "import name as name" syntax is here to satisfy mypy's attrs-defined rule. +# Alternatively all exported objects can be listed in __all__. + +from . import ( + ecodes as ecodes, + ff as ff, +) + +from .device import ( + AbsInfo as AbsInfo, + DeviceInfo as DeviceInfo, + EvdevError as EvdevError, + InputDevice as InputDevice, +) + +from .events import ( + AbsEvent as AbsEvent, + InputEvent as InputEvent, + KeyEvent as KeyEvent, + RelEvent as RelEvent, + SynEvent as SynEvent, + event_factory as event_factory, +) + +from .uinput import ( + UInput as UInput, + UInputError as UInputError, +) + +from .util import ( + categorize as categorize, + list_devices as list_devices, + resolve_ecodes as resolve_ecodes, + resolve_ecodes_dict as resolve_ecodes_dict, +) diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40658da368887b15a823d0d916e6391db4f26e5c GIT binary patch literal 675 zcmY+By>8nu5XVV<+Op;NE9p@50W>5+leGv?G#-ow9h!FGA~+Hq6D1{qq6DZfl4t0v zv~R$*Q@5fnU?5X@k~5UUPyf5);r=@Q2*UuGQ~vqB+uI2Jgy8vDN3mB%JfaL`m?MD+ z78bEE#1^-OLmc4}S9rt|KJmM}%?Dygh9V$=7?F_}ld%X%C?;gm)g68!rerE+WY)zl zpNj=qh$UHyQ*tWK$Qeeh7x}-i868>LqiK=RN?Y4)Wh)52j>2&p}EpQSLpTNJ#CNbBjrbR*XF$nDKsS8O{xmnf`!jruO9W^ zZjkX3q#H#a3dz1wJ?5-ZiE&{(ReB<6Rq%!;NAHXO<0NCL`VhU)NSehX=@@9QZa7!U#`2HL9`{JT7X%oH+Ctr(Xxi06O>U}^9T?G4e>T`Y1H z-$>Tb%lH$MMak6drq0tHmGQgVb!;}##GKv7Wvg~Yes%HsGOn1S=jA5-vU#9YOkwwN zlCYeqB)KTtr@hI-v9yT&xOBGkS|Tg EKZXdr$N&HU literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/device.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/device.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77a8f7a8c24c74105464cae49024cce417cbe11c GIT binary patch literal 18186 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 BHZ=eM literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e98e8eef1c37e62637f0055856a08cb0d526dd6 GIT binary patch literal 125099 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes_runtime.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/ecodes_runtime.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e616a36d29fe519f8ee84802bf8928716584c7a GIT binary patch literal 2922 zcmaJ?%}*Og6rZ)%#_Zz6P`>iX5>P0qg99XOl(a;A*p*x3ARu3MQ)lrGu*BY7?XDe& zs>-N`nkrJvDYQM*y-`K|1NtwtmsSwPnG;ggLwX{#z4X*KyIu&vbS2Ne_nY_Tz4^^= z*1!1u9D+yN`FXyTN9cFzI8STU_^aqf=n0Zg0!fVI$}m}1!o?uTEwLGQmQAn>l2O7V zc^3Rm>fZZl)lAe$-h|JEaQ!aAf#<^PQ^pP%Lw7$z=o1%02|m$)>%iB+_G5nG)ZTiI zh5b&Reit`j59Z&8sY7CYPOR}E<`z1fHTK@vFQcbWnLddCtQW{5JqZ0ZV(^XuikqBy zy~V*6daQ(f1LmDt3{nD4B`72+S^AKDf#UkP9L?H$5*KLROV>8Ego6QBw_goAX$Z6%)^4T}Z2nVTy`r2oj!^ z6)eGwaPMA5R&t9WSog{fOXVSH*dD8#~JL1AP%PVouAL7pV)FU~_xcV6F=MELrmJ}wx)O9~Q8zH{U6@t%2cj+sSy9tuWzG=P zS&Ifm%t9oM$cvdAHn=J-&Zv1TWMPZ4N=ezJ$=TD;(2#)h63+Kwn*-QnYS?Of@PfVV z10i-~vd0STx%>aY5R@FeU}3cyhs`X`&VZ<1(mx}B>QeTZK8ypARN_?OAaJU0DsQT8DsHN6 zkTxh=08vv-@5vdg*90xxh^8VDf_h!?I22&c#d|M7nUtiaQz=p>D~5*CrVe)->0UZ` zU?5(*4dOAhjBFC0ro&}k#0KHP%BO6X)Xino8Mq^anIkM^mbgLn#9N)_;6tFB#sk@$ zC!B#z_#lY6j7b=YaIyiF;X9GWgw4o?NxX28up$xWK4J32BbzvD5RaLI6C&(=ykrn> zPLo6vY5)hs4g8Qg7*gZIw{2rIK25x~>Z~`gN8EIvAkawMbnt*Pb&I&*M{(elxamM0 zAegx6U}sFwj0wvDx`~?(bOzW42L`$paO;9!gJo7fD5QS(+d{my(uv=`Db@4+0sRFu zqkr#&vWgiR)8#xK2u;hns>xAIiuxA#KT=SCzrO{(+DIcz+ir$oUa@Bx_MZs`F&%%P zmTfQM8VcSmKKYy%f8)gsK3(utjsyz)3zq*PT3}vzQPat_4>uaScTf{^YB^dMD|S_y zj_;sG uf!XJHnZROh9yPN!(%8Ap(Na^BAZ0oJIC)ZZ5m9K8T6{r9tDS3bSQ ztaW|k-8$7-8ZM<*BU`N}SNK<5P<`7C4Q&UJuW6YrFopigk=7mLX1WWJN}#cHcD4S= z(bc0HfzBP|@^r7TMW)#Qf^R8_Yt7I2(=Sd4<;HI>7l(_pE76kpRqT}qqPE?TzkLMx zxB^>2?3es9UmV>;f!A%=fv3LM_PArE<5%`rh4t;)bf)3U_;S27R$+O|7~N-#FOQc7 z_8~NQf6PI|$$HMV|Hihj^=`K{aIS*)?~{l*3FimRbQSZZhvojVxZb!vyuSF;3H>UZ F`G5AS?KIFnYrQZg(jTan>ul}!(GuJcit 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/events.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/events.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22db36adc1be2a5f662e6110983c3f5101771a3f GIT binary patch literal 8555 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/evtest.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/evtest.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36c5d06c7a0e7d609b8f9562c942366e5de82843 GIT binary patch literal 9616 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 HQeXcAWtKhZ1Sf0~b}>Y=j^{caV~^dL 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 X*|S&o;Xa2!=EtwzhJnJo3uXBaT({k) literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/uinput.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/uinput.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e118c6f0b5c32ebfa83c7ba408299abaee9add6 GIT binary patch literal 16028 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 E0fL_3*Z=?k literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/util.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/evdev/__pycache__/util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54007b4c3334684c5148d82b870db3745329c7f8 GIT binary patch literal 5697 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 CrCh84 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/_ecodes.cpython-312-x86_64-linux-gnu.so b/CLI/venv/lib/python3.12/site-packages/evdev/_ecodes.cpython-312-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..b8d03dce5e99a16f2c078d5eaa10b0e34c08717e GIT binary patch literal 86304 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 z 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/_input.cpython-312-x86_64-linux-gnu.so b/CLI/venv/lib/python3.12/site-packages/evdev/_input.cpython-312-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..05dda820846c7a6a5f3a29230b96898b3d45c92a GIT binary patch literal 51824 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Νd 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 W#qG=R9`dM3ruf&=`1 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/_uinput.cpython-312-x86_64-linux-gnu.so b/CLI/venv/lib/python3.12/site-packages/evdev/_uinput.cpython-312-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..495f87ef3ed6e703b3d5315e929066e4c20248cb GIT binary patch literal 37352 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 b{>*L~A-jE=?oTEE2RbleyCO><3l#qg2^g+{ literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/device.py b/CLI/venv/lib/python3.12/site-packages/evdev/device.py new file mode 100644 index 0000000..a7f9b92 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/device.py @@ -0,0 +1,440 @@ +import contextlib +import os +from typing import Dict, Generic, Iterator, List, Literal, NamedTuple, Tuple, TypeVar, Union, overload + +from . import _input, ecodes, util + +try: + from .eventio_async import EvdevError, EventIO +except ImportError: + from .eventio import EvdevError, EventIO + +_AnyStr = TypeVar("_AnyStr", str, bytes) + + +class AbsInfo(NamedTuple): + """Absolute axis information. + + A ``namedtuple`` with absolute axis information - + corresponds to the ``input_absinfo`` struct: + + Attributes + --------- + value + Latest reported value for the axis. + + min + Specifies minimum value for the axis. + + max + Specifies maximum value for the axis. + + fuzz + Specifies fuzz value that is used to filter noise from the + event stream. + + flat + Values that are within this value will be discarded by joydev + interface and reported as 0 instead. + + resolution + Specifies resolution for the values reported for the axis. + Resolution for main axes (``ABS_X, ABS_Y, ABS_Z``) is reported + in units per millimeter (units/mm), resolution for rotational + axes (``ABS_RX, ABS_RY, ABS_RZ``) is reported in units per + radian. + + Note + ---- + The input core does not clamp reported values to the ``[minimum, + maximum]`` limits, such task is left to userspace. + + """ + + value: int + min: int + max: int + fuzz: int + flat: int + resolution: int + + def __str__(self): + return "value {}, min {}, max {}, fuzz {}, flat {}, res {}".format(*self) # pylint: disable=not-an-iterable + + +class KbdInfo(NamedTuple): + """Keyboard repeat rate. + + Attributes + ---------- + delay + Amount of time that a key must be depressed before it will start + to repeat (in milliseconds). + + repeat + Keyboard repeat rate in characters per second. + """ + + delay: int + repeat: int + + def __str__(self): + return "delay {}, repeat {}".format(self.delay, self.repeat) + + +class DeviceInfo(NamedTuple): + """ + Attributes + ---------- + bustype + vendor + product + version + """ + + bustype: int + vendor: int + product: int + version: int + + def __str__(self) -> str: + msg = "bus: {:04x}, vendor {:04x}, product {:04x}, version {:04x}" + return msg.format(*self) # pylint: disable=not-an-iterable + + +class InputDevice(EventIO, Generic[_AnyStr]): + """ + A linux input device from which input events can be read. + """ + + __slots__ = ("path", "fd", "info", "name", "phys", "uniq", "_rawcapabilities", "version", "ff_effects_count") + + def __init__(self, dev: Union[_AnyStr, "os.PathLike[_AnyStr]"]): + """ + Arguments + --------- + dev : str|bytes|PathLike + Path to input device + """ + + #: Path to input device. + self.path: _AnyStr = dev if not hasattr(dev, "__fspath__") else dev.__fspath__() + + # Certain operations are possible only when the device is opened in read-write mode. + try: + fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK) + except OSError: + fd = os.open(dev, os.O_RDONLY | os.O_NONBLOCK) + + #: A non-blocking file descriptor to the device file. + self.fd: int = fd + + # Returns (bustype, vendor, product, version, name, phys, capabilities). + info_res = _input.ioctl_devinfo(self.fd) + + #: A :class:`DeviceInfo ` instance. + self.info = DeviceInfo(*info_res[:4]) + + #: The name of the event device. + self.name: str = info_res[4] + + #: The physical topology of the device. + self.phys: str = info_res[5] + + #: The unique identifier of the device. + self.uniq: str = info_res[6] + + #: The evdev protocol version. + self.version: int = _input.ioctl_EVIOCGVERSION(self.fd) + + #: The raw dictionary of device capabilities - see `:func:capabilities()`. + self._rawcapabilities = _input.ioctl_capabilities(self.fd) + + #: The number of force feedback effects the device can keep in its memory. + self.ff_effects_count = _input.ioctl_EVIOCGEFFECTS(self.fd) + + def __del__(self) -> None: + if hasattr(self, "fd") and self.fd is not None: + try: + self.close() + except (OSError, ImportError, AttributeError): + pass + + def _capabilities(self, absinfo: bool = True): + res = {} + + for etype, _ecodes in self._rawcapabilities.items(): + for code in _ecodes: + l = res.setdefault(etype, []) + if isinstance(code, tuple): + if absinfo: + a = code[1] # (0, 0, 0, 255, 0, 0) + i = AbsInfo(*a) + l.append((code[0], i)) + else: + l.append(code[0]) + else: + l.append(code) + + return res + + @overload + def capabilities(self, verbose: Literal[False] = ..., absinfo: bool = ...) -> Dict[int, List[int]]: + ... + @overload + def capabilities(self, verbose: Literal[True], absinfo: bool = ...) -> Dict[Tuple[str, int], List[Tuple[str, int]]]: + ... + def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Union[Dict[int, List[int]], Dict[Tuple[str, int], List[Tuple[str, int]]]]: + """ + Return the event types that this device supports as a mapping of + supported event types to lists of handled event codes. + + Example + -------- + >>> device.capabilities() + { 1: [272, 273, 274], + 2: [0, 1, 6, 8] } + + If ``verbose`` is ``True``, event codes and types will be resolved + to their names. + + :: + + { ('EV_KEY', 1): [('BTN_MOUSE', 272), + ('BTN_RIGHT', 273), + ('BTN_MIDDLE', 273)], + ('EV_REL', 2): [('REL_X', 0), + ('REL_Y', 1), + ('REL_HWHEEL', 6), + ('REL_WHEEL', 8)] } + + Unknown codes or types will be resolved to ``'?'``. + + If ``absinfo`` is ``True``, the list of capabilities will also + include absolute axis information in the form of + :class:`AbsInfo` instances:: + + { 3: [ (0, AbsInfo(min=0, max=255, fuzz=0, flat=0)), + (1, AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]} + + Combined with ``verbose`` the above becomes:: + + { ('EV_ABS', 3): [ (('ABS_X', 0), AbsInfo(min=0, max=255, fuzz=0, flat=0)), + (('ABS_Y', 1), AbsInfo(min=0, max=255, fuzz=0, flat=0)) ]} + + """ + + if verbose: + return dict(util.resolve_ecodes_dict(self._capabilities(absinfo))) + else: + return self._capabilities(absinfo) + + def input_props(self, verbose: bool = False): + """ + Get device properties and quirks. + + Example + ------- + >>> device.input_props() + [0, 5] + + If ``verbose`` is ``True``, input properties are resolved to their + names. Unknown codes are resolved to ``'?'``:: + + [('INPUT_PROP_POINTER', 0), ('INPUT_PROP_POINTING_STICK', 5)] + + """ + props = _input.ioctl_EVIOCGPROP(self.fd) + if verbose: + return util.resolve_ecodes(ecodes.INPUT_PROP, props) + + return props + + def leds(self, verbose: bool = False): + """ + Return currently set LED keys. + + Example + ------- + >>> device.leds() + [0, 1, 8, 9] + + If ``verbose`` is ``True``, event codes are resolved to their + names. Unknown codes are resolved to ``'?'``:: + + [('LED_NUML', 0), ('LED_CAPSL', 1), ('LED_MISC', 8), ('LED_MAIL', 9)] + + """ + leds = _input.ioctl_EVIOCG_bits(self.fd, ecodes.EV_LED) + if verbose: + return util.resolve_ecodes(ecodes.LED, leds) + + return leds + + def set_led(self, led_num: int, value: int) -> None: + """ + Set the state of the selected LED. + + Example + ------- + >>> device.set_led(ecodes.LED_NUML, 1) + """ + self.write(ecodes.EV_LED, led_num, value) + + def __eq__(self, other): + """ + Two devices are equal if their :data:`info` attributes are equal. + """ + return isinstance(other, self.__class__) and self.info == other.info and self.path == other.path + + def __str__(self) -> str: + msg = 'device {}, name "{}", phys "{}", uniq "{}"' + return msg.format(self.path, self.name, self.phys, self.uniq or "") + + def __repr__(self) -> str: + msg = (self.__class__.__name__, self.path) + return "{}({!r})".format(*msg) + + def __fspath__(self): + return self.path + + def close(self) -> None: + if self.fd > -1: + try: + super().close() + os.close(self.fd) + finally: + self.fd = -1 + + def grab(self) -> None: + """ + Grab input device using ``EVIOCGRAB`` - other applications will + be unable to receive events until the device is released. Only + one process can hold a ``EVIOCGRAB`` on a device. + + Warning + ------- + Grabbing an already grabbed device will raise an ``OSError``. + """ + + _input.ioctl_EVIOCGRAB(self.fd, 1) + + def ungrab(self) -> None: + """ + Release device if it has been already grabbed (uses `EVIOCGRAB`). + + Warning + ------- + Releasing an already released device will raise an + ``OSError('Invalid argument')``. + """ + + _input.ioctl_EVIOCGRAB(self.fd, 0) + + @contextlib.contextmanager + def grab_context(self) -> Iterator[None]: + """ + A context manager for the duration of which only the current + process will be able to receive events from the device. + """ + self.grab() + yield + self.ungrab() + + def upload_effect(self, effect: "ff.Effect"): + """ + Upload a force feedback effect to a force feedback device. + """ + + data = memoryview(effect).tobytes() + ff_id = _input.upload_effect(self.fd, data) + return ff_id + + def erase_effect(self, ff_id) -> None: + """ + Erase a force effect from a force feedback device. This also + stops the effect. + """ + + _input.erase_effect(self.fd, ff_id) + + @property + def repeat(self): + """ + Get or set the keyboard repeat rate (in characters per + minute) and delay (in milliseconds). + """ + + return KbdInfo(*_input.ioctl_EVIOCGREP(self.fd)) + + @repeat.setter + def repeat(self, value: Tuple[int, int]): + return _input.ioctl_EVIOCSREP(self.fd, *value) + + def active_keys(self, verbose: bool = False): + """ + Return currently active keys. + + Example + ------- + + >>> device.active_keys() + [1, 42] + + If ``verbose`` is ``True``, key codes are resolved to their + verbose names. Unknown codes are resolved to ``'?'``. For + example:: + + [('KEY_ESC', 1), ('KEY_LEFTSHIFT', 42)] + + """ + active_keys = _input.ioctl_EVIOCG_bits(self.fd, ecodes.EV_KEY) + if verbose: + return util.resolve_ecodes(ecodes.KEY, active_keys) + + return active_keys + + def absinfo(self, axis_num: int): + """ + Return current :class:`AbsInfo` for input device axis + + Arguments + --------- + axis_num : int + EV_ABS keycode (example :attr:`ecodes.ABS_X`) + + Example + ------- + >>> device.absinfo(ecodes.ABS_X) + AbsInfo(value=1501, min=-32768, max=32767, fuzz=0, flat=128, resolution=0) + """ + return AbsInfo(*_input.ioctl_EVIOCGABS(self.fd, axis_num)) + + def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None) -> None: + """ + Update :class:`AbsInfo` values. Only specified values will be overwritten. + + Arguments + --------- + axis_num : int + EV_ABS keycode (example :attr:`ecodes.ABS_X`) + + Example + ------- + >>> device.set_absinfo(ecodes.ABS_X, min=-2000, max=2000) + + You can also unpack AbsInfo tuple that will overwrite all values + + >>> device.set_absinfo(ecodes.ABS_Y, *AbsInfo(0, -2000, 2000, 0, 15, 0)) + """ + + cur_absinfo = self.absinfo(axis_num) + new_absinfo = AbsInfo( + value if value is not None else cur_absinfo.value, + min if min is not None else cur_absinfo.min, + max if max is not None else cur_absinfo.max, + fuzz if fuzz is not None else cur_absinfo.fuzz, + flat if flat is not None else cur_absinfo.flat, + resolution if resolution is not None else cur_absinfo.resolution, + ) + _input.ioctl_EVIOCSABS(self.fd, axis_num, new_absinfo) diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/ecodes.py b/CLI/venv/lib/python3.12/site-packages/evdev/ecodes.py new file mode 100644 index 0000000..39cdcbd --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/ecodes.py @@ -0,0 +1,3885 @@ +# Automatically generated by evdev.genecodes_py + +""" +This modules exposes the integer constants defined in ``linux/input.h`` and +``linux/input-event-codes.h``. + +Exposed constants:: + + KEY, ABS, REL, SW, MSC, LED, BTN, REP, SND, ID, EV, + BUS, SYN, FF, FF_STATUS, INPUT_PROP + +This module also provides reverse and forward mappings of the names and values +of the above mentioned constants:: + + >>> evdev.ecodes.KEY_A + 30 + + >>> evdev.ecodes.ecodes['KEY_A'] + 30 + + >>> evdev.ecodes.KEY[30] + 'KEY_A' + + >>> evdev.ecodes.REL[0] + 'REL_X' + + >>> evdev.ecodes.EV[evdev.ecodes.EV_KEY] + 'EV_KEY' + + >>> evdev.ecodes.bytype[evdev.ecodes.EV_REL][0] + 'REL_X' + +Keep in mind that values in reverse mappings may point to one or more event +codes. For example:: + + >>> evdev.ecodes.FF[80] + ('FF_EFFECT_MIN', 'FF_RUMBLE') + + >>> evdev.ecodes.FF[81] + 'FF_PERIODIC' +""" + +from typing import Final, Dict, Tuple, Union + +ABS_BRAKE: Final[int] = 10 +ABS_CNT: Final[int] = 64 +ABS_DISTANCE: Final[int] = 25 +ABS_GAS: Final[int] = 9 +ABS_HAT0X: Final[int] = 16 +ABS_HAT0Y: Final[int] = 17 +ABS_HAT1X: Final[int] = 18 +ABS_HAT1Y: Final[int] = 19 +ABS_HAT2X: Final[int] = 20 +ABS_HAT2Y: Final[int] = 21 +ABS_HAT3X: Final[int] = 22 +ABS_HAT3Y: Final[int] = 23 +ABS_MAX: Final[int] = 63 +ABS_MISC: Final[int] = 40 +ABS_MT_BLOB_ID: Final[int] = 56 +ABS_MT_DISTANCE: Final[int] = 59 +ABS_MT_ORIENTATION: Final[int] = 52 +ABS_MT_POSITION_X: Final[int] = 53 +ABS_MT_POSITION_Y: Final[int] = 54 +ABS_MT_PRESSURE: Final[int] = 58 +ABS_MT_SLOT: Final[int] = 47 +ABS_MT_TOOL_TYPE: Final[int] = 55 +ABS_MT_TOOL_X: Final[int] = 60 +ABS_MT_TOOL_Y: Final[int] = 61 +ABS_MT_TOUCH_MAJOR: Final[int] = 48 +ABS_MT_TOUCH_MINOR: Final[int] = 49 +ABS_MT_TRACKING_ID: Final[int] = 57 +ABS_MT_WIDTH_MAJOR: Final[int] = 50 +ABS_MT_WIDTH_MINOR: Final[int] = 51 +ABS_PRESSURE: Final[int] = 24 +ABS_PROFILE: Final[int] = 33 +ABS_RESERVED: Final[int] = 46 +ABS_RUDDER: Final[int] = 7 +ABS_RX: Final[int] = 3 +ABS_RY: Final[int] = 4 +ABS_RZ: Final[int] = 5 +ABS_THROTTLE: Final[int] = 6 +ABS_TILT_X: Final[int] = 26 +ABS_TILT_Y: Final[int] = 27 +ABS_TOOL_WIDTH: Final[int] = 28 +ABS_VOLUME: Final[int] = 32 +ABS_WHEEL: Final[int] = 8 +ABS_X: Final[int] = 0 +ABS_Y: Final[int] = 1 +ABS_Z: Final[int] = 2 +BTN_0: Final[int] = 256 +BTN_1: Final[int] = 257 +BTN_2: Final[int] = 258 +BTN_3: Final[int] = 259 +BTN_4: Final[int] = 260 +BTN_5: Final[int] = 261 +BTN_6: Final[int] = 262 +BTN_7: Final[int] = 263 +BTN_8: Final[int] = 264 +BTN_9: Final[int] = 265 +BTN_A: Final[int] = 304 +BTN_B: Final[int] = 305 +BTN_BACK: Final[int] = 278 +BTN_BASE: Final[int] = 294 +BTN_BASE2: Final[int] = 295 +BTN_BASE3: Final[int] = 296 +BTN_BASE4: Final[int] = 297 +BTN_BASE5: Final[int] = 298 +BTN_BASE6: Final[int] = 299 +BTN_C: Final[int] = 306 +BTN_DEAD: Final[int] = 303 +BTN_DIGI: Final[int] = 320 +BTN_DPAD_DOWN: Final[int] = 545 +BTN_DPAD_LEFT: Final[int] = 546 +BTN_DPAD_RIGHT: Final[int] = 547 +BTN_DPAD_UP: Final[int] = 544 +BTN_EAST: Final[int] = 305 +BTN_EXTRA: Final[int] = 276 +BTN_FORWARD: Final[int] = 277 +BTN_GAMEPAD: Final[int] = 304 +BTN_GEAR_DOWN: Final[int] = 336 +BTN_GEAR_UP: Final[int] = 337 +BTN_JOYSTICK: Final[int] = 288 +BTN_LEFT: Final[int] = 272 +BTN_MIDDLE: Final[int] = 274 +BTN_MISC: Final[int] = 256 +BTN_MODE: Final[int] = 316 +BTN_MOUSE: Final[int] = 272 +BTN_NORTH: Final[int] = 307 +BTN_PINKIE: Final[int] = 293 +BTN_RIGHT: Final[int] = 273 +BTN_SELECT: Final[int] = 314 +BTN_SIDE: Final[int] = 275 +BTN_SOUTH: Final[int] = 304 +BTN_START: Final[int] = 315 +BTN_STYLUS: Final[int] = 331 +BTN_STYLUS2: Final[int] = 332 +BTN_STYLUS3: Final[int] = 329 +BTN_TASK: Final[int] = 279 +BTN_THUMB: Final[int] = 289 +BTN_THUMB2: Final[int] = 290 +BTN_THUMBL: Final[int] = 317 +BTN_THUMBR: Final[int] = 318 +BTN_TL: Final[int] = 310 +BTN_TL2: Final[int] = 312 +BTN_TOOL_AIRBRUSH: Final[int] = 324 +BTN_TOOL_BRUSH: Final[int] = 322 +BTN_TOOL_DOUBLETAP: Final[int] = 333 +BTN_TOOL_FINGER: Final[int] = 325 +BTN_TOOL_LENS: Final[int] = 327 +BTN_TOOL_MOUSE: Final[int] = 326 +BTN_TOOL_PEN: Final[int] = 320 +BTN_TOOL_PENCIL: Final[int] = 323 +BTN_TOOL_QUADTAP: Final[int] = 335 +BTN_TOOL_QUINTTAP: Final[int] = 328 +BTN_TOOL_RUBBER: Final[int] = 321 +BTN_TOOL_TRIPLETAP: Final[int] = 334 +BTN_TOP: Final[int] = 291 +BTN_TOP2: Final[int] = 292 +BTN_TOUCH: Final[int] = 330 +BTN_TR: Final[int] = 311 +BTN_TR2: Final[int] = 313 +BTN_TRIGGER: Final[int] = 288 +BTN_TRIGGER_HAPPY: Final[int] = 704 +BTN_TRIGGER_HAPPY1: Final[int] = 704 +BTN_TRIGGER_HAPPY10: Final[int] = 713 +BTN_TRIGGER_HAPPY11: Final[int] = 714 +BTN_TRIGGER_HAPPY12: Final[int] = 715 +BTN_TRIGGER_HAPPY13: Final[int] = 716 +BTN_TRIGGER_HAPPY14: Final[int] = 717 +BTN_TRIGGER_HAPPY15: Final[int] = 718 +BTN_TRIGGER_HAPPY16: Final[int] = 719 +BTN_TRIGGER_HAPPY17: Final[int] = 720 +BTN_TRIGGER_HAPPY18: Final[int] = 721 +BTN_TRIGGER_HAPPY19: Final[int] = 722 +BTN_TRIGGER_HAPPY2: Final[int] = 705 +BTN_TRIGGER_HAPPY20: Final[int] = 723 +BTN_TRIGGER_HAPPY21: Final[int] = 724 +BTN_TRIGGER_HAPPY22: Final[int] = 725 +BTN_TRIGGER_HAPPY23: Final[int] = 726 +BTN_TRIGGER_HAPPY24: Final[int] = 727 +BTN_TRIGGER_HAPPY25: Final[int] = 728 +BTN_TRIGGER_HAPPY26: Final[int] = 729 +BTN_TRIGGER_HAPPY27: Final[int] = 730 +BTN_TRIGGER_HAPPY28: Final[int] = 731 +BTN_TRIGGER_HAPPY29: Final[int] = 732 +BTN_TRIGGER_HAPPY3: Final[int] = 706 +BTN_TRIGGER_HAPPY30: Final[int] = 733 +BTN_TRIGGER_HAPPY31: Final[int] = 734 +BTN_TRIGGER_HAPPY32: Final[int] = 735 +BTN_TRIGGER_HAPPY33: Final[int] = 736 +BTN_TRIGGER_HAPPY34: Final[int] = 737 +BTN_TRIGGER_HAPPY35: Final[int] = 738 +BTN_TRIGGER_HAPPY36: Final[int] = 739 +BTN_TRIGGER_HAPPY37: Final[int] = 740 +BTN_TRIGGER_HAPPY38: Final[int] = 741 +BTN_TRIGGER_HAPPY39: Final[int] = 742 +BTN_TRIGGER_HAPPY4: Final[int] = 707 +BTN_TRIGGER_HAPPY40: Final[int] = 743 +BTN_TRIGGER_HAPPY5: Final[int] = 708 +BTN_TRIGGER_HAPPY6: Final[int] = 709 +BTN_TRIGGER_HAPPY7: Final[int] = 710 +BTN_TRIGGER_HAPPY8: Final[int] = 711 +BTN_TRIGGER_HAPPY9: Final[int] = 712 +BTN_WEST: Final[int] = 308 +BTN_WHEEL: Final[int] = 336 +BTN_X: Final[int] = 307 +BTN_Y: Final[int] = 308 +BTN_Z: Final[int] = 309 +BUS_ADB: Final[int] = 23 +BUS_AMD_SFH: Final[int] = 32 +BUS_AMIGA: Final[int] = 22 +BUS_ATARI: Final[int] = 27 +BUS_BLUETOOTH: Final[int] = 5 +BUS_CEC: Final[int] = 30 +BUS_GAMEPORT: Final[int] = 20 +BUS_GSC: Final[int] = 26 +BUS_HIL: Final[int] = 4 +BUS_HOST: Final[int] = 25 +BUS_I2C: Final[int] = 24 +BUS_I8042: Final[int] = 17 +BUS_INTEL_ISHTP: Final[int] = 31 +BUS_ISA: Final[int] = 16 +BUS_ISAPNP: Final[int] = 2 +BUS_PARPORT: Final[int] = 21 +BUS_PCI: Final[int] = 1 +BUS_RMI: Final[int] = 29 +BUS_RS232: Final[int] = 19 +BUS_SPI: Final[int] = 28 +BUS_USB: Final[int] = 3 +BUS_VIRTUAL: Final[int] = 6 +BUS_XTKBD: Final[int] = 18 +EV_ABS: Final[int] = 3 +EV_CNT: Final[int] = 32 +EV_FF: Final[int] = 21 +EV_FF_STATUS: Final[int] = 23 +EV_KEY: Final[int] = 1 +EV_LED: Final[int] = 17 +EV_MAX: Final[int] = 31 +EV_MSC: Final[int] = 4 +EV_PWR: Final[int] = 22 +EV_REL: Final[int] = 2 +EV_REP: Final[int] = 20 +EV_SND: Final[int] = 18 +EV_SW: Final[int] = 5 +EV_SYN: Final[int] = 0 +EV_UINPUT: Final[int] = 257 +EV_VERSION: Final[int] = 65537 +FF_AUTOCENTER: Final[int] = 97 +FF_CNT: Final[int] = 128 +FF_CONSTANT: Final[int] = 82 +FF_CUSTOM: Final[int] = 93 +FF_DAMPER: Final[int] = 85 +FF_EFFECT_MAX: Final[int] = 87 +FF_EFFECT_MIN: Final[int] = 80 +FF_FRICTION: Final[int] = 84 +FF_GAIN: Final[int] = 96 +FF_INERTIA: Final[int] = 86 +FF_MAX: Final[int] = 127 +FF_MAX_EFFECTS: Final[int] = 96 +FF_PERIODIC: Final[int] = 81 +FF_RAMP: Final[int] = 87 +FF_RUMBLE: Final[int] = 80 +FF_SAW_DOWN: Final[int] = 92 +FF_SAW_UP: Final[int] = 91 +FF_SINE: Final[int] = 90 +FF_SPRING: Final[int] = 83 +FF_SQUARE: Final[int] = 88 +FF_STATUS_MAX: Final[int] = 1 +FF_STATUS_PLAYING: Final[int] = 1 +FF_STATUS_STOPPED: Final[int] = 0 +FF_TRIANGLE: Final[int] = 89 +FF_WAVEFORM_MAX: Final[int] = 93 +FF_WAVEFORM_MIN: Final[int] = 88 +ID_BUS: Final[int] = 0 +ID_PRODUCT: Final[int] = 2 +ID_VENDOR: Final[int] = 1 +ID_VERSION: Final[int] = 3 +INPUT_PROP_ACCELEROMETER: Final[int] = 6 +INPUT_PROP_BUTTONPAD: Final[int] = 2 +INPUT_PROP_CNT: Final[int] = 32 +INPUT_PROP_DIRECT: Final[int] = 1 +INPUT_PROP_MAX: Final[int] = 31 +INPUT_PROP_POINTER: Final[int] = 0 +INPUT_PROP_POINTING_STICK: Final[int] = 5 +INPUT_PROP_SEMI_MT: Final[int] = 3 +INPUT_PROP_TOPBUTTONPAD: Final[int] = 4 +KEY_0: Final[int] = 11 +KEY_1: Final[int] = 2 +KEY_102ND: Final[int] = 86 +KEY_10CHANNELSDOWN: Final[int] = 441 +KEY_10CHANNELSUP: Final[int] = 440 +KEY_2: Final[int] = 3 +KEY_3: Final[int] = 4 +KEY_3D_MODE: Final[int] = 623 +KEY_4: Final[int] = 5 +KEY_5: Final[int] = 6 +KEY_6: Final[int] = 7 +KEY_7: Final[int] = 8 +KEY_8: Final[int] = 9 +KEY_9: Final[int] = 10 +KEY_A: Final[int] = 30 +KEY_AB: Final[int] = 406 +KEY_ACCESSIBILITY: Final[int] = 590 +KEY_ADDRESSBOOK: Final[int] = 429 +KEY_AGAIN: Final[int] = 129 +KEY_ALL_APPLICATIONS: Final[int] = 204 +KEY_ALS_TOGGLE: Final[int] = 560 +KEY_ALTERASE: Final[int] = 222 +KEY_ANGLE: Final[int] = 371 +KEY_APOSTROPHE: Final[int] = 40 +KEY_APPSELECT: Final[int] = 580 +KEY_ARCHIVE: Final[int] = 361 +KEY_ASPECT_RATIO: Final[int] = 375 +KEY_ASSISTANT: Final[int] = 583 +KEY_ATTENDANT_OFF: Final[int] = 540 +KEY_ATTENDANT_ON: Final[int] = 539 +KEY_ATTENDANT_TOGGLE: Final[int] = 541 +KEY_AUDIO: Final[int] = 392 +KEY_AUDIO_DESC: Final[int] = 622 +KEY_AUTOPILOT_ENGAGE_TOGGLE: Final[int] = 637 +KEY_AUX: Final[int] = 390 +KEY_B: Final[int] = 48 +KEY_BACK: Final[int] = 158 +KEY_BACKSLASH: Final[int] = 43 +KEY_BACKSPACE: Final[int] = 14 +KEY_BASSBOOST: Final[int] = 209 +KEY_BATTERY: Final[int] = 236 +KEY_BLUE: Final[int] = 401 +KEY_BLUETOOTH: Final[int] = 237 +KEY_BOOKMARKS: Final[int] = 156 +KEY_BREAK: Final[int] = 411 +KEY_BRIGHTNESSDOWN: Final[int] = 224 +KEY_BRIGHTNESSUP: Final[int] = 225 +KEY_BRIGHTNESS_AUTO: Final[int] = 244 +KEY_BRIGHTNESS_CYCLE: Final[int] = 243 +KEY_BRIGHTNESS_MAX: Final[int] = 593 +KEY_BRIGHTNESS_MENU: Final[int] = 649 +KEY_BRIGHTNESS_MIN: Final[int] = 592 +KEY_BRIGHTNESS_TOGGLE: Final[int] = 431 +KEY_BRIGHTNESS_ZERO: Final[int] = 244 +KEY_BRL_DOT1: Final[int] = 497 +KEY_BRL_DOT10: Final[int] = 506 +KEY_BRL_DOT2: Final[int] = 498 +KEY_BRL_DOT3: Final[int] = 499 +KEY_BRL_DOT4: Final[int] = 500 +KEY_BRL_DOT5: Final[int] = 501 +KEY_BRL_DOT6: Final[int] = 502 +KEY_BRL_DOT7: Final[int] = 503 +KEY_BRL_DOT8: Final[int] = 504 +KEY_BRL_DOT9: Final[int] = 505 +KEY_BUTTONCONFIG: Final[int] = 576 +KEY_C: Final[int] = 46 +KEY_CALC: Final[int] = 140 +KEY_CALENDAR: Final[int] = 397 +KEY_CAMERA: Final[int] = 212 +KEY_CAMERA_ACCESS_DISABLE: Final[int] = 588 +KEY_CAMERA_ACCESS_ENABLE: Final[int] = 587 +KEY_CAMERA_ACCESS_TOGGLE: Final[int] = 589 +KEY_CAMERA_DOWN: Final[int] = 536 +KEY_CAMERA_FOCUS: Final[int] = 528 +KEY_CAMERA_LEFT: Final[int] = 537 +KEY_CAMERA_RIGHT: Final[int] = 538 +KEY_CAMERA_UP: Final[int] = 535 +KEY_CAMERA_ZOOMIN: Final[int] = 533 +KEY_CAMERA_ZOOMOUT: Final[int] = 534 +KEY_CANCEL: Final[int] = 223 +KEY_CAPSLOCK: Final[int] = 58 +KEY_CD: Final[int] = 383 +KEY_CHANNEL: Final[int] = 363 +KEY_CHANNELDOWN: Final[int] = 403 +KEY_CHANNELUP: Final[int] = 402 +KEY_CHAT: Final[int] = 216 +KEY_CLEAR: Final[int] = 355 +KEY_CLEARVU_SONAR: Final[int] = 646 +KEY_CLOSE: Final[int] = 206 +KEY_CLOSECD: Final[int] = 160 +KEY_CNT: Final[int] = 768 +KEY_COFFEE: Final[int] = 152 +KEY_COMMA: Final[int] = 51 +KEY_COMPOSE: Final[int] = 127 +KEY_COMPUTER: Final[int] = 157 +KEY_CONFIG: Final[int] = 171 +KEY_CONNECT: Final[int] = 218 +KEY_CONTEXT_MENU: Final[int] = 438 +KEY_CONTROLPANEL: Final[int] = 579 +KEY_COPY: Final[int] = 133 +KEY_CUT: Final[int] = 137 +KEY_CYCLEWINDOWS: Final[int] = 154 +KEY_D: Final[int] = 32 +KEY_DASHBOARD: Final[int] = 204 +KEY_DATA: Final[int] = 631 +KEY_DATABASE: Final[int] = 426 +KEY_DELETE: Final[int] = 111 +KEY_DELETEFILE: Final[int] = 146 +KEY_DEL_EOL: Final[int] = 448 +KEY_DEL_EOS: Final[int] = 449 +KEY_DEL_LINE: Final[int] = 451 +KEY_DICTATE: Final[int] = 586 +KEY_DIGITS: Final[int] = 413 +KEY_DIRECTION: Final[int] = 153 +KEY_DIRECTORY: Final[int] = 394 +KEY_DISPLAYTOGGLE: Final[int] = 431 +KEY_DISPLAY_OFF: Final[int] = 245 +KEY_DOCUMENTS: Final[int] = 235 +KEY_DOLLAR: Final[int] = 434 +KEY_DOT: Final[int] = 52 +KEY_DOWN: Final[int] = 108 +KEY_DO_NOT_DISTURB: Final[int] = 591 +KEY_DUAL_RANGE_RADAR: Final[int] = 643 +KEY_DVD: Final[int] = 389 +KEY_E: Final[int] = 18 +KEY_EDIT: Final[int] = 176 +KEY_EDITOR: Final[int] = 422 +KEY_EJECTCD: Final[int] = 161 +KEY_EJECTCLOSECD: Final[int] = 162 +KEY_EMAIL: Final[int] = 215 +KEY_EMOJI_PICKER: Final[int] = 585 +KEY_END: Final[int] = 107 +KEY_ENTER: Final[int] = 28 +KEY_EPG: Final[int] = 365 +KEY_EQUAL: Final[int] = 13 +KEY_ESC: Final[int] = 1 +KEY_EURO: Final[int] = 435 +KEY_EXIT: Final[int] = 174 +KEY_F: Final[int] = 33 +KEY_F1: Final[int] = 59 +KEY_F10: Final[int] = 68 +KEY_F11: Final[int] = 87 +KEY_F12: Final[int] = 88 +KEY_F13: Final[int] = 183 +KEY_F14: Final[int] = 184 +KEY_F15: Final[int] = 185 +KEY_F16: Final[int] = 186 +KEY_F17: Final[int] = 187 +KEY_F18: Final[int] = 188 +KEY_F19: Final[int] = 189 +KEY_F2: Final[int] = 60 +KEY_F20: Final[int] = 190 +KEY_F21: Final[int] = 191 +KEY_F22: Final[int] = 192 +KEY_F23: Final[int] = 193 +KEY_F24: Final[int] = 194 +KEY_F3: Final[int] = 61 +KEY_F4: Final[int] = 62 +KEY_F5: Final[int] = 63 +KEY_F6: Final[int] = 64 +KEY_F7: Final[int] = 65 +KEY_F8: Final[int] = 66 +KEY_F9: Final[int] = 67 +KEY_FASTFORWARD: Final[int] = 208 +KEY_FASTREVERSE: Final[int] = 629 +KEY_FAVORITES: Final[int] = 364 +KEY_FILE: Final[int] = 144 +KEY_FINANCE: Final[int] = 219 +KEY_FIND: Final[int] = 136 +KEY_FIRST: Final[int] = 404 +KEY_FISHING_CHART: Final[int] = 641 +KEY_FN: Final[int] = 464 +KEY_FN_1: Final[int] = 478 +KEY_FN_2: Final[int] = 479 +KEY_FN_B: Final[int] = 484 +KEY_FN_D: Final[int] = 480 +KEY_FN_E: Final[int] = 481 +KEY_FN_ESC: Final[int] = 465 +KEY_FN_F: Final[int] = 482 +KEY_FN_F1: Final[int] = 466 +KEY_FN_F10: Final[int] = 475 +KEY_FN_F11: Final[int] = 476 +KEY_FN_F12: Final[int] = 477 +KEY_FN_F2: Final[int] = 467 +KEY_FN_F3: Final[int] = 468 +KEY_FN_F4: Final[int] = 469 +KEY_FN_F5: Final[int] = 470 +KEY_FN_F6: Final[int] = 471 +KEY_FN_F7: Final[int] = 472 +KEY_FN_F8: Final[int] = 473 +KEY_FN_F9: Final[int] = 474 +KEY_FN_RIGHT_SHIFT: Final[int] = 485 +KEY_FN_S: Final[int] = 483 +KEY_FORWARD: Final[int] = 159 +KEY_FORWARDMAIL: Final[int] = 233 +KEY_FRAMEBACK: Final[int] = 436 +KEY_FRAMEFORWARD: Final[int] = 437 +KEY_FRONT: Final[int] = 132 +KEY_FULL_SCREEN: Final[int] = 372 +KEY_G: Final[int] = 34 +KEY_GAMES: Final[int] = 417 +KEY_GOTO: Final[int] = 354 +KEY_GRAPHICSEDITOR: Final[int] = 424 +KEY_GRAVE: Final[int] = 41 +KEY_GREEN: Final[int] = 399 +KEY_H: Final[int] = 35 +KEY_HANGEUL: Final[int] = 122 +KEY_HANGUEL: Final[int] = 122 +KEY_HANGUP_PHONE: Final[int] = 446 +KEY_HANJA: Final[int] = 123 +KEY_HELP: Final[int] = 138 +KEY_HENKAN: Final[int] = 92 +KEY_HIRAGANA: Final[int] = 91 +KEY_HOME: Final[int] = 102 +KEY_HOMEPAGE: Final[int] = 172 +KEY_HP: Final[int] = 211 +KEY_I: Final[int] = 23 +KEY_IMAGES: Final[int] = 442 +KEY_INFO: Final[int] = 358 +KEY_INSERT: Final[int] = 110 +KEY_INS_LINE: Final[int] = 450 +KEY_ISO: Final[int] = 170 +KEY_J: Final[int] = 36 +KEY_JOURNAL: Final[int] = 578 +KEY_K: Final[int] = 37 +KEY_KATAKANA: Final[int] = 90 +KEY_KATAKANAHIRAGANA: Final[int] = 93 +KEY_KBDILLUMDOWN: Final[int] = 229 +KEY_KBDILLUMTOGGLE: Final[int] = 228 +KEY_KBDILLUMUP: Final[int] = 230 +KEY_KBDINPUTASSIST_ACCEPT: Final[int] = 612 +KEY_KBDINPUTASSIST_CANCEL: Final[int] = 613 +KEY_KBDINPUTASSIST_NEXT: Final[int] = 609 +KEY_KBDINPUTASSIST_NEXTGROUP: Final[int] = 611 +KEY_KBDINPUTASSIST_PREV: Final[int] = 608 +KEY_KBDINPUTASSIST_PREVGROUP: Final[int] = 610 +KEY_KBD_LAYOUT_NEXT: Final[int] = 584 +KEY_KBD_LCD_MENU1: Final[int] = 696 +KEY_KBD_LCD_MENU2: Final[int] = 697 +KEY_KBD_LCD_MENU3: Final[int] = 698 +KEY_KBD_LCD_MENU4: Final[int] = 699 +KEY_KBD_LCD_MENU5: Final[int] = 700 +KEY_KEYBOARD: Final[int] = 374 +KEY_KP0: Final[int] = 82 +KEY_KP1: Final[int] = 79 +KEY_KP2: Final[int] = 80 +KEY_KP3: Final[int] = 81 +KEY_KP4: Final[int] = 75 +KEY_KP5: Final[int] = 76 +KEY_KP6: Final[int] = 77 +KEY_KP7: Final[int] = 71 +KEY_KP8: Final[int] = 72 +KEY_KP9: Final[int] = 73 +KEY_KPASTERISK: Final[int] = 55 +KEY_KPCOMMA: Final[int] = 121 +KEY_KPDOT: Final[int] = 83 +KEY_KPENTER: Final[int] = 96 +KEY_KPEQUAL: Final[int] = 117 +KEY_KPJPCOMMA: Final[int] = 95 +KEY_KPLEFTPAREN: Final[int] = 179 +KEY_KPMINUS: Final[int] = 74 +KEY_KPPLUS: Final[int] = 78 +KEY_KPPLUSMINUS: Final[int] = 118 +KEY_KPRIGHTPAREN: Final[int] = 180 +KEY_KPSLASH: Final[int] = 98 +KEY_L: Final[int] = 38 +KEY_LANGUAGE: Final[int] = 368 +KEY_LAST: Final[int] = 405 +KEY_LEFT: Final[int] = 105 +KEY_LEFTALT: Final[int] = 56 +KEY_LEFTBRACE: Final[int] = 26 +KEY_LEFTCTRL: Final[int] = 29 +KEY_LEFTMETA: Final[int] = 125 +KEY_LEFTSHIFT: Final[int] = 42 +KEY_LEFT_DOWN: Final[int] = 617 +KEY_LEFT_UP: Final[int] = 616 +KEY_LIGHTS_TOGGLE: Final[int] = 542 +KEY_LINEFEED: Final[int] = 101 +KEY_LINK_PHONE: Final[int] = 447 +KEY_LIST: Final[int] = 395 +KEY_LOGOFF: Final[int] = 433 +KEY_M: Final[int] = 50 +KEY_MACRO: Final[int] = 112 +KEY_MACRO1: Final[int] = 656 +KEY_MACRO10: Final[int] = 665 +KEY_MACRO11: Final[int] = 666 +KEY_MACRO12: Final[int] = 667 +KEY_MACRO13: Final[int] = 668 +KEY_MACRO14: Final[int] = 669 +KEY_MACRO15: Final[int] = 670 +KEY_MACRO16: Final[int] = 671 +KEY_MACRO17: Final[int] = 672 +KEY_MACRO18: Final[int] = 673 +KEY_MACRO19: Final[int] = 674 +KEY_MACRO2: Final[int] = 657 +KEY_MACRO20: Final[int] = 675 +KEY_MACRO21: Final[int] = 676 +KEY_MACRO22: Final[int] = 677 +KEY_MACRO23: Final[int] = 678 +KEY_MACRO24: Final[int] = 679 +KEY_MACRO25: Final[int] = 680 +KEY_MACRO26: Final[int] = 681 +KEY_MACRO27: Final[int] = 682 +KEY_MACRO28: Final[int] = 683 +KEY_MACRO29: Final[int] = 684 +KEY_MACRO3: Final[int] = 658 +KEY_MACRO30: Final[int] = 685 +KEY_MACRO4: Final[int] = 659 +KEY_MACRO5: Final[int] = 660 +KEY_MACRO6: Final[int] = 661 +KEY_MACRO7: Final[int] = 662 +KEY_MACRO8: Final[int] = 663 +KEY_MACRO9: Final[int] = 664 +KEY_MACRO_PRESET1: Final[int] = 691 +KEY_MACRO_PRESET2: Final[int] = 692 +KEY_MACRO_PRESET3: Final[int] = 693 +KEY_MACRO_PRESET_CYCLE: Final[int] = 690 +KEY_MACRO_RECORD_START: Final[int] = 688 +KEY_MACRO_RECORD_STOP: Final[int] = 689 +KEY_MAIL: Final[int] = 155 +KEY_MARK_WAYPOINT: Final[int] = 638 +KEY_MAX: Final[int] = 767 +KEY_MEDIA: Final[int] = 226 +KEY_MEDIA_REPEAT: Final[int] = 439 +KEY_MEDIA_TOP_MENU: Final[int] = 619 +KEY_MEMO: Final[int] = 396 +KEY_MENU: Final[int] = 139 +KEY_MESSENGER: Final[int] = 430 +KEY_MHP: Final[int] = 367 +KEY_MICMUTE: Final[int] = 248 +KEY_MINUS: Final[int] = 12 +KEY_MIN_INTERESTING: Final[int] = 113 +KEY_MODE: Final[int] = 373 +KEY_MOVE: Final[int] = 175 +KEY_MP3: Final[int] = 391 +KEY_MSDOS: Final[int] = 151 +KEY_MUHENKAN: Final[int] = 94 +KEY_MUTE: Final[int] = 113 +KEY_N: Final[int] = 49 +KEY_NAV_CHART: Final[int] = 640 +KEY_NAV_INFO: Final[int] = 648 +KEY_NEW: Final[int] = 181 +KEY_NEWS: Final[int] = 427 +KEY_NEXT: Final[int] = 407 +KEY_NEXTSONG: Final[int] = 163 +KEY_NEXT_ELEMENT: Final[int] = 635 +KEY_NEXT_FAVORITE: Final[int] = 624 +KEY_NOTIFICATION_CENTER: Final[int] = 444 +KEY_NUMERIC_0: Final[int] = 512 +KEY_NUMERIC_1: Final[int] = 513 +KEY_NUMERIC_11: Final[int] = 620 +KEY_NUMERIC_12: Final[int] = 621 +KEY_NUMERIC_2: Final[int] = 514 +KEY_NUMERIC_3: Final[int] = 515 +KEY_NUMERIC_4: Final[int] = 516 +KEY_NUMERIC_5: Final[int] = 517 +KEY_NUMERIC_6: Final[int] = 518 +KEY_NUMERIC_7: Final[int] = 519 +KEY_NUMERIC_8: Final[int] = 520 +KEY_NUMERIC_9: Final[int] = 521 +KEY_NUMERIC_A: Final[int] = 524 +KEY_NUMERIC_B: Final[int] = 525 +KEY_NUMERIC_C: Final[int] = 526 +KEY_NUMERIC_D: Final[int] = 527 +KEY_NUMERIC_POUND: Final[int] = 523 +KEY_NUMERIC_STAR: Final[int] = 522 +KEY_NUMLOCK: Final[int] = 69 +KEY_O: Final[int] = 24 +KEY_OK: Final[int] = 352 +KEY_ONSCREEN_KEYBOARD: Final[int] = 632 +KEY_OPEN: Final[int] = 134 +KEY_OPTION: Final[int] = 357 +KEY_P: Final[int] = 25 +KEY_PAGEDOWN: Final[int] = 109 +KEY_PAGEUP: Final[int] = 104 +KEY_PASTE: Final[int] = 135 +KEY_PAUSE: Final[int] = 119 +KEY_PAUSECD: Final[int] = 201 +KEY_PAUSE_RECORD: Final[int] = 626 +KEY_PC: Final[int] = 376 +KEY_PHONE: Final[int] = 169 +KEY_PICKUP_PHONE: Final[int] = 445 +KEY_PLAY: Final[int] = 207 +KEY_PLAYCD: Final[int] = 200 +KEY_PLAYER: Final[int] = 387 +KEY_PLAYPAUSE: Final[int] = 164 +KEY_POWER: Final[int] = 116 +KEY_POWER2: Final[int] = 356 +KEY_PRESENTATION: Final[int] = 425 +KEY_PREVIOUS: Final[int] = 412 +KEY_PREVIOUSSONG: Final[int] = 165 +KEY_PREVIOUS_ELEMENT: Final[int] = 636 +KEY_PRINT: Final[int] = 210 +KEY_PRIVACY_SCREEN_TOGGLE: Final[int] = 633 +KEY_PROG1: Final[int] = 148 +KEY_PROG2: Final[int] = 149 +KEY_PROG3: Final[int] = 202 +KEY_PROG4: Final[int] = 203 +KEY_PROGRAM: Final[int] = 362 +KEY_PROPS: Final[int] = 130 +KEY_PVR: Final[int] = 366 +KEY_Q: Final[int] = 16 +KEY_QUESTION: Final[int] = 214 +KEY_R: Final[int] = 19 +KEY_RADAR_OVERLAY: Final[int] = 644 +KEY_RADIO: Final[int] = 385 +KEY_RECORD: Final[int] = 167 +KEY_RED: Final[int] = 398 +KEY_REDO: Final[int] = 182 +KEY_REFRESH: Final[int] = 173 +KEY_REFRESH_RATE_TOGGLE: Final[int] = 562 +KEY_REPLY: Final[int] = 232 +KEY_RESERVED: Final[int] = 0 +KEY_RESTART: Final[int] = 408 +KEY_REWIND: Final[int] = 168 +KEY_RFKILL: Final[int] = 247 +KEY_RIGHT: Final[int] = 106 +KEY_RIGHTALT: Final[int] = 100 +KEY_RIGHTBRACE: Final[int] = 27 +KEY_RIGHTCTRL: Final[int] = 97 +KEY_RIGHTMETA: Final[int] = 126 +KEY_RIGHTSHIFT: Final[int] = 54 +KEY_RIGHT_DOWN: Final[int] = 615 +KEY_RIGHT_UP: Final[int] = 614 +KEY_RO: Final[int] = 89 +KEY_ROOT_MENU: Final[int] = 618 +KEY_ROTATE_DISPLAY: Final[int] = 153 +KEY_ROTATE_LOCK_TOGGLE: Final[int] = 561 +KEY_S: Final[int] = 31 +KEY_SAT: Final[int] = 381 +KEY_SAT2: Final[int] = 382 +KEY_SAVE: Final[int] = 234 +KEY_SCALE: Final[int] = 120 +KEY_SCREEN: Final[int] = 375 +KEY_SCREENLOCK: Final[int] = 152 +KEY_SCREENSAVER: Final[int] = 581 +KEY_SCROLLDOWN: Final[int] = 178 +KEY_SCROLLLOCK: Final[int] = 70 +KEY_SCROLLUP: Final[int] = 177 +KEY_SEARCH: Final[int] = 217 +KEY_SELECT: Final[int] = 353 +KEY_SELECTIVE_SCREENSHOT: Final[int] = 634 +KEY_SEMICOLON: Final[int] = 39 +KEY_SEND: Final[int] = 231 +KEY_SENDFILE: Final[int] = 145 +KEY_SETUP: Final[int] = 141 +KEY_SHOP: Final[int] = 221 +KEY_SHUFFLE: Final[int] = 410 +KEY_SIDEVU_SONAR: Final[int] = 647 +KEY_SINGLE_RANGE_RADAR: Final[int] = 642 +KEY_SLASH: Final[int] = 53 +KEY_SLEEP: Final[int] = 142 +KEY_SLOW: Final[int] = 409 +KEY_SLOWREVERSE: Final[int] = 630 +KEY_SOS: Final[int] = 639 +KEY_SOUND: Final[int] = 213 +KEY_SPACE: Final[int] = 57 +KEY_SPELLCHECK: Final[int] = 432 +KEY_SPORT: Final[int] = 220 +KEY_SPREADSHEET: Final[int] = 423 +KEY_STOP: Final[int] = 128 +KEY_STOPCD: Final[int] = 166 +KEY_STOP_RECORD: Final[int] = 625 +KEY_SUBTITLE: Final[int] = 370 +KEY_SUSPEND: Final[int] = 205 +KEY_SWITCHVIDEOMODE: Final[int] = 227 +KEY_SYSRQ: Final[int] = 99 +KEY_T: Final[int] = 20 +KEY_TAB: Final[int] = 15 +KEY_TAPE: Final[int] = 384 +KEY_TASKMANAGER: Final[int] = 577 +KEY_TEEN: Final[int] = 414 +KEY_TEXT: Final[int] = 388 +KEY_TIME: Final[int] = 359 +KEY_TITLE: Final[int] = 369 +KEY_TOUCHPAD_OFF: Final[int] = 532 +KEY_TOUCHPAD_ON: Final[int] = 531 +KEY_TOUCHPAD_TOGGLE: Final[int] = 530 +KEY_TRADITIONAL_SONAR: Final[int] = 645 +KEY_TUNER: Final[int] = 386 +KEY_TV: Final[int] = 377 +KEY_TV2: Final[int] = 378 +KEY_TWEN: Final[int] = 415 +KEY_U: Final[int] = 22 +KEY_UNDO: Final[int] = 131 +KEY_UNKNOWN: Final[int] = 240 +KEY_UNMUTE: Final[int] = 628 +KEY_UP: Final[int] = 103 +KEY_UWB: Final[int] = 239 +KEY_V: Final[int] = 47 +KEY_VCR: Final[int] = 379 +KEY_VCR2: Final[int] = 380 +KEY_VENDOR: Final[int] = 360 +KEY_VIDEO: Final[int] = 393 +KEY_VIDEOPHONE: Final[int] = 416 +KEY_VIDEO_NEXT: Final[int] = 241 +KEY_VIDEO_PREV: Final[int] = 242 +KEY_VOD: Final[int] = 627 +KEY_VOICECOMMAND: Final[int] = 582 +KEY_VOICEMAIL: Final[int] = 428 +KEY_VOLUMEDOWN: Final[int] = 114 +KEY_VOLUMEUP: Final[int] = 115 +KEY_W: Final[int] = 17 +KEY_WAKEUP: Final[int] = 143 +KEY_WIMAX: Final[int] = 246 +KEY_WLAN: Final[int] = 238 +KEY_WORDPROCESSOR: Final[int] = 421 +KEY_WPS_BUTTON: Final[int] = 529 +KEY_WWAN: Final[int] = 246 +KEY_WWW: Final[int] = 150 +KEY_X: Final[int] = 45 +KEY_XFER: Final[int] = 147 +KEY_Y: Final[int] = 21 +KEY_YELLOW: Final[int] = 400 +KEY_YEN: Final[int] = 124 +KEY_Z: Final[int] = 44 +KEY_ZENKAKUHANKAKU: Final[int] = 85 +KEY_ZOOM: Final[int] = 372 +KEY_ZOOMIN: Final[int] = 418 +KEY_ZOOMOUT: Final[int] = 419 +KEY_ZOOMRESET: Final[int] = 420 +LED_CAPSL: Final[int] = 1 +LED_CHARGING: Final[int] = 10 +LED_CNT: Final[int] = 16 +LED_COMPOSE: Final[int] = 3 +LED_KANA: Final[int] = 4 +LED_MAIL: Final[int] = 9 +LED_MAX: Final[int] = 15 +LED_MISC: Final[int] = 8 +LED_MUTE: Final[int] = 7 +LED_NUML: Final[int] = 0 +LED_SCROLLL: Final[int] = 2 +LED_SLEEP: Final[int] = 5 +LED_SUSPEND: Final[int] = 6 +MSC_CNT: Final[int] = 8 +MSC_GESTURE: Final[int] = 2 +MSC_MAX: Final[int] = 7 +MSC_PULSELED: Final[int] = 1 +MSC_RAW: Final[int] = 3 +MSC_SCAN: Final[int] = 4 +MSC_SERIAL: Final[int] = 0 +MSC_TIMESTAMP: Final[int] = 5 +REL_CNT: Final[int] = 16 +REL_DIAL: Final[int] = 7 +REL_HWHEEL: Final[int] = 6 +REL_HWHEEL_HI_RES: Final[int] = 12 +REL_MAX: Final[int] = 15 +REL_MISC: Final[int] = 9 +REL_RESERVED: Final[int] = 10 +REL_RX: Final[int] = 3 +REL_RY: Final[int] = 4 +REL_RZ: Final[int] = 5 +REL_WHEEL: Final[int] = 8 +REL_WHEEL_HI_RES: Final[int] = 11 +REL_X: Final[int] = 0 +REL_Y: Final[int] = 1 +REL_Z: Final[int] = 2 +REP_CNT: Final[int] = 2 +REP_DELAY: Final[int] = 0 +REP_MAX: Final[int] = 1 +REP_PERIOD: Final[int] = 1 +SND_BELL: Final[int] = 1 +SND_CLICK: Final[int] = 0 +SND_CNT: Final[int] = 8 +SND_MAX: Final[int] = 7 +SND_TONE: Final[int] = 2 +SW_CAMERA_LENS_COVER: Final[int] = 9 +SW_CNT: Final[int] = 17 +SW_DOCK: Final[int] = 5 +SW_FRONT_PROXIMITY: Final[int] = 11 +SW_HEADPHONE_INSERT: Final[int] = 2 +SW_JACK_PHYSICAL_INSERT: Final[int] = 7 +SW_KEYPAD_SLIDE: Final[int] = 10 +SW_LID: Final[int] = 0 +SW_LINEIN_INSERT: Final[int] = 13 +SW_LINEOUT_INSERT: Final[int] = 6 +SW_MACHINE_COVER: Final[int] = 16 +SW_MAX: Final[int] = 16 +SW_MICROPHONE_INSERT: Final[int] = 4 +SW_MUTE_DEVICE: Final[int] = 14 +SW_PEN_INSERTED: Final[int] = 15 +SW_RADIO: Final[int] = 3 +SW_RFKILL_ALL: Final[int] = 3 +SW_ROTATE_LOCK: Final[int] = 12 +SW_TABLET_MODE: Final[int] = 1 +SW_VIDEOOUT_INSERT: Final[int] = 8 +SYN_CNT: Final[int] = 16 +SYN_CONFIG: Final[int] = 1 +SYN_DROPPED: Final[int] = 3 +SYN_MAX: Final[int] = 15 +SYN_MT_REPORT: Final[int] = 2 +SYN_REPORT: Final[int] = 0 +UI_FF_ERASE: Final[int] = 2 +UI_FF_UPLOAD: Final[int] = 1 + +#: Mapping of names to values. +ecodes: Dict[str, int] = { 'ABS_BRAKE': 10, + 'ABS_CNT': 64, + 'ABS_DISTANCE': 25, + 'ABS_GAS': 9, + 'ABS_HAT0X': 16, + 'ABS_HAT0Y': 17, + 'ABS_HAT1X': 18, + 'ABS_HAT1Y': 19, + 'ABS_HAT2X': 20, + 'ABS_HAT2Y': 21, + 'ABS_HAT3X': 22, + 'ABS_HAT3Y': 23, + 'ABS_MAX': 63, + 'ABS_MISC': 40, + 'ABS_MT_BLOB_ID': 56, + 'ABS_MT_DISTANCE': 59, + 'ABS_MT_ORIENTATION': 52, + 'ABS_MT_POSITION_X': 53, + 'ABS_MT_POSITION_Y': 54, + 'ABS_MT_PRESSURE': 58, + 'ABS_MT_SLOT': 47, + 'ABS_MT_TOOL_TYPE': 55, + 'ABS_MT_TOOL_X': 60, + 'ABS_MT_TOOL_Y': 61, + 'ABS_MT_TOUCH_MAJOR': 48, + 'ABS_MT_TOUCH_MINOR': 49, + 'ABS_MT_TRACKING_ID': 57, + 'ABS_MT_WIDTH_MAJOR': 50, + 'ABS_MT_WIDTH_MINOR': 51, + 'ABS_PRESSURE': 24, + 'ABS_PROFILE': 33, + 'ABS_RESERVED': 46, + 'ABS_RUDDER': 7, + 'ABS_RX': 3, + 'ABS_RY': 4, + 'ABS_RZ': 5, + 'ABS_THROTTLE': 6, + 'ABS_TILT_X': 26, + 'ABS_TILT_Y': 27, + 'ABS_TOOL_WIDTH': 28, + 'ABS_VOLUME': 32, + 'ABS_WHEEL': 8, + 'ABS_X': 0, + 'ABS_Y': 1, + 'ABS_Z': 2, + 'BTN_0': 256, + 'BTN_1': 257, + 'BTN_2': 258, + 'BTN_3': 259, + 'BTN_4': 260, + 'BTN_5': 261, + 'BTN_6': 262, + 'BTN_7': 263, + 'BTN_8': 264, + 'BTN_9': 265, + 'BTN_A': 304, + 'BTN_B': 305, + 'BTN_BACK': 278, + 'BTN_BASE': 294, + 'BTN_BASE2': 295, + 'BTN_BASE3': 296, + 'BTN_BASE4': 297, + 'BTN_BASE5': 298, + 'BTN_BASE6': 299, + 'BTN_C': 306, + 'BTN_DEAD': 303, + 'BTN_DIGI': 320, + 'BTN_DPAD_DOWN': 545, + 'BTN_DPAD_LEFT': 546, + 'BTN_DPAD_RIGHT': 547, + 'BTN_DPAD_UP': 544, + 'BTN_EAST': 305, + 'BTN_EXTRA': 276, + 'BTN_FORWARD': 277, + 'BTN_GAMEPAD': 304, + 'BTN_GEAR_DOWN': 336, + 'BTN_GEAR_UP': 337, + 'BTN_JOYSTICK': 288, + 'BTN_LEFT': 272, + 'BTN_MIDDLE': 274, + 'BTN_MISC': 256, + 'BTN_MODE': 316, + 'BTN_MOUSE': 272, + 'BTN_NORTH': 307, + 'BTN_PINKIE': 293, + 'BTN_RIGHT': 273, + 'BTN_SELECT': 314, + 'BTN_SIDE': 275, + 'BTN_SOUTH': 304, + 'BTN_START': 315, + 'BTN_STYLUS': 331, + 'BTN_STYLUS2': 332, + 'BTN_STYLUS3': 329, + 'BTN_TASK': 279, + 'BTN_THUMB': 289, + 'BTN_THUMB2': 290, + 'BTN_THUMBL': 317, + 'BTN_THUMBR': 318, + 'BTN_TL': 310, + 'BTN_TL2': 312, + 'BTN_TOOL_AIRBRUSH': 324, + 'BTN_TOOL_BRUSH': 322, + 'BTN_TOOL_DOUBLETAP': 333, + 'BTN_TOOL_FINGER': 325, + 'BTN_TOOL_LENS': 327, + 'BTN_TOOL_MOUSE': 326, + 'BTN_TOOL_PEN': 320, + 'BTN_TOOL_PENCIL': 323, + 'BTN_TOOL_QUADTAP': 335, + 'BTN_TOOL_QUINTTAP': 328, + 'BTN_TOOL_RUBBER': 321, + 'BTN_TOOL_TRIPLETAP': 334, + 'BTN_TOP': 291, + 'BTN_TOP2': 292, + 'BTN_TOUCH': 330, + 'BTN_TR': 311, + 'BTN_TR2': 313, + 'BTN_TRIGGER': 288, + 'BTN_TRIGGER_HAPPY': 704, + 'BTN_TRIGGER_HAPPY1': 704, + 'BTN_TRIGGER_HAPPY10': 713, + 'BTN_TRIGGER_HAPPY11': 714, + 'BTN_TRIGGER_HAPPY12': 715, + 'BTN_TRIGGER_HAPPY13': 716, + 'BTN_TRIGGER_HAPPY14': 717, + 'BTN_TRIGGER_HAPPY15': 718, + 'BTN_TRIGGER_HAPPY16': 719, + 'BTN_TRIGGER_HAPPY17': 720, + 'BTN_TRIGGER_HAPPY18': 721, + 'BTN_TRIGGER_HAPPY19': 722, + 'BTN_TRIGGER_HAPPY2': 705, + 'BTN_TRIGGER_HAPPY20': 723, + 'BTN_TRIGGER_HAPPY21': 724, + 'BTN_TRIGGER_HAPPY22': 725, + 'BTN_TRIGGER_HAPPY23': 726, + 'BTN_TRIGGER_HAPPY24': 727, + 'BTN_TRIGGER_HAPPY25': 728, + 'BTN_TRIGGER_HAPPY26': 729, + 'BTN_TRIGGER_HAPPY27': 730, + 'BTN_TRIGGER_HAPPY28': 731, + 'BTN_TRIGGER_HAPPY29': 732, + 'BTN_TRIGGER_HAPPY3': 706, + 'BTN_TRIGGER_HAPPY30': 733, + 'BTN_TRIGGER_HAPPY31': 734, + 'BTN_TRIGGER_HAPPY32': 735, + 'BTN_TRIGGER_HAPPY33': 736, + 'BTN_TRIGGER_HAPPY34': 737, + 'BTN_TRIGGER_HAPPY35': 738, + 'BTN_TRIGGER_HAPPY36': 739, + 'BTN_TRIGGER_HAPPY37': 740, + 'BTN_TRIGGER_HAPPY38': 741, + 'BTN_TRIGGER_HAPPY39': 742, + 'BTN_TRIGGER_HAPPY4': 707, + 'BTN_TRIGGER_HAPPY40': 743, + 'BTN_TRIGGER_HAPPY5': 708, + 'BTN_TRIGGER_HAPPY6': 709, + 'BTN_TRIGGER_HAPPY7': 710, + 'BTN_TRIGGER_HAPPY8': 711, + 'BTN_TRIGGER_HAPPY9': 712, + 'BTN_WEST': 308, + 'BTN_WHEEL': 336, + 'BTN_X': 307, + 'BTN_Y': 308, + 'BTN_Z': 309, + 'BUS_ADB': 23, + 'BUS_AMD_SFH': 32, + 'BUS_AMIGA': 22, + 'BUS_ATARI': 27, + 'BUS_BLUETOOTH': 5, + 'BUS_CEC': 30, + 'BUS_GAMEPORT': 20, + 'BUS_GSC': 26, + 'BUS_HIL': 4, + 'BUS_HOST': 25, + 'BUS_I2C': 24, + 'BUS_I8042': 17, + 'BUS_INTEL_ISHTP': 31, + 'BUS_ISA': 16, + 'BUS_ISAPNP': 2, + 'BUS_PARPORT': 21, + 'BUS_PCI': 1, + 'BUS_RMI': 29, + 'BUS_RS232': 19, + 'BUS_SPI': 28, + 'BUS_USB': 3, + 'BUS_VIRTUAL': 6, + 'BUS_XTKBD': 18, + 'EV_ABS': 3, + 'EV_CNT': 32, + 'EV_FF': 21, + 'EV_FF_STATUS': 23, + 'EV_KEY': 1, + 'EV_LED': 17, + 'EV_MAX': 31, + 'EV_MSC': 4, + 'EV_PWR': 22, + 'EV_REL': 2, + 'EV_REP': 20, + 'EV_SND': 18, + 'EV_SW': 5, + 'EV_SYN': 0, + 'EV_UINPUT': 257, + 'EV_VERSION': 65537, + 'FF_AUTOCENTER': 97, + 'FF_CNT': 128, + 'FF_CONSTANT': 82, + 'FF_CUSTOM': 93, + 'FF_DAMPER': 85, + 'FF_EFFECT_MAX': 87, + 'FF_EFFECT_MIN': 80, + 'FF_FRICTION': 84, + 'FF_GAIN': 96, + 'FF_INERTIA': 86, + 'FF_MAX': 127, + 'FF_MAX_EFFECTS': 96, + 'FF_PERIODIC': 81, + 'FF_RAMP': 87, + 'FF_RUMBLE': 80, + 'FF_SAW_DOWN': 92, + 'FF_SAW_UP': 91, + 'FF_SINE': 90, + 'FF_SPRING': 83, + 'FF_SQUARE': 88, + 'FF_STATUS_MAX': 1, + 'FF_STATUS_PLAYING': 1, + 'FF_STATUS_STOPPED': 0, + 'FF_TRIANGLE': 89, + 'FF_WAVEFORM_MAX': 93, + 'FF_WAVEFORM_MIN': 88, + 'ID_BUS': 0, + 'ID_PRODUCT': 2, + 'ID_VENDOR': 1, + 'ID_VERSION': 3, + 'INPUT_PROP_ACCELEROMETER': 6, + 'INPUT_PROP_BUTTONPAD': 2, + 'INPUT_PROP_CNT': 32, + 'INPUT_PROP_DIRECT': 1, + 'INPUT_PROP_MAX': 31, + 'INPUT_PROP_POINTER': 0, + 'INPUT_PROP_POINTING_STICK': 5, + 'INPUT_PROP_SEMI_MT': 3, + 'INPUT_PROP_TOPBUTTONPAD': 4, + 'KEY_0': 11, + 'KEY_1': 2, + 'KEY_102ND': 86, + 'KEY_10CHANNELSDOWN': 441, + 'KEY_10CHANNELSUP': 440, + 'KEY_2': 3, + 'KEY_3': 4, + 'KEY_3D_MODE': 623, + 'KEY_4': 5, + 'KEY_5': 6, + 'KEY_6': 7, + 'KEY_7': 8, + 'KEY_8': 9, + 'KEY_9': 10, + 'KEY_A': 30, + 'KEY_AB': 406, + 'KEY_ACCESSIBILITY': 590, + 'KEY_ADDRESSBOOK': 429, + 'KEY_AGAIN': 129, + 'KEY_ALL_APPLICATIONS': 204, + 'KEY_ALS_TOGGLE': 560, + 'KEY_ALTERASE': 222, + 'KEY_ANGLE': 371, + 'KEY_APOSTROPHE': 40, + 'KEY_APPSELECT': 580, + 'KEY_ARCHIVE': 361, + 'KEY_ASPECT_RATIO': 375, + 'KEY_ASSISTANT': 583, + 'KEY_ATTENDANT_OFF': 540, + 'KEY_ATTENDANT_ON': 539, + 'KEY_ATTENDANT_TOGGLE': 541, + 'KEY_AUDIO': 392, + 'KEY_AUDIO_DESC': 622, + 'KEY_AUTOPILOT_ENGAGE_TOGGLE': 637, + 'KEY_AUX': 390, + 'KEY_B': 48, + 'KEY_BACK': 158, + 'KEY_BACKSLASH': 43, + 'KEY_BACKSPACE': 14, + 'KEY_BASSBOOST': 209, + 'KEY_BATTERY': 236, + 'KEY_BLUE': 401, + 'KEY_BLUETOOTH': 237, + 'KEY_BOOKMARKS': 156, + 'KEY_BREAK': 411, + 'KEY_BRIGHTNESSDOWN': 224, + 'KEY_BRIGHTNESSUP': 225, + 'KEY_BRIGHTNESS_AUTO': 244, + 'KEY_BRIGHTNESS_CYCLE': 243, + 'KEY_BRIGHTNESS_MAX': 593, + 'KEY_BRIGHTNESS_MENU': 649, + 'KEY_BRIGHTNESS_MIN': 592, + 'KEY_BRIGHTNESS_TOGGLE': 431, + 'KEY_BRIGHTNESS_ZERO': 244, + 'KEY_BRL_DOT1': 497, + 'KEY_BRL_DOT10': 506, + 'KEY_BRL_DOT2': 498, + 'KEY_BRL_DOT3': 499, + 'KEY_BRL_DOT4': 500, + 'KEY_BRL_DOT5': 501, + 'KEY_BRL_DOT6': 502, + 'KEY_BRL_DOT7': 503, + 'KEY_BRL_DOT8': 504, + 'KEY_BRL_DOT9': 505, + 'KEY_BUTTONCONFIG': 576, + 'KEY_C': 46, + 'KEY_CALC': 140, + 'KEY_CALENDAR': 397, + 'KEY_CAMERA': 212, + 'KEY_CAMERA_ACCESS_DISABLE': 588, + 'KEY_CAMERA_ACCESS_ENABLE': 587, + 'KEY_CAMERA_ACCESS_TOGGLE': 589, + 'KEY_CAMERA_DOWN': 536, + 'KEY_CAMERA_FOCUS': 528, + 'KEY_CAMERA_LEFT': 537, + 'KEY_CAMERA_RIGHT': 538, + 'KEY_CAMERA_UP': 535, + 'KEY_CAMERA_ZOOMIN': 533, + 'KEY_CAMERA_ZOOMOUT': 534, + 'KEY_CANCEL': 223, + 'KEY_CAPSLOCK': 58, + 'KEY_CD': 383, + 'KEY_CHANNEL': 363, + 'KEY_CHANNELDOWN': 403, + 'KEY_CHANNELUP': 402, + 'KEY_CHAT': 216, + 'KEY_CLEAR': 355, + 'KEY_CLEARVU_SONAR': 646, + 'KEY_CLOSE': 206, + 'KEY_CLOSECD': 160, + 'KEY_CNT': 768, + 'KEY_COFFEE': 152, + 'KEY_COMMA': 51, + 'KEY_COMPOSE': 127, + 'KEY_COMPUTER': 157, + 'KEY_CONFIG': 171, + 'KEY_CONNECT': 218, + 'KEY_CONTEXT_MENU': 438, + 'KEY_CONTROLPANEL': 579, + 'KEY_COPY': 133, + 'KEY_CUT': 137, + 'KEY_CYCLEWINDOWS': 154, + 'KEY_D': 32, + 'KEY_DASHBOARD': 204, + 'KEY_DATA': 631, + 'KEY_DATABASE': 426, + 'KEY_DELETE': 111, + 'KEY_DELETEFILE': 146, + 'KEY_DEL_EOL': 448, + 'KEY_DEL_EOS': 449, + 'KEY_DEL_LINE': 451, + 'KEY_DICTATE': 586, + 'KEY_DIGITS': 413, + 'KEY_DIRECTION': 153, + 'KEY_DIRECTORY': 394, + 'KEY_DISPLAYTOGGLE': 431, + 'KEY_DISPLAY_OFF': 245, + 'KEY_DOCUMENTS': 235, + 'KEY_DOLLAR': 434, + 'KEY_DOT': 52, + 'KEY_DOWN': 108, + 'KEY_DO_NOT_DISTURB': 591, + 'KEY_DUAL_RANGE_RADAR': 643, + 'KEY_DVD': 389, + 'KEY_E': 18, + 'KEY_EDIT': 176, + 'KEY_EDITOR': 422, + 'KEY_EJECTCD': 161, + 'KEY_EJECTCLOSECD': 162, + 'KEY_EMAIL': 215, + 'KEY_EMOJI_PICKER': 585, + 'KEY_END': 107, + 'KEY_ENTER': 28, + 'KEY_EPG': 365, + 'KEY_EQUAL': 13, + 'KEY_ESC': 1, + 'KEY_EURO': 435, + 'KEY_EXIT': 174, + 'KEY_F': 33, + 'KEY_F1': 59, + 'KEY_F10': 68, + 'KEY_F11': 87, + 'KEY_F12': 88, + 'KEY_F13': 183, + 'KEY_F14': 184, + 'KEY_F15': 185, + 'KEY_F16': 186, + 'KEY_F17': 187, + 'KEY_F18': 188, + 'KEY_F19': 189, + 'KEY_F2': 60, + 'KEY_F20': 190, + 'KEY_F21': 191, + 'KEY_F22': 192, + 'KEY_F23': 193, + 'KEY_F24': 194, + 'KEY_F3': 61, + 'KEY_F4': 62, + 'KEY_F5': 63, + 'KEY_F6': 64, + 'KEY_F7': 65, + 'KEY_F8': 66, + 'KEY_F9': 67, + 'KEY_FASTFORWARD': 208, + 'KEY_FASTREVERSE': 629, + 'KEY_FAVORITES': 364, + 'KEY_FILE': 144, + 'KEY_FINANCE': 219, + 'KEY_FIND': 136, + 'KEY_FIRST': 404, + 'KEY_FISHING_CHART': 641, + 'KEY_FN': 464, + 'KEY_FN_1': 478, + 'KEY_FN_2': 479, + 'KEY_FN_B': 484, + 'KEY_FN_D': 480, + 'KEY_FN_E': 481, + 'KEY_FN_ESC': 465, + 'KEY_FN_F': 482, + 'KEY_FN_F1': 466, + 'KEY_FN_F10': 475, + 'KEY_FN_F11': 476, + 'KEY_FN_F12': 477, + 'KEY_FN_F2': 467, + 'KEY_FN_F3': 468, + 'KEY_FN_F4': 469, + 'KEY_FN_F5': 470, + 'KEY_FN_F6': 471, + 'KEY_FN_F7': 472, + 'KEY_FN_F8': 473, + 'KEY_FN_F9': 474, + 'KEY_FN_RIGHT_SHIFT': 485, + 'KEY_FN_S': 483, + 'KEY_FORWARD': 159, + 'KEY_FORWARDMAIL': 233, + 'KEY_FRAMEBACK': 436, + 'KEY_FRAMEFORWARD': 437, + 'KEY_FRONT': 132, + 'KEY_FULL_SCREEN': 372, + 'KEY_G': 34, + 'KEY_GAMES': 417, + 'KEY_GOTO': 354, + 'KEY_GRAPHICSEDITOR': 424, + 'KEY_GRAVE': 41, + 'KEY_GREEN': 399, + 'KEY_H': 35, + 'KEY_HANGEUL': 122, + 'KEY_HANGUEL': 122, + 'KEY_HANGUP_PHONE': 446, + 'KEY_HANJA': 123, + 'KEY_HELP': 138, + 'KEY_HENKAN': 92, + 'KEY_HIRAGANA': 91, + 'KEY_HOME': 102, + 'KEY_HOMEPAGE': 172, + 'KEY_HP': 211, + 'KEY_I': 23, + 'KEY_IMAGES': 442, + 'KEY_INFO': 358, + 'KEY_INSERT': 110, + 'KEY_INS_LINE': 450, + 'KEY_ISO': 170, + 'KEY_J': 36, + 'KEY_JOURNAL': 578, + 'KEY_K': 37, + 'KEY_KATAKANA': 90, + 'KEY_KATAKANAHIRAGANA': 93, + 'KEY_KBDILLUMDOWN': 229, + 'KEY_KBDILLUMTOGGLE': 228, + 'KEY_KBDILLUMUP': 230, + 'KEY_KBDINPUTASSIST_ACCEPT': 612, + 'KEY_KBDINPUTASSIST_CANCEL': 613, + 'KEY_KBDINPUTASSIST_NEXT': 609, + 'KEY_KBDINPUTASSIST_NEXTGROUP': 611, + 'KEY_KBDINPUTASSIST_PREV': 608, + 'KEY_KBDINPUTASSIST_PREVGROUP': 610, + 'KEY_KBD_LAYOUT_NEXT': 584, + 'KEY_KBD_LCD_MENU1': 696, + 'KEY_KBD_LCD_MENU2': 697, + 'KEY_KBD_LCD_MENU3': 698, + 'KEY_KBD_LCD_MENU4': 699, + 'KEY_KBD_LCD_MENU5': 700, + 'KEY_KEYBOARD': 374, + 'KEY_KP0': 82, + 'KEY_KP1': 79, + 'KEY_KP2': 80, + 'KEY_KP3': 81, + 'KEY_KP4': 75, + 'KEY_KP5': 76, + 'KEY_KP6': 77, + 'KEY_KP7': 71, + 'KEY_KP8': 72, + 'KEY_KP9': 73, + 'KEY_KPASTERISK': 55, + 'KEY_KPCOMMA': 121, + 'KEY_KPDOT': 83, + 'KEY_KPENTER': 96, + 'KEY_KPEQUAL': 117, + 'KEY_KPJPCOMMA': 95, + 'KEY_KPLEFTPAREN': 179, + 'KEY_KPMINUS': 74, + 'KEY_KPPLUS': 78, + 'KEY_KPPLUSMINUS': 118, + 'KEY_KPRIGHTPAREN': 180, + 'KEY_KPSLASH': 98, + 'KEY_L': 38, + 'KEY_LANGUAGE': 368, + 'KEY_LAST': 405, + 'KEY_LEFT': 105, + 'KEY_LEFTALT': 56, + 'KEY_LEFTBRACE': 26, + 'KEY_LEFTCTRL': 29, + 'KEY_LEFTMETA': 125, + 'KEY_LEFTSHIFT': 42, + 'KEY_LEFT_DOWN': 617, + 'KEY_LEFT_UP': 616, + 'KEY_LIGHTS_TOGGLE': 542, + 'KEY_LINEFEED': 101, + 'KEY_LINK_PHONE': 447, + 'KEY_LIST': 395, + 'KEY_LOGOFF': 433, + 'KEY_M': 50, + 'KEY_MACRO': 112, + 'KEY_MACRO1': 656, + 'KEY_MACRO10': 665, + 'KEY_MACRO11': 666, + 'KEY_MACRO12': 667, + 'KEY_MACRO13': 668, + 'KEY_MACRO14': 669, + 'KEY_MACRO15': 670, + 'KEY_MACRO16': 671, + 'KEY_MACRO17': 672, + 'KEY_MACRO18': 673, + 'KEY_MACRO19': 674, + 'KEY_MACRO2': 657, + 'KEY_MACRO20': 675, + 'KEY_MACRO21': 676, + 'KEY_MACRO22': 677, + 'KEY_MACRO23': 678, + 'KEY_MACRO24': 679, + 'KEY_MACRO25': 680, + 'KEY_MACRO26': 681, + 'KEY_MACRO27': 682, + 'KEY_MACRO28': 683, + 'KEY_MACRO29': 684, + 'KEY_MACRO3': 658, + 'KEY_MACRO30': 685, + 'KEY_MACRO4': 659, + 'KEY_MACRO5': 660, + 'KEY_MACRO6': 661, + 'KEY_MACRO7': 662, + 'KEY_MACRO8': 663, + 'KEY_MACRO9': 664, + 'KEY_MACRO_PRESET1': 691, + 'KEY_MACRO_PRESET2': 692, + 'KEY_MACRO_PRESET3': 693, + 'KEY_MACRO_PRESET_CYCLE': 690, + 'KEY_MACRO_RECORD_START': 688, + 'KEY_MACRO_RECORD_STOP': 689, + 'KEY_MAIL': 155, + 'KEY_MARK_WAYPOINT': 638, + 'KEY_MAX': 767, + 'KEY_MEDIA': 226, + 'KEY_MEDIA_REPEAT': 439, + 'KEY_MEDIA_TOP_MENU': 619, + 'KEY_MEMO': 396, + 'KEY_MENU': 139, + 'KEY_MESSENGER': 430, + 'KEY_MHP': 367, + 'KEY_MICMUTE': 248, + 'KEY_MINUS': 12, + 'KEY_MIN_INTERESTING': 113, + 'KEY_MODE': 373, + 'KEY_MOVE': 175, + 'KEY_MP3': 391, + 'KEY_MSDOS': 151, + 'KEY_MUHENKAN': 94, + 'KEY_MUTE': 113, + 'KEY_N': 49, + 'KEY_NAV_CHART': 640, + 'KEY_NAV_INFO': 648, + 'KEY_NEW': 181, + 'KEY_NEWS': 427, + 'KEY_NEXT': 407, + 'KEY_NEXTSONG': 163, + 'KEY_NEXT_ELEMENT': 635, + 'KEY_NEXT_FAVORITE': 624, + 'KEY_NOTIFICATION_CENTER': 444, + 'KEY_NUMERIC_0': 512, + 'KEY_NUMERIC_1': 513, + 'KEY_NUMERIC_11': 620, + 'KEY_NUMERIC_12': 621, + 'KEY_NUMERIC_2': 514, + 'KEY_NUMERIC_3': 515, + 'KEY_NUMERIC_4': 516, + 'KEY_NUMERIC_5': 517, + 'KEY_NUMERIC_6': 518, + 'KEY_NUMERIC_7': 519, + 'KEY_NUMERIC_8': 520, + 'KEY_NUMERIC_9': 521, + 'KEY_NUMERIC_A': 524, + 'KEY_NUMERIC_B': 525, + 'KEY_NUMERIC_C': 526, + 'KEY_NUMERIC_D': 527, + 'KEY_NUMERIC_POUND': 523, + 'KEY_NUMERIC_STAR': 522, + 'KEY_NUMLOCK': 69, + 'KEY_O': 24, + 'KEY_OK': 352, + 'KEY_ONSCREEN_KEYBOARD': 632, + 'KEY_OPEN': 134, + 'KEY_OPTION': 357, + 'KEY_P': 25, + 'KEY_PAGEDOWN': 109, + 'KEY_PAGEUP': 104, + 'KEY_PASTE': 135, + 'KEY_PAUSE': 119, + 'KEY_PAUSECD': 201, + 'KEY_PAUSE_RECORD': 626, + 'KEY_PC': 376, + 'KEY_PHONE': 169, + 'KEY_PICKUP_PHONE': 445, + 'KEY_PLAY': 207, + 'KEY_PLAYCD': 200, + 'KEY_PLAYER': 387, + 'KEY_PLAYPAUSE': 164, + 'KEY_POWER': 116, + 'KEY_POWER2': 356, + 'KEY_PRESENTATION': 425, + 'KEY_PREVIOUS': 412, + 'KEY_PREVIOUSSONG': 165, + 'KEY_PREVIOUS_ELEMENT': 636, + 'KEY_PRINT': 210, + 'KEY_PRIVACY_SCREEN_TOGGLE': 633, + 'KEY_PROG1': 148, + 'KEY_PROG2': 149, + 'KEY_PROG3': 202, + 'KEY_PROG4': 203, + 'KEY_PROGRAM': 362, + 'KEY_PROPS': 130, + 'KEY_PVR': 366, + 'KEY_Q': 16, + 'KEY_QUESTION': 214, + 'KEY_R': 19, + 'KEY_RADAR_OVERLAY': 644, + 'KEY_RADIO': 385, + 'KEY_RECORD': 167, + 'KEY_RED': 398, + 'KEY_REDO': 182, + 'KEY_REFRESH': 173, + 'KEY_REFRESH_RATE_TOGGLE': 562, + 'KEY_REPLY': 232, + 'KEY_RESERVED': 0, + 'KEY_RESTART': 408, + 'KEY_REWIND': 168, + 'KEY_RFKILL': 247, + 'KEY_RIGHT': 106, + 'KEY_RIGHTALT': 100, + 'KEY_RIGHTBRACE': 27, + 'KEY_RIGHTCTRL': 97, + 'KEY_RIGHTMETA': 126, + 'KEY_RIGHTSHIFT': 54, + 'KEY_RIGHT_DOWN': 615, + 'KEY_RIGHT_UP': 614, + 'KEY_RO': 89, + 'KEY_ROOT_MENU': 618, + 'KEY_ROTATE_DISPLAY': 153, + 'KEY_ROTATE_LOCK_TOGGLE': 561, + 'KEY_S': 31, + 'KEY_SAT': 381, + 'KEY_SAT2': 382, + 'KEY_SAVE': 234, + 'KEY_SCALE': 120, + 'KEY_SCREEN': 375, + 'KEY_SCREENLOCK': 152, + 'KEY_SCREENSAVER': 581, + 'KEY_SCROLLDOWN': 178, + 'KEY_SCROLLLOCK': 70, + 'KEY_SCROLLUP': 177, + 'KEY_SEARCH': 217, + 'KEY_SELECT': 353, + 'KEY_SELECTIVE_SCREENSHOT': 634, + 'KEY_SEMICOLON': 39, + 'KEY_SEND': 231, + 'KEY_SENDFILE': 145, + 'KEY_SETUP': 141, + 'KEY_SHOP': 221, + 'KEY_SHUFFLE': 410, + 'KEY_SIDEVU_SONAR': 647, + 'KEY_SINGLE_RANGE_RADAR': 642, + 'KEY_SLASH': 53, + 'KEY_SLEEP': 142, + 'KEY_SLOW': 409, + 'KEY_SLOWREVERSE': 630, + 'KEY_SOS': 639, + 'KEY_SOUND': 213, + 'KEY_SPACE': 57, + 'KEY_SPELLCHECK': 432, + 'KEY_SPORT': 220, + 'KEY_SPREADSHEET': 423, + 'KEY_STOP': 128, + 'KEY_STOPCD': 166, + 'KEY_STOP_RECORD': 625, + 'KEY_SUBTITLE': 370, + 'KEY_SUSPEND': 205, + 'KEY_SWITCHVIDEOMODE': 227, + 'KEY_SYSRQ': 99, + 'KEY_T': 20, + 'KEY_TAB': 15, + 'KEY_TAPE': 384, + 'KEY_TASKMANAGER': 577, + 'KEY_TEEN': 414, + 'KEY_TEXT': 388, + 'KEY_TIME': 359, + 'KEY_TITLE': 369, + 'KEY_TOUCHPAD_OFF': 532, + 'KEY_TOUCHPAD_ON': 531, + 'KEY_TOUCHPAD_TOGGLE': 530, + 'KEY_TRADITIONAL_SONAR': 645, + 'KEY_TUNER': 386, + 'KEY_TV': 377, + 'KEY_TV2': 378, + 'KEY_TWEN': 415, + 'KEY_U': 22, + 'KEY_UNDO': 131, + 'KEY_UNKNOWN': 240, + 'KEY_UNMUTE': 628, + 'KEY_UP': 103, + 'KEY_UWB': 239, + 'KEY_V': 47, + 'KEY_VCR': 379, + 'KEY_VCR2': 380, + 'KEY_VENDOR': 360, + 'KEY_VIDEO': 393, + 'KEY_VIDEOPHONE': 416, + 'KEY_VIDEO_NEXT': 241, + 'KEY_VIDEO_PREV': 242, + 'KEY_VOD': 627, + 'KEY_VOICECOMMAND': 582, + 'KEY_VOICEMAIL': 428, + 'KEY_VOLUMEDOWN': 114, + 'KEY_VOLUMEUP': 115, + 'KEY_W': 17, + 'KEY_WAKEUP': 143, + 'KEY_WIMAX': 246, + 'KEY_WLAN': 238, + 'KEY_WORDPROCESSOR': 421, + 'KEY_WPS_BUTTON': 529, + 'KEY_WWAN': 246, + 'KEY_WWW': 150, + 'KEY_X': 45, + 'KEY_XFER': 147, + 'KEY_Y': 21, + 'KEY_YELLOW': 400, + 'KEY_YEN': 124, + 'KEY_Z': 44, + 'KEY_ZENKAKUHANKAKU': 85, + 'KEY_ZOOM': 372, + 'KEY_ZOOMIN': 418, + 'KEY_ZOOMOUT': 419, + 'KEY_ZOOMRESET': 420, + 'LED_CAPSL': 1, + 'LED_CHARGING': 10, + 'LED_CNT': 16, + 'LED_COMPOSE': 3, + 'LED_KANA': 4, + 'LED_MAIL': 9, + 'LED_MAX': 15, + 'LED_MISC': 8, + 'LED_MUTE': 7, + 'LED_NUML': 0, + 'LED_SCROLLL': 2, + 'LED_SLEEP': 5, + 'LED_SUSPEND': 6, + 'MSC_CNT': 8, + 'MSC_GESTURE': 2, + 'MSC_MAX': 7, + 'MSC_PULSELED': 1, + 'MSC_RAW': 3, + 'MSC_SCAN': 4, + 'MSC_SERIAL': 0, + 'MSC_TIMESTAMP': 5, + 'REL_CNT': 16, + 'REL_DIAL': 7, + 'REL_HWHEEL': 6, + 'REL_HWHEEL_HI_RES': 12, + 'REL_MAX': 15, + 'REL_MISC': 9, + 'REL_RESERVED': 10, + 'REL_RX': 3, + 'REL_RY': 4, + 'REL_RZ': 5, + 'REL_WHEEL': 8, + 'REL_WHEEL_HI_RES': 11, + 'REL_X': 0, + 'REL_Y': 1, + 'REL_Z': 2, + 'REP_CNT': 2, + 'REP_DELAY': 0, + 'REP_MAX': 1, + 'REP_PERIOD': 1, + 'SND_BELL': 1, + 'SND_CLICK': 0, + 'SND_CNT': 8, + 'SND_MAX': 7, + 'SND_TONE': 2, + 'SW_CAMERA_LENS_COVER': 9, + 'SW_CNT': 17, + 'SW_DOCK': 5, + 'SW_FRONT_PROXIMITY': 11, + 'SW_HEADPHONE_INSERT': 2, + 'SW_JACK_PHYSICAL_INSERT': 7, + 'SW_KEYPAD_SLIDE': 10, + 'SW_LID': 0, + 'SW_LINEIN_INSERT': 13, + 'SW_LINEOUT_INSERT': 6, + 'SW_MACHINE_COVER': 16, + 'SW_MAX': 16, + 'SW_MICROPHONE_INSERT': 4, + 'SW_MUTE_DEVICE': 14, + 'SW_PEN_INSERTED': 15, + 'SW_RADIO': 3, + 'SW_RFKILL_ALL': 3, + 'SW_ROTATE_LOCK': 12, + 'SW_TABLET_MODE': 1, + 'SW_VIDEOOUT_INSERT': 8, + 'SYN_CNT': 16, + 'SYN_CONFIG': 1, + 'SYN_DROPPED': 3, + 'SYN_MAX': 15, + 'SYN_MT_REPORT': 2, + 'SYN_REPORT': 0, + 'UI_FF_ERASE': 2, + 'UI_FF_UPLOAD': 1} + +#: Mapping of event types to other value/name mappings. +bytype: Dict[int, Dict[int, Union[str, Tuple[str]]]] = { 0: {0: 'SYN_REPORT', 1: 'SYN_CONFIG', 2: 'SYN_MT_REPORT', 3: 'SYN_DROPPED', 15: 'SYN_MAX', 16: 'SYN_CNT'}, + 1: { 0: 'KEY_RESERVED', + 1: 'KEY_ESC', + 2: 'KEY_1', + 3: 'KEY_2', + 4: 'KEY_3', + 5: 'KEY_4', + 6: 'KEY_5', + 7: 'KEY_6', + 8: 'KEY_7', + 9: 'KEY_8', + 10: 'KEY_9', + 11: 'KEY_0', + 12: 'KEY_MINUS', + 13: 'KEY_EQUAL', + 14: 'KEY_BACKSPACE', + 15: 'KEY_TAB', + 16: 'KEY_Q', + 17: 'KEY_W', + 18: 'KEY_E', + 19: 'KEY_R', + 20: 'KEY_T', + 21: 'KEY_Y', + 22: 'KEY_U', + 23: 'KEY_I', + 24: 'KEY_O', + 25: 'KEY_P', + 26: 'KEY_LEFTBRACE', + 27: 'KEY_RIGHTBRACE', + 28: 'KEY_ENTER', + 29: 'KEY_LEFTCTRL', + 30: 'KEY_A', + 31: 'KEY_S', + 32: 'KEY_D', + 33: 'KEY_F', + 34: 'KEY_G', + 35: 'KEY_H', + 36: 'KEY_J', + 37: 'KEY_K', + 38: 'KEY_L', + 39: 'KEY_SEMICOLON', + 40: 'KEY_APOSTROPHE', + 41: 'KEY_GRAVE', + 42: 'KEY_LEFTSHIFT', + 43: 'KEY_BACKSLASH', + 44: 'KEY_Z', + 45: 'KEY_X', + 46: 'KEY_C', + 47: 'KEY_V', + 48: 'KEY_B', + 49: 'KEY_N', + 50: 'KEY_M', + 51: 'KEY_COMMA', + 52: 'KEY_DOT', + 53: 'KEY_SLASH', + 54: 'KEY_RIGHTSHIFT', + 55: 'KEY_KPASTERISK', + 56: 'KEY_LEFTALT', + 57: 'KEY_SPACE', + 58: 'KEY_CAPSLOCK', + 59: 'KEY_F1', + 60: 'KEY_F2', + 61: 'KEY_F3', + 62: 'KEY_F4', + 63: 'KEY_F5', + 64: 'KEY_F6', + 65: 'KEY_F7', + 66: 'KEY_F8', + 67: 'KEY_F9', + 68: 'KEY_F10', + 69: 'KEY_NUMLOCK', + 70: 'KEY_SCROLLLOCK', + 71: 'KEY_KP7', + 72: 'KEY_KP8', + 73: 'KEY_KP9', + 74: 'KEY_KPMINUS', + 75: 'KEY_KP4', + 76: 'KEY_KP5', + 77: 'KEY_KP6', + 78: 'KEY_KPPLUS', + 79: 'KEY_KP1', + 80: 'KEY_KP2', + 81: 'KEY_KP3', + 82: 'KEY_KP0', + 83: 'KEY_KPDOT', + 85: 'KEY_ZENKAKUHANKAKU', + 86: 'KEY_102ND', + 87: 'KEY_F11', + 88: 'KEY_F12', + 89: 'KEY_RO', + 90: 'KEY_KATAKANA', + 91: 'KEY_HIRAGANA', + 92: 'KEY_HENKAN', + 93: 'KEY_KATAKANAHIRAGANA', + 94: 'KEY_MUHENKAN', + 95: 'KEY_KPJPCOMMA', + 96: 'KEY_KPENTER', + 97: 'KEY_RIGHTCTRL', + 98: 'KEY_KPSLASH', + 99: 'KEY_SYSRQ', + 100: 'KEY_RIGHTALT', + 101: 'KEY_LINEFEED', + 102: 'KEY_HOME', + 103: 'KEY_UP', + 104: 'KEY_PAGEUP', + 105: 'KEY_LEFT', + 106: 'KEY_RIGHT', + 107: 'KEY_END', + 108: 'KEY_DOWN', + 109: 'KEY_PAGEDOWN', + 110: 'KEY_INSERT', + 111: 'KEY_DELETE', + 112: 'KEY_MACRO', + 113: ('KEY_MIN_INTERESTING', 'KEY_MUTE'), + 114: 'KEY_VOLUMEDOWN', + 115: 'KEY_VOLUMEUP', + 116: 'KEY_POWER', + 117: 'KEY_KPEQUAL', + 118: 'KEY_KPPLUSMINUS', + 119: 'KEY_PAUSE', + 120: 'KEY_SCALE', + 121: 'KEY_KPCOMMA', + 122: ('KEY_HANGEUL', 'KEY_HANGUEL'), + 123: 'KEY_HANJA', + 124: 'KEY_YEN', + 125: 'KEY_LEFTMETA', + 126: 'KEY_RIGHTMETA', + 127: 'KEY_COMPOSE', + 128: 'KEY_STOP', + 129: 'KEY_AGAIN', + 130: 'KEY_PROPS', + 131: 'KEY_UNDO', + 132: 'KEY_FRONT', + 133: 'KEY_COPY', + 134: 'KEY_OPEN', + 135: 'KEY_PASTE', + 136: 'KEY_FIND', + 137: 'KEY_CUT', + 138: 'KEY_HELP', + 139: 'KEY_MENU', + 140: 'KEY_CALC', + 141: 'KEY_SETUP', + 142: 'KEY_SLEEP', + 143: 'KEY_WAKEUP', + 144: 'KEY_FILE', + 145: 'KEY_SENDFILE', + 146: 'KEY_DELETEFILE', + 147: 'KEY_XFER', + 148: 'KEY_PROG1', + 149: 'KEY_PROG2', + 150: 'KEY_WWW', + 151: 'KEY_MSDOS', + 152: ('KEY_COFFEE', 'KEY_SCREENLOCK'), + 153: ('KEY_DIRECTION', 'KEY_ROTATE_DISPLAY'), + 154: 'KEY_CYCLEWINDOWS', + 155: 'KEY_MAIL', + 156: 'KEY_BOOKMARKS', + 157: 'KEY_COMPUTER', + 158: 'KEY_BACK', + 159: 'KEY_FORWARD', + 160: 'KEY_CLOSECD', + 161: 'KEY_EJECTCD', + 162: 'KEY_EJECTCLOSECD', + 163: 'KEY_NEXTSONG', + 164: 'KEY_PLAYPAUSE', + 165: 'KEY_PREVIOUSSONG', + 166: 'KEY_STOPCD', + 167: 'KEY_RECORD', + 168: 'KEY_REWIND', + 169: 'KEY_PHONE', + 170: 'KEY_ISO', + 171: 'KEY_CONFIG', + 172: 'KEY_HOMEPAGE', + 173: 'KEY_REFRESH', + 174: 'KEY_EXIT', + 175: 'KEY_MOVE', + 176: 'KEY_EDIT', + 177: 'KEY_SCROLLUP', + 178: 'KEY_SCROLLDOWN', + 179: 'KEY_KPLEFTPAREN', + 180: 'KEY_KPRIGHTPAREN', + 181: 'KEY_NEW', + 182: 'KEY_REDO', + 183: 'KEY_F13', + 184: 'KEY_F14', + 185: 'KEY_F15', + 186: 'KEY_F16', + 187: 'KEY_F17', + 188: 'KEY_F18', + 189: 'KEY_F19', + 190: 'KEY_F20', + 191: 'KEY_F21', + 192: 'KEY_F22', + 193: 'KEY_F23', + 194: 'KEY_F24', + 200: 'KEY_PLAYCD', + 201: 'KEY_PAUSECD', + 202: 'KEY_PROG3', + 203: 'KEY_PROG4', + 204: ('KEY_ALL_APPLICATIONS', 'KEY_DASHBOARD'), + 205: 'KEY_SUSPEND', + 206: 'KEY_CLOSE', + 207: 'KEY_PLAY', + 208: 'KEY_FASTFORWARD', + 209: 'KEY_BASSBOOST', + 210: 'KEY_PRINT', + 211: 'KEY_HP', + 212: 'KEY_CAMERA', + 213: 'KEY_SOUND', + 214: 'KEY_QUESTION', + 215: 'KEY_EMAIL', + 216: 'KEY_CHAT', + 217: 'KEY_SEARCH', + 218: 'KEY_CONNECT', + 219: 'KEY_FINANCE', + 220: 'KEY_SPORT', + 221: 'KEY_SHOP', + 222: 'KEY_ALTERASE', + 223: 'KEY_CANCEL', + 224: 'KEY_BRIGHTNESSDOWN', + 225: 'KEY_BRIGHTNESSUP', + 226: 'KEY_MEDIA', + 227: 'KEY_SWITCHVIDEOMODE', + 228: 'KEY_KBDILLUMTOGGLE', + 229: 'KEY_KBDILLUMDOWN', + 230: 'KEY_KBDILLUMUP', + 231: 'KEY_SEND', + 232: 'KEY_REPLY', + 233: 'KEY_FORWARDMAIL', + 234: 'KEY_SAVE', + 235: 'KEY_DOCUMENTS', + 236: 'KEY_BATTERY', + 237: 'KEY_BLUETOOTH', + 238: 'KEY_WLAN', + 239: 'KEY_UWB', + 240: 'KEY_UNKNOWN', + 241: 'KEY_VIDEO_NEXT', + 242: 'KEY_VIDEO_PREV', + 243: 'KEY_BRIGHTNESS_CYCLE', + 244: ('KEY_BRIGHTNESS_AUTO', 'KEY_BRIGHTNESS_ZERO'), + 245: 'KEY_DISPLAY_OFF', + 246: ('KEY_WIMAX', 'KEY_WWAN'), + 247: 'KEY_RFKILL', + 248: 'KEY_MICMUTE', + 256: ('BTN_0', 'BTN_MISC'), + 257: 'BTN_1', + 258: 'BTN_2', + 259: 'BTN_3', + 260: 'BTN_4', + 261: 'BTN_5', + 262: 'BTN_6', + 263: 'BTN_7', + 264: 'BTN_8', + 265: 'BTN_9', + 272: ('BTN_LEFT', 'BTN_MOUSE'), + 273: 'BTN_RIGHT', + 274: 'BTN_MIDDLE', + 275: 'BTN_SIDE', + 276: 'BTN_EXTRA', + 277: 'BTN_FORWARD', + 278: 'BTN_BACK', + 279: 'BTN_TASK', + 288: ('BTN_JOYSTICK', 'BTN_TRIGGER'), + 289: 'BTN_THUMB', + 290: 'BTN_THUMB2', + 291: 'BTN_TOP', + 292: 'BTN_TOP2', + 293: 'BTN_PINKIE', + 294: 'BTN_BASE', + 295: 'BTN_BASE2', + 296: 'BTN_BASE3', + 297: 'BTN_BASE4', + 298: 'BTN_BASE5', + 299: 'BTN_BASE6', + 303: 'BTN_DEAD', + 304: ('BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'), + 305: ('BTN_B', 'BTN_EAST'), + 306: 'BTN_C', + 307: ('BTN_NORTH', 'BTN_X'), + 308: ('BTN_WEST', 'BTN_Y'), + 309: 'BTN_Z', + 310: 'BTN_TL', + 311: 'BTN_TR', + 312: 'BTN_TL2', + 313: 'BTN_TR2', + 314: 'BTN_SELECT', + 315: 'BTN_START', + 316: 'BTN_MODE', + 317: 'BTN_THUMBL', + 318: 'BTN_THUMBR', + 320: ('BTN_DIGI', 'BTN_TOOL_PEN'), + 321: 'BTN_TOOL_RUBBER', + 322: 'BTN_TOOL_BRUSH', + 323: 'BTN_TOOL_PENCIL', + 324: 'BTN_TOOL_AIRBRUSH', + 325: 'BTN_TOOL_FINGER', + 326: 'BTN_TOOL_MOUSE', + 327: 'BTN_TOOL_LENS', + 328: 'BTN_TOOL_QUINTTAP', + 329: 'BTN_STYLUS3', + 330: 'BTN_TOUCH', + 331: 'BTN_STYLUS', + 332: 'BTN_STYLUS2', + 333: 'BTN_TOOL_DOUBLETAP', + 334: 'BTN_TOOL_TRIPLETAP', + 335: 'BTN_TOOL_QUADTAP', + 336: ('BTN_GEAR_DOWN', 'BTN_WHEEL'), + 337: 'BTN_GEAR_UP', + 352: 'KEY_OK', + 353: 'KEY_SELECT', + 354: 'KEY_GOTO', + 355: 'KEY_CLEAR', + 356: 'KEY_POWER2', + 357: 'KEY_OPTION', + 358: 'KEY_INFO', + 359: 'KEY_TIME', + 360: 'KEY_VENDOR', + 361: 'KEY_ARCHIVE', + 362: 'KEY_PROGRAM', + 363: 'KEY_CHANNEL', + 364: 'KEY_FAVORITES', + 365: 'KEY_EPG', + 366: 'KEY_PVR', + 367: 'KEY_MHP', + 368: 'KEY_LANGUAGE', + 369: 'KEY_TITLE', + 370: 'KEY_SUBTITLE', + 371: 'KEY_ANGLE', + 372: ('KEY_FULL_SCREEN', 'KEY_ZOOM'), + 373: 'KEY_MODE', + 374: 'KEY_KEYBOARD', + 375: ('KEY_ASPECT_RATIO', 'KEY_SCREEN'), + 376: 'KEY_PC', + 377: 'KEY_TV', + 378: 'KEY_TV2', + 379: 'KEY_VCR', + 380: 'KEY_VCR2', + 381: 'KEY_SAT', + 382: 'KEY_SAT2', + 383: 'KEY_CD', + 384: 'KEY_TAPE', + 385: 'KEY_RADIO', + 386: 'KEY_TUNER', + 387: 'KEY_PLAYER', + 388: 'KEY_TEXT', + 389: 'KEY_DVD', + 390: 'KEY_AUX', + 391: 'KEY_MP3', + 392: 'KEY_AUDIO', + 393: 'KEY_VIDEO', + 394: 'KEY_DIRECTORY', + 395: 'KEY_LIST', + 396: 'KEY_MEMO', + 397: 'KEY_CALENDAR', + 398: 'KEY_RED', + 399: 'KEY_GREEN', + 400: 'KEY_YELLOW', + 401: 'KEY_BLUE', + 402: 'KEY_CHANNELUP', + 403: 'KEY_CHANNELDOWN', + 404: 'KEY_FIRST', + 405: 'KEY_LAST', + 406: 'KEY_AB', + 407: 'KEY_NEXT', + 408: 'KEY_RESTART', + 409: 'KEY_SLOW', + 410: 'KEY_SHUFFLE', + 411: 'KEY_BREAK', + 412: 'KEY_PREVIOUS', + 413: 'KEY_DIGITS', + 414: 'KEY_TEEN', + 415: 'KEY_TWEN', + 416: 'KEY_VIDEOPHONE', + 417: 'KEY_GAMES', + 418: 'KEY_ZOOMIN', + 419: 'KEY_ZOOMOUT', + 420: 'KEY_ZOOMRESET', + 421: 'KEY_WORDPROCESSOR', + 422: 'KEY_EDITOR', + 423: 'KEY_SPREADSHEET', + 424: 'KEY_GRAPHICSEDITOR', + 425: 'KEY_PRESENTATION', + 426: 'KEY_DATABASE', + 427: 'KEY_NEWS', + 428: 'KEY_VOICEMAIL', + 429: 'KEY_ADDRESSBOOK', + 430: 'KEY_MESSENGER', + 431: ('KEY_BRIGHTNESS_TOGGLE', 'KEY_DISPLAYTOGGLE'), + 432: 'KEY_SPELLCHECK', + 433: 'KEY_LOGOFF', + 434: 'KEY_DOLLAR', + 435: 'KEY_EURO', + 436: 'KEY_FRAMEBACK', + 437: 'KEY_FRAMEFORWARD', + 438: 'KEY_CONTEXT_MENU', + 439: 'KEY_MEDIA_REPEAT', + 440: 'KEY_10CHANNELSUP', + 441: 'KEY_10CHANNELSDOWN', + 442: 'KEY_IMAGES', + 444: 'KEY_NOTIFICATION_CENTER', + 445: 'KEY_PICKUP_PHONE', + 446: 'KEY_HANGUP_PHONE', + 447: 'KEY_LINK_PHONE', + 448: 'KEY_DEL_EOL', + 449: 'KEY_DEL_EOS', + 450: 'KEY_INS_LINE', + 451: 'KEY_DEL_LINE', + 464: 'KEY_FN', + 465: 'KEY_FN_ESC', + 466: 'KEY_FN_F1', + 467: 'KEY_FN_F2', + 468: 'KEY_FN_F3', + 469: 'KEY_FN_F4', + 470: 'KEY_FN_F5', + 471: 'KEY_FN_F6', + 472: 'KEY_FN_F7', + 473: 'KEY_FN_F8', + 474: 'KEY_FN_F9', + 475: 'KEY_FN_F10', + 476: 'KEY_FN_F11', + 477: 'KEY_FN_F12', + 478: 'KEY_FN_1', + 479: 'KEY_FN_2', + 480: 'KEY_FN_D', + 481: 'KEY_FN_E', + 482: 'KEY_FN_F', + 483: 'KEY_FN_S', + 484: 'KEY_FN_B', + 485: 'KEY_FN_RIGHT_SHIFT', + 497: 'KEY_BRL_DOT1', + 498: 'KEY_BRL_DOT2', + 499: 'KEY_BRL_DOT3', + 500: 'KEY_BRL_DOT4', + 501: 'KEY_BRL_DOT5', + 502: 'KEY_BRL_DOT6', + 503: 'KEY_BRL_DOT7', + 504: 'KEY_BRL_DOT8', + 505: 'KEY_BRL_DOT9', + 506: 'KEY_BRL_DOT10', + 512: 'KEY_NUMERIC_0', + 513: 'KEY_NUMERIC_1', + 514: 'KEY_NUMERIC_2', + 515: 'KEY_NUMERIC_3', + 516: 'KEY_NUMERIC_4', + 517: 'KEY_NUMERIC_5', + 518: 'KEY_NUMERIC_6', + 519: 'KEY_NUMERIC_7', + 520: 'KEY_NUMERIC_8', + 521: 'KEY_NUMERIC_9', + 522: 'KEY_NUMERIC_STAR', + 523: 'KEY_NUMERIC_POUND', + 524: 'KEY_NUMERIC_A', + 525: 'KEY_NUMERIC_B', + 526: 'KEY_NUMERIC_C', + 527: 'KEY_NUMERIC_D', + 528: 'KEY_CAMERA_FOCUS', + 529: 'KEY_WPS_BUTTON', + 530: 'KEY_TOUCHPAD_TOGGLE', + 531: 'KEY_TOUCHPAD_ON', + 532: 'KEY_TOUCHPAD_OFF', + 533: 'KEY_CAMERA_ZOOMIN', + 534: 'KEY_CAMERA_ZOOMOUT', + 535: 'KEY_CAMERA_UP', + 536: 'KEY_CAMERA_DOWN', + 537: 'KEY_CAMERA_LEFT', + 538: 'KEY_CAMERA_RIGHT', + 539: 'KEY_ATTENDANT_ON', + 540: 'KEY_ATTENDANT_OFF', + 541: 'KEY_ATTENDANT_TOGGLE', + 542: 'KEY_LIGHTS_TOGGLE', + 544: 'BTN_DPAD_UP', + 545: 'BTN_DPAD_DOWN', + 546: 'BTN_DPAD_LEFT', + 547: 'BTN_DPAD_RIGHT', + 560: 'KEY_ALS_TOGGLE', + 561: 'KEY_ROTATE_LOCK_TOGGLE', + 562: 'KEY_REFRESH_RATE_TOGGLE', + 576: 'KEY_BUTTONCONFIG', + 577: 'KEY_TASKMANAGER', + 578: 'KEY_JOURNAL', + 579: 'KEY_CONTROLPANEL', + 580: 'KEY_APPSELECT', + 581: 'KEY_SCREENSAVER', + 582: 'KEY_VOICECOMMAND', + 583: 'KEY_ASSISTANT', + 584: 'KEY_KBD_LAYOUT_NEXT', + 585: 'KEY_EMOJI_PICKER', + 586: 'KEY_DICTATE', + 587: 'KEY_CAMERA_ACCESS_ENABLE', + 588: 'KEY_CAMERA_ACCESS_DISABLE', + 589: 'KEY_CAMERA_ACCESS_TOGGLE', + 590: 'KEY_ACCESSIBILITY', + 591: 'KEY_DO_NOT_DISTURB', + 592: 'KEY_BRIGHTNESS_MIN', + 593: 'KEY_BRIGHTNESS_MAX', + 608: 'KEY_KBDINPUTASSIST_PREV', + 609: 'KEY_KBDINPUTASSIST_NEXT', + 610: 'KEY_KBDINPUTASSIST_PREVGROUP', + 611: 'KEY_KBDINPUTASSIST_NEXTGROUP', + 612: 'KEY_KBDINPUTASSIST_ACCEPT', + 613: 'KEY_KBDINPUTASSIST_CANCEL', + 614: 'KEY_RIGHT_UP', + 615: 'KEY_RIGHT_DOWN', + 616: 'KEY_LEFT_UP', + 617: 'KEY_LEFT_DOWN', + 618: 'KEY_ROOT_MENU', + 619: 'KEY_MEDIA_TOP_MENU', + 620: 'KEY_NUMERIC_11', + 621: 'KEY_NUMERIC_12', + 622: 'KEY_AUDIO_DESC', + 623: 'KEY_3D_MODE', + 624: 'KEY_NEXT_FAVORITE', + 625: 'KEY_STOP_RECORD', + 626: 'KEY_PAUSE_RECORD', + 627: 'KEY_VOD', + 628: 'KEY_UNMUTE', + 629: 'KEY_FASTREVERSE', + 630: 'KEY_SLOWREVERSE', + 631: 'KEY_DATA', + 632: 'KEY_ONSCREEN_KEYBOARD', + 633: 'KEY_PRIVACY_SCREEN_TOGGLE', + 634: 'KEY_SELECTIVE_SCREENSHOT', + 635: 'KEY_NEXT_ELEMENT', + 636: 'KEY_PREVIOUS_ELEMENT', + 637: 'KEY_AUTOPILOT_ENGAGE_TOGGLE', + 638: 'KEY_MARK_WAYPOINT', + 639: 'KEY_SOS', + 640: 'KEY_NAV_CHART', + 641: 'KEY_FISHING_CHART', + 642: 'KEY_SINGLE_RANGE_RADAR', + 643: 'KEY_DUAL_RANGE_RADAR', + 644: 'KEY_RADAR_OVERLAY', + 645: 'KEY_TRADITIONAL_SONAR', + 646: 'KEY_CLEARVU_SONAR', + 647: 'KEY_SIDEVU_SONAR', + 648: 'KEY_NAV_INFO', + 649: 'KEY_BRIGHTNESS_MENU', + 656: 'KEY_MACRO1', + 657: 'KEY_MACRO2', + 658: 'KEY_MACRO3', + 659: 'KEY_MACRO4', + 660: 'KEY_MACRO5', + 661: 'KEY_MACRO6', + 662: 'KEY_MACRO7', + 663: 'KEY_MACRO8', + 664: 'KEY_MACRO9', + 665: 'KEY_MACRO10', + 666: 'KEY_MACRO11', + 667: 'KEY_MACRO12', + 668: 'KEY_MACRO13', + 669: 'KEY_MACRO14', + 670: 'KEY_MACRO15', + 671: 'KEY_MACRO16', + 672: 'KEY_MACRO17', + 673: 'KEY_MACRO18', + 674: 'KEY_MACRO19', + 675: 'KEY_MACRO20', + 676: 'KEY_MACRO21', + 677: 'KEY_MACRO22', + 678: 'KEY_MACRO23', + 679: 'KEY_MACRO24', + 680: 'KEY_MACRO25', + 681: 'KEY_MACRO26', + 682: 'KEY_MACRO27', + 683: 'KEY_MACRO28', + 684: 'KEY_MACRO29', + 685: 'KEY_MACRO30', + 688: 'KEY_MACRO_RECORD_START', + 689: 'KEY_MACRO_RECORD_STOP', + 690: 'KEY_MACRO_PRESET_CYCLE', + 691: 'KEY_MACRO_PRESET1', + 692: 'KEY_MACRO_PRESET2', + 693: 'KEY_MACRO_PRESET3', + 696: 'KEY_KBD_LCD_MENU1', + 697: 'KEY_KBD_LCD_MENU2', + 698: 'KEY_KBD_LCD_MENU3', + 699: 'KEY_KBD_LCD_MENU4', + 700: 'KEY_KBD_LCD_MENU5', + 704: ('BTN_TRIGGER_HAPPY', 'BTN_TRIGGER_HAPPY1'), + 705: 'BTN_TRIGGER_HAPPY2', + 706: 'BTN_TRIGGER_HAPPY3', + 707: 'BTN_TRIGGER_HAPPY4', + 708: 'BTN_TRIGGER_HAPPY5', + 709: 'BTN_TRIGGER_HAPPY6', + 710: 'BTN_TRIGGER_HAPPY7', + 711: 'BTN_TRIGGER_HAPPY8', + 712: 'BTN_TRIGGER_HAPPY9', + 713: 'BTN_TRIGGER_HAPPY10', + 714: 'BTN_TRIGGER_HAPPY11', + 715: 'BTN_TRIGGER_HAPPY12', + 716: 'BTN_TRIGGER_HAPPY13', + 717: 'BTN_TRIGGER_HAPPY14', + 718: 'BTN_TRIGGER_HAPPY15', + 719: 'BTN_TRIGGER_HAPPY16', + 720: 'BTN_TRIGGER_HAPPY17', + 721: 'BTN_TRIGGER_HAPPY18', + 722: 'BTN_TRIGGER_HAPPY19', + 723: 'BTN_TRIGGER_HAPPY20', + 724: 'BTN_TRIGGER_HAPPY21', + 725: 'BTN_TRIGGER_HAPPY22', + 726: 'BTN_TRIGGER_HAPPY23', + 727: 'BTN_TRIGGER_HAPPY24', + 728: 'BTN_TRIGGER_HAPPY25', + 729: 'BTN_TRIGGER_HAPPY26', + 730: 'BTN_TRIGGER_HAPPY27', + 731: 'BTN_TRIGGER_HAPPY28', + 732: 'BTN_TRIGGER_HAPPY29', + 733: 'BTN_TRIGGER_HAPPY30', + 734: 'BTN_TRIGGER_HAPPY31', + 735: 'BTN_TRIGGER_HAPPY32', + 736: 'BTN_TRIGGER_HAPPY33', + 737: 'BTN_TRIGGER_HAPPY34', + 738: 'BTN_TRIGGER_HAPPY35', + 739: 'BTN_TRIGGER_HAPPY36', + 740: 'BTN_TRIGGER_HAPPY37', + 741: 'BTN_TRIGGER_HAPPY38', + 742: 'BTN_TRIGGER_HAPPY39', + 743: 'BTN_TRIGGER_HAPPY40'}, + 2: { 0: 'REL_X', + 1: 'REL_Y', + 2: 'REL_Z', + 3: 'REL_RX', + 4: 'REL_RY', + 5: 'REL_RZ', + 6: 'REL_HWHEEL', + 7: 'REL_DIAL', + 8: 'REL_WHEEL', + 9: 'REL_MISC', + 10: 'REL_RESERVED', + 11: 'REL_WHEEL_HI_RES', + 12: 'REL_HWHEEL_HI_RES', + 15: 'REL_MAX', + 16: 'REL_CNT'}, + 3: { 0: 'ABS_X', + 1: 'ABS_Y', + 2: 'ABS_Z', + 3: 'ABS_RX', + 4: 'ABS_RY', + 5: 'ABS_RZ', + 6: 'ABS_THROTTLE', + 7: 'ABS_RUDDER', + 8: 'ABS_WHEEL', + 9: 'ABS_GAS', + 10: 'ABS_BRAKE', + 16: 'ABS_HAT0X', + 17: 'ABS_HAT0Y', + 18: 'ABS_HAT1X', + 19: 'ABS_HAT1Y', + 20: 'ABS_HAT2X', + 21: 'ABS_HAT2Y', + 22: 'ABS_HAT3X', + 23: 'ABS_HAT3Y', + 24: 'ABS_PRESSURE', + 25: 'ABS_DISTANCE', + 26: 'ABS_TILT_X', + 27: 'ABS_TILT_Y', + 28: 'ABS_TOOL_WIDTH', + 32: 'ABS_VOLUME', + 33: 'ABS_PROFILE', + 40: 'ABS_MISC', + 46: 'ABS_RESERVED', + 47: 'ABS_MT_SLOT', + 48: 'ABS_MT_TOUCH_MAJOR', + 49: 'ABS_MT_TOUCH_MINOR', + 50: 'ABS_MT_WIDTH_MAJOR', + 51: 'ABS_MT_WIDTH_MINOR', + 52: 'ABS_MT_ORIENTATION', + 53: 'ABS_MT_POSITION_X', + 54: 'ABS_MT_POSITION_Y', + 55: 'ABS_MT_TOOL_TYPE', + 56: 'ABS_MT_BLOB_ID', + 57: 'ABS_MT_TRACKING_ID', + 58: 'ABS_MT_PRESSURE', + 59: 'ABS_MT_DISTANCE', + 60: 'ABS_MT_TOOL_X', + 61: 'ABS_MT_TOOL_Y', + 63: 'ABS_MAX', + 64: 'ABS_CNT'}, + 4: { 0: 'MSC_SERIAL', + 1: 'MSC_PULSELED', + 2: 'MSC_GESTURE', + 3: 'MSC_RAW', + 4: 'MSC_SCAN', + 5: 'MSC_TIMESTAMP', + 7: 'MSC_MAX', + 8: 'MSC_CNT'}, + 5: { 0: 'SW_LID', + 1: 'SW_TABLET_MODE', + 2: 'SW_HEADPHONE_INSERT', + 3: ('SW_RADIO', 'SW_RFKILL_ALL'), + 4: 'SW_MICROPHONE_INSERT', + 5: 'SW_DOCK', + 6: 'SW_LINEOUT_INSERT', + 7: 'SW_JACK_PHYSICAL_INSERT', + 8: 'SW_VIDEOOUT_INSERT', + 9: 'SW_CAMERA_LENS_COVER', + 10: 'SW_KEYPAD_SLIDE', + 11: 'SW_FRONT_PROXIMITY', + 12: 'SW_ROTATE_LOCK', + 13: 'SW_LINEIN_INSERT', + 14: 'SW_MUTE_DEVICE', + 15: 'SW_PEN_INSERTED', + 16: ('SW_MACHINE_COVER', 'SW_MAX'), + 17: 'SW_CNT'}, + 17: { 0: 'LED_NUML', + 1: 'LED_CAPSL', + 2: 'LED_SCROLLL', + 3: 'LED_COMPOSE', + 4: 'LED_KANA', + 5: 'LED_SLEEP', + 6: 'LED_SUSPEND', + 7: 'LED_MUTE', + 8: 'LED_MISC', + 9: 'LED_MAIL', + 10: 'LED_CHARGING', + 15: 'LED_MAX', + 16: 'LED_CNT'}, + 18: {0: 'SND_CLICK', 1: 'SND_BELL', 2: 'SND_TONE', 7: 'SND_MAX', 8: 'SND_CNT'}, + 20: {0: 'REP_DELAY', 1: ('REP_MAX', 'REP_PERIOD'), 2: 'REP_CNT'}, + 21: { 80: ('FF_EFFECT_MIN', 'FF_RUMBLE'), + 81: 'FF_PERIODIC', + 82: 'FF_CONSTANT', + 83: 'FF_SPRING', + 84: 'FF_FRICTION', + 85: 'FF_DAMPER', + 86: 'FF_INERTIA', + 87: ('FF_EFFECT_MAX', 'FF_RAMP'), + 88: ('FF_SQUARE', 'FF_WAVEFORM_MIN'), + 89: 'FF_TRIANGLE', + 90: 'FF_SINE', + 91: 'FF_SAW_UP', + 92: 'FF_SAW_DOWN', + 93: ('FF_CUSTOM', 'FF_WAVEFORM_MAX'), + 96: ('FF_GAIN', 'FF_MAX_EFFECTS'), + 97: 'FF_AUTOCENTER', + 127: 'FF_MAX', + 128: 'FF_CNT'}, + 23: {0: 'FF_STATUS_STOPPED', 1: ('FF_STATUS_MAX', 'FF_STATUS_PLAYING')}} + +#: Keys are a combination of all BTN and KEY codes. +keys: Dict[int, Union[str, Tuple[str]]] = { 0: 'KEY_RESERVED', + 1: 'KEY_ESC', + 2: 'KEY_1', + 3: 'KEY_2', + 4: 'KEY_3', + 5: 'KEY_4', + 6: 'KEY_5', + 7: 'KEY_6', + 8: 'KEY_7', + 9: 'KEY_8', + 10: 'KEY_9', + 11: 'KEY_0', + 12: 'KEY_MINUS', + 13: 'KEY_EQUAL', + 14: 'KEY_BACKSPACE', + 15: 'KEY_TAB', + 16: 'KEY_Q', + 17: 'KEY_W', + 18: 'KEY_E', + 19: 'KEY_R', + 20: 'KEY_T', + 21: 'KEY_Y', + 22: 'KEY_U', + 23: 'KEY_I', + 24: 'KEY_O', + 25: 'KEY_P', + 26: 'KEY_LEFTBRACE', + 27: 'KEY_RIGHTBRACE', + 28: 'KEY_ENTER', + 29: 'KEY_LEFTCTRL', + 30: 'KEY_A', + 31: 'KEY_S', + 32: 'KEY_D', + 33: 'KEY_F', + 34: 'KEY_G', + 35: 'KEY_H', + 36: 'KEY_J', + 37: 'KEY_K', + 38: 'KEY_L', + 39: 'KEY_SEMICOLON', + 40: 'KEY_APOSTROPHE', + 41: 'KEY_GRAVE', + 42: 'KEY_LEFTSHIFT', + 43: 'KEY_BACKSLASH', + 44: 'KEY_Z', + 45: 'KEY_X', + 46: 'KEY_C', + 47: 'KEY_V', + 48: 'KEY_B', + 49: 'KEY_N', + 50: 'KEY_M', + 51: 'KEY_COMMA', + 52: 'KEY_DOT', + 53: 'KEY_SLASH', + 54: 'KEY_RIGHTSHIFT', + 55: 'KEY_KPASTERISK', + 56: 'KEY_LEFTALT', + 57: 'KEY_SPACE', + 58: 'KEY_CAPSLOCK', + 59: 'KEY_F1', + 60: 'KEY_F2', + 61: 'KEY_F3', + 62: 'KEY_F4', + 63: 'KEY_F5', + 64: 'KEY_F6', + 65: 'KEY_F7', + 66: 'KEY_F8', + 67: 'KEY_F9', + 68: 'KEY_F10', + 69: 'KEY_NUMLOCK', + 70: 'KEY_SCROLLLOCK', + 71: 'KEY_KP7', + 72: 'KEY_KP8', + 73: 'KEY_KP9', + 74: 'KEY_KPMINUS', + 75: 'KEY_KP4', + 76: 'KEY_KP5', + 77: 'KEY_KP6', + 78: 'KEY_KPPLUS', + 79: 'KEY_KP1', + 80: 'KEY_KP2', + 81: 'KEY_KP3', + 82: 'KEY_KP0', + 83: 'KEY_KPDOT', + 85: 'KEY_ZENKAKUHANKAKU', + 86: 'KEY_102ND', + 87: 'KEY_F11', + 88: 'KEY_F12', + 89: 'KEY_RO', + 90: 'KEY_KATAKANA', + 91: 'KEY_HIRAGANA', + 92: 'KEY_HENKAN', + 93: 'KEY_KATAKANAHIRAGANA', + 94: 'KEY_MUHENKAN', + 95: 'KEY_KPJPCOMMA', + 96: 'KEY_KPENTER', + 97: 'KEY_RIGHTCTRL', + 98: 'KEY_KPSLASH', + 99: 'KEY_SYSRQ', + 100: 'KEY_RIGHTALT', + 101: 'KEY_LINEFEED', + 102: 'KEY_HOME', + 103: 'KEY_UP', + 104: 'KEY_PAGEUP', + 105: 'KEY_LEFT', + 106: 'KEY_RIGHT', + 107: 'KEY_END', + 108: 'KEY_DOWN', + 109: 'KEY_PAGEDOWN', + 110: 'KEY_INSERT', + 111: 'KEY_DELETE', + 112: 'KEY_MACRO', + 113: ('KEY_MIN_INTERESTING', 'KEY_MUTE'), + 114: 'KEY_VOLUMEDOWN', + 115: 'KEY_VOLUMEUP', + 116: 'KEY_POWER', + 117: 'KEY_KPEQUAL', + 118: 'KEY_KPPLUSMINUS', + 119: 'KEY_PAUSE', + 120: 'KEY_SCALE', + 121: 'KEY_KPCOMMA', + 122: ('KEY_HANGEUL', 'KEY_HANGUEL'), + 123: 'KEY_HANJA', + 124: 'KEY_YEN', + 125: 'KEY_LEFTMETA', + 126: 'KEY_RIGHTMETA', + 127: 'KEY_COMPOSE', + 128: 'KEY_STOP', + 129: 'KEY_AGAIN', + 130: 'KEY_PROPS', + 131: 'KEY_UNDO', + 132: 'KEY_FRONT', + 133: 'KEY_COPY', + 134: 'KEY_OPEN', + 135: 'KEY_PASTE', + 136: 'KEY_FIND', + 137: 'KEY_CUT', + 138: 'KEY_HELP', + 139: 'KEY_MENU', + 140: 'KEY_CALC', + 141: 'KEY_SETUP', + 142: 'KEY_SLEEP', + 143: 'KEY_WAKEUP', + 144: 'KEY_FILE', + 145: 'KEY_SENDFILE', + 146: 'KEY_DELETEFILE', + 147: 'KEY_XFER', + 148: 'KEY_PROG1', + 149: 'KEY_PROG2', + 150: 'KEY_WWW', + 151: 'KEY_MSDOS', + 152: ('KEY_COFFEE', 'KEY_SCREENLOCK'), + 153: ('KEY_DIRECTION', 'KEY_ROTATE_DISPLAY'), + 154: 'KEY_CYCLEWINDOWS', + 155: 'KEY_MAIL', + 156: 'KEY_BOOKMARKS', + 157: 'KEY_COMPUTER', + 158: 'KEY_BACK', + 159: 'KEY_FORWARD', + 160: 'KEY_CLOSECD', + 161: 'KEY_EJECTCD', + 162: 'KEY_EJECTCLOSECD', + 163: 'KEY_NEXTSONG', + 164: 'KEY_PLAYPAUSE', + 165: 'KEY_PREVIOUSSONG', + 166: 'KEY_STOPCD', + 167: 'KEY_RECORD', + 168: 'KEY_REWIND', + 169: 'KEY_PHONE', + 170: 'KEY_ISO', + 171: 'KEY_CONFIG', + 172: 'KEY_HOMEPAGE', + 173: 'KEY_REFRESH', + 174: 'KEY_EXIT', + 175: 'KEY_MOVE', + 176: 'KEY_EDIT', + 177: 'KEY_SCROLLUP', + 178: 'KEY_SCROLLDOWN', + 179: 'KEY_KPLEFTPAREN', + 180: 'KEY_KPRIGHTPAREN', + 181: 'KEY_NEW', + 182: 'KEY_REDO', + 183: 'KEY_F13', + 184: 'KEY_F14', + 185: 'KEY_F15', + 186: 'KEY_F16', + 187: 'KEY_F17', + 188: 'KEY_F18', + 189: 'KEY_F19', + 190: 'KEY_F20', + 191: 'KEY_F21', + 192: 'KEY_F22', + 193: 'KEY_F23', + 194: 'KEY_F24', + 200: 'KEY_PLAYCD', + 201: 'KEY_PAUSECD', + 202: 'KEY_PROG3', + 203: 'KEY_PROG4', + 204: ('KEY_ALL_APPLICATIONS', 'KEY_DASHBOARD'), + 205: 'KEY_SUSPEND', + 206: 'KEY_CLOSE', + 207: 'KEY_PLAY', + 208: 'KEY_FASTFORWARD', + 209: 'KEY_BASSBOOST', + 210: 'KEY_PRINT', + 211: 'KEY_HP', + 212: 'KEY_CAMERA', + 213: 'KEY_SOUND', + 214: 'KEY_QUESTION', + 215: 'KEY_EMAIL', + 216: 'KEY_CHAT', + 217: 'KEY_SEARCH', + 218: 'KEY_CONNECT', + 219: 'KEY_FINANCE', + 220: 'KEY_SPORT', + 221: 'KEY_SHOP', + 222: 'KEY_ALTERASE', + 223: 'KEY_CANCEL', + 224: 'KEY_BRIGHTNESSDOWN', + 225: 'KEY_BRIGHTNESSUP', + 226: 'KEY_MEDIA', + 227: 'KEY_SWITCHVIDEOMODE', + 228: 'KEY_KBDILLUMTOGGLE', + 229: 'KEY_KBDILLUMDOWN', + 230: 'KEY_KBDILLUMUP', + 231: 'KEY_SEND', + 232: 'KEY_REPLY', + 233: 'KEY_FORWARDMAIL', + 234: 'KEY_SAVE', + 235: 'KEY_DOCUMENTS', + 236: 'KEY_BATTERY', + 237: 'KEY_BLUETOOTH', + 238: 'KEY_WLAN', + 239: 'KEY_UWB', + 240: 'KEY_UNKNOWN', + 241: 'KEY_VIDEO_NEXT', + 242: 'KEY_VIDEO_PREV', + 243: 'KEY_BRIGHTNESS_CYCLE', + 244: ('KEY_BRIGHTNESS_AUTO', 'KEY_BRIGHTNESS_ZERO'), + 245: 'KEY_DISPLAY_OFF', + 246: ('KEY_WIMAX', 'KEY_WWAN'), + 247: 'KEY_RFKILL', + 248: 'KEY_MICMUTE', + 256: ('BTN_0', 'BTN_MISC'), + 257: 'BTN_1', + 258: 'BTN_2', + 259: 'BTN_3', + 260: 'BTN_4', + 261: 'BTN_5', + 262: 'BTN_6', + 263: 'BTN_7', + 264: 'BTN_8', + 265: 'BTN_9', + 272: ('BTN_LEFT', 'BTN_MOUSE'), + 273: 'BTN_RIGHT', + 274: 'BTN_MIDDLE', + 275: 'BTN_SIDE', + 276: 'BTN_EXTRA', + 277: 'BTN_FORWARD', + 278: 'BTN_BACK', + 279: 'BTN_TASK', + 288: ('BTN_JOYSTICK', 'BTN_TRIGGER'), + 289: 'BTN_THUMB', + 290: 'BTN_THUMB2', + 291: 'BTN_TOP', + 292: 'BTN_TOP2', + 293: 'BTN_PINKIE', + 294: 'BTN_BASE', + 295: 'BTN_BASE2', + 296: 'BTN_BASE3', + 297: 'BTN_BASE4', + 298: 'BTN_BASE5', + 299: 'BTN_BASE6', + 303: 'BTN_DEAD', + 304: ('BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'), + 305: ('BTN_B', 'BTN_EAST'), + 306: 'BTN_C', + 307: ('BTN_NORTH', 'BTN_X'), + 308: ('BTN_WEST', 'BTN_Y'), + 309: 'BTN_Z', + 310: 'BTN_TL', + 311: 'BTN_TR', + 312: 'BTN_TL2', + 313: 'BTN_TR2', + 314: 'BTN_SELECT', + 315: 'BTN_START', + 316: 'BTN_MODE', + 317: 'BTN_THUMBL', + 318: 'BTN_THUMBR', + 320: ('BTN_DIGI', 'BTN_TOOL_PEN'), + 321: 'BTN_TOOL_RUBBER', + 322: 'BTN_TOOL_BRUSH', + 323: 'BTN_TOOL_PENCIL', + 324: 'BTN_TOOL_AIRBRUSH', + 325: 'BTN_TOOL_FINGER', + 326: 'BTN_TOOL_MOUSE', + 327: 'BTN_TOOL_LENS', + 328: 'BTN_TOOL_QUINTTAP', + 329: 'BTN_STYLUS3', + 330: 'BTN_TOUCH', + 331: 'BTN_STYLUS', + 332: 'BTN_STYLUS2', + 333: 'BTN_TOOL_DOUBLETAP', + 334: 'BTN_TOOL_TRIPLETAP', + 335: 'BTN_TOOL_QUADTAP', + 336: ('BTN_GEAR_DOWN', 'BTN_WHEEL'), + 337: 'BTN_GEAR_UP', + 352: 'KEY_OK', + 353: 'KEY_SELECT', + 354: 'KEY_GOTO', + 355: 'KEY_CLEAR', + 356: 'KEY_POWER2', + 357: 'KEY_OPTION', + 358: 'KEY_INFO', + 359: 'KEY_TIME', + 360: 'KEY_VENDOR', + 361: 'KEY_ARCHIVE', + 362: 'KEY_PROGRAM', + 363: 'KEY_CHANNEL', + 364: 'KEY_FAVORITES', + 365: 'KEY_EPG', + 366: 'KEY_PVR', + 367: 'KEY_MHP', + 368: 'KEY_LANGUAGE', + 369: 'KEY_TITLE', + 370: 'KEY_SUBTITLE', + 371: 'KEY_ANGLE', + 372: ('KEY_FULL_SCREEN', 'KEY_ZOOM'), + 373: 'KEY_MODE', + 374: 'KEY_KEYBOARD', + 375: ('KEY_ASPECT_RATIO', 'KEY_SCREEN'), + 376: 'KEY_PC', + 377: 'KEY_TV', + 378: 'KEY_TV2', + 379: 'KEY_VCR', + 380: 'KEY_VCR2', + 381: 'KEY_SAT', + 382: 'KEY_SAT2', + 383: 'KEY_CD', + 384: 'KEY_TAPE', + 385: 'KEY_RADIO', + 386: 'KEY_TUNER', + 387: 'KEY_PLAYER', + 388: 'KEY_TEXT', + 389: 'KEY_DVD', + 390: 'KEY_AUX', + 391: 'KEY_MP3', + 392: 'KEY_AUDIO', + 393: 'KEY_VIDEO', + 394: 'KEY_DIRECTORY', + 395: 'KEY_LIST', + 396: 'KEY_MEMO', + 397: 'KEY_CALENDAR', + 398: 'KEY_RED', + 399: 'KEY_GREEN', + 400: 'KEY_YELLOW', + 401: 'KEY_BLUE', + 402: 'KEY_CHANNELUP', + 403: 'KEY_CHANNELDOWN', + 404: 'KEY_FIRST', + 405: 'KEY_LAST', + 406: 'KEY_AB', + 407: 'KEY_NEXT', + 408: 'KEY_RESTART', + 409: 'KEY_SLOW', + 410: 'KEY_SHUFFLE', + 411: 'KEY_BREAK', + 412: 'KEY_PREVIOUS', + 413: 'KEY_DIGITS', + 414: 'KEY_TEEN', + 415: 'KEY_TWEN', + 416: 'KEY_VIDEOPHONE', + 417: 'KEY_GAMES', + 418: 'KEY_ZOOMIN', + 419: 'KEY_ZOOMOUT', + 420: 'KEY_ZOOMRESET', + 421: 'KEY_WORDPROCESSOR', + 422: 'KEY_EDITOR', + 423: 'KEY_SPREADSHEET', + 424: 'KEY_GRAPHICSEDITOR', + 425: 'KEY_PRESENTATION', + 426: 'KEY_DATABASE', + 427: 'KEY_NEWS', + 428: 'KEY_VOICEMAIL', + 429: 'KEY_ADDRESSBOOK', + 430: 'KEY_MESSENGER', + 431: ('KEY_BRIGHTNESS_TOGGLE', 'KEY_DISPLAYTOGGLE'), + 432: 'KEY_SPELLCHECK', + 433: 'KEY_LOGOFF', + 434: 'KEY_DOLLAR', + 435: 'KEY_EURO', + 436: 'KEY_FRAMEBACK', + 437: 'KEY_FRAMEFORWARD', + 438: 'KEY_CONTEXT_MENU', + 439: 'KEY_MEDIA_REPEAT', + 440: 'KEY_10CHANNELSUP', + 441: 'KEY_10CHANNELSDOWN', + 442: 'KEY_IMAGES', + 444: 'KEY_NOTIFICATION_CENTER', + 445: 'KEY_PICKUP_PHONE', + 446: 'KEY_HANGUP_PHONE', + 447: 'KEY_LINK_PHONE', + 448: 'KEY_DEL_EOL', + 449: 'KEY_DEL_EOS', + 450: 'KEY_INS_LINE', + 451: 'KEY_DEL_LINE', + 464: 'KEY_FN', + 465: 'KEY_FN_ESC', + 466: 'KEY_FN_F1', + 467: 'KEY_FN_F2', + 468: 'KEY_FN_F3', + 469: 'KEY_FN_F4', + 470: 'KEY_FN_F5', + 471: 'KEY_FN_F6', + 472: 'KEY_FN_F7', + 473: 'KEY_FN_F8', + 474: 'KEY_FN_F9', + 475: 'KEY_FN_F10', + 476: 'KEY_FN_F11', + 477: 'KEY_FN_F12', + 478: 'KEY_FN_1', + 479: 'KEY_FN_2', + 480: 'KEY_FN_D', + 481: 'KEY_FN_E', + 482: 'KEY_FN_F', + 483: 'KEY_FN_S', + 484: 'KEY_FN_B', + 485: 'KEY_FN_RIGHT_SHIFT', + 497: 'KEY_BRL_DOT1', + 498: 'KEY_BRL_DOT2', + 499: 'KEY_BRL_DOT3', + 500: 'KEY_BRL_DOT4', + 501: 'KEY_BRL_DOT5', + 502: 'KEY_BRL_DOT6', + 503: 'KEY_BRL_DOT7', + 504: 'KEY_BRL_DOT8', + 505: 'KEY_BRL_DOT9', + 506: 'KEY_BRL_DOT10', + 512: 'KEY_NUMERIC_0', + 513: 'KEY_NUMERIC_1', + 514: 'KEY_NUMERIC_2', + 515: 'KEY_NUMERIC_3', + 516: 'KEY_NUMERIC_4', + 517: 'KEY_NUMERIC_5', + 518: 'KEY_NUMERIC_6', + 519: 'KEY_NUMERIC_7', + 520: 'KEY_NUMERIC_8', + 521: 'KEY_NUMERIC_9', + 522: 'KEY_NUMERIC_STAR', + 523: 'KEY_NUMERIC_POUND', + 524: 'KEY_NUMERIC_A', + 525: 'KEY_NUMERIC_B', + 526: 'KEY_NUMERIC_C', + 527: 'KEY_NUMERIC_D', + 528: 'KEY_CAMERA_FOCUS', + 529: 'KEY_WPS_BUTTON', + 530: 'KEY_TOUCHPAD_TOGGLE', + 531: 'KEY_TOUCHPAD_ON', + 532: 'KEY_TOUCHPAD_OFF', + 533: 'KEY_CAMERA_ZOOMIN', + 534: 'KEY_CAMERA_ZOOMOUT', + 535: 'KEY_CAMERA_UP', + 536: 'KEY_CAMERA_DOWN', + 537: 'KEY_CAMERA_LEFT', + 538: 'KEY_CAMERA_RIGHT', + 539: 'KEY_ATTENDANT_ON', + 540: 'KEY_ATTENDANT_OFF', + 541: 'KEY_ATTENDANT_TOGGLE', + 542: 'KEY_LIGHTS_TOGGLE', + 544: 'BTN_DPAD_UP', + 545: 'BTN_DPAD_DOWN', + 546: 'BTN_DPAD_LEFT', + 547: 'BTN_DPAD_RIGHT', + 560: 'KEY_ALS_TOGGLE', + 561: 'KEY_ROTATE_LOCK_TOGGLE', + 562: 'KEY_REFRESH_RATE_TOGGLE', + 576: 'KEY_BUTTONCONFIG', + 577: 'KEY_TASKMANAGER', + 578: 'KEY_JOURNAL', + 579: 'KEY_CONTROLPANEL', + 580: 'KEY_APPSELECT', + 581: 'KEY_SCREENSAVER', + 582: 'KEY_VOICECOMMAND', + 583: 'KEY_ASSISTANT', + 584: 'KEY_KBD_LAYOUT_NEXT', + 585: 'KEY_EMOJI_PICKER', + 586: 'KEY_DICTATE', + 587: 'KEY_CAMERA_ACCESS_ENABLE', + 588: 'KEY_CAMERA_ACCESS_DISABLE', + 589: 'KEY_CAMERA_ACCESS_TOGGLE', + 590: 'KEY_ACCESSIBILITY', + 591: 'KEY_DO_NOT_DISTURB', + 592: 'KEY_BRIGHTNESS_MIN', + 593: 'KEY_BRIGHTNESS_MAX', + 608: 'KEY_KBDINPUTASSIST_PREV', + 609: 'KEY_KBDINPUTASSIST_NEXT', + 610: 'KEY_KBDINPUTASSIST_PREVGROUP', + 611: 'KEY_KBDINPUTASSIST_NEXTGROUP', + 612: 'KEY_KBDINPUTASSIST_ACCEPT', + 613: 'KEY_KBDINPUTASSIST_CANCEL', + 614: 'KEY_RIGHT_UP', + 615: 'KEY_RIGHT_DOWN', + 616: 'KEY_LEFT_UP', + 617: 'KEY_LEFT_DOWN', + 618: 'KEY_ROOT_MENU', + 619: 'KEY_MEDIA_TOP_MENU', + 620: 'KEY_NUMERIC_11', + 621: 'KEY_NUMERIC_12', + 622: 'KEY_AUDIO_DESC', + 623: 'KEY_3D_MODE', + 624: 'KEY_NEXT_FAVORITE', + 625: 'KEY_STOP_RECORD', + 626: 'KEY_PAUSE_RECORD', + 627: 'KEY_VOD', + 628: 'KEY_UNMUTE', + 629: 'KEY_FASTREVERSE', + 630: 'KEY_SLOWREVERSE', + 631: 'KEY_DATA', + 632: 'KEY_ONSCREEN_KEYBOARD', + 633: 'KEY_PRIVACY_SCREEN_TOGGLE', + 634: 'KEY_SELECTIVE_SCREENSHOT', + 635: 'KEY_NEXT_ELEMENT', + 636: 'KEY_PREVIOUS_ELEMENT', + 637: 'KEY_AUTOPILOT_ENGAGE_TOGGLE', + 638: 'KEY_MARK_WAYPOINT', + 639: 'KEY_SOS', + 640: 'KEY_NAV_CHART', + 641: 'KEY_FISHING_CHART', + 642: 'KEY_SINGLE_RANGE_RADAR', + 643: 'KEY_DUAL_RANGE_RADAR', + 644: 'KEY_RADAR_OVERLAY', + 645: 'KEY_TRADITIONAL_SONAR', + 646: 'KEY_CLEARVU_SONAR', + 647: 'KEY_SIDEVU_SONAR', + 648: 'KEY_NAV_INFO', + 649: 'KEY_BRIGHTNESS_MENU', + 656: 'KEY_MACRO1', + 657: 'KEY_MACRO2', + 658: 'KEY_MACRO3', + 659: 'KEY_MACRO4', + 660: 'KEY_MACRO5', + 661: 'KEY_MACRO6', + 662: 'KEY_MACRO7', + 663: 'KEY_MACRO8', + 664: 'KEY_MACRO9', + 665: 'KEY_MACRO10', + 666: 'KEY_MACRO11', + 667: 'KEY_MACRO12', + 668: 'KEY_MACRO13', + 669: 'KEY_MACRO14', + 670: 'KEY_MACRO15', + 671: 'KEY_MACRO16', + 672: 'KEY_MACRO17', + 673: 'KEY_MACRO18', + 674: 'KEY_MACRO19', + 675: 'KEY_MACRO20', + 676: 'KEY_MACRO21', + 677: 'KEY_MACRO22', + 678: 'KEY_MACRO23', + 679: 'KEY_MACRO24', + 680: 'KEY_MACRO25', + 681: 'KEY_MACRO26', + 682: 'KEY_MACRO27', + 683: 'KEY_MACRO28', + 684: 'KEY_MACRO29', + 685: 'KEY_MACRO30', + 688: 'KEY_MACRO_RECORD_START', + 689: 'KEY_MACRO_RECORD_STOP', + 690: 'KEY_MACRO_PRESET_CYCLE', + 691: 'KEY_MACRO_PRESET1', + 692: 'KEY_MACRO_PRESET2', + 693: 'KEY_MACRO_PRESET3', + 696: 'KEY_KBD_LCD_MENU1', + 697: 'KEY_KBD_LCD_MENU2', + 698: 'KEY_KBD_LCD_MENU3', + 699: 'KEY_KBD_LCD_MENU4', + 700: 'KEY_KBD_LCD_MENU5', + 704: ('BTN_TRIGGER_HAPPY', 'BTN_TRIGGER_HAPPY1'), + 705: 'BTN_TRIGGER_HAPPY2', + 706: 'BTN_TRIGGER_HAPPY3', + 707: 'BTN_TRIGGER_HAPPY4', + 708: 'BTN_TRIGGER_HAPPY5', + 709: 'BTN_TRIGGER_HAPPY6', + 710: 'BTN_TRIGGER_HAPPY7', + 711: 'BTN_TRIGGER_HAPPY8', + 712: 'BTN_TRIGGER_HAPPY9', + 713: 'BTN_TRIGGER_HAPPY10', + 714: 'BTN_TRIGGER_HAPPY11', + 715: 'BTN_TRIGGER_HAPPY12', + 716: 'BTN_TRIGGER_HAPPY13', + 717: 'BTN_TRIGGER_HAPPY14', + 718: 'BTN_TRIGGER_HAPPY15', + 719: 'BTN_TRIGGER_HAPPY16', + 720: 'BTN_TRIGGER_HAPPY17', + 721: 'BTN_TRIGGER_HAPPY18', + 722: 'BTN_TRIGGER_HAPPY19', + 723: 'BTN_TRIGGER_HAPPY20', + 724: 'BTN_TRIGGER_HAPPY21', + 725: 'BTN_TRIGGER_HAPPY22', + 726: 'BTN_TRIGGER_HAPPY23', + 727: 'BTN_TRIGGER_HAPPY24', + 728: 'BTN_TRIGGER_HAPPY25', + 729: 'BTN_TRIGGER_HAPPY26', + 730: 'BTN_TRIGGER_HAPPY27', + 731: 'BTN_TRIGGER_HAPPY28', + 732: 'BTN_TRIGGER_HAPPY29', + 733: 'BTN_TRIGGER_HAPPY30', + 734: 'BTN_TRIGGER_HAPPY31', + 735: 'BTN_TRIGGER_HAPPY32', + 736: 'BTN_TRIGGER_HAPPY33', + 737: 'BTN_TRIGGER_HAPPY34', + 738: 'BTN_TRIGGER_HAPPY35', + 739: 'BTN_TRIGGER_HAPPY36', + 740: 'BTN_TRIGGER_HAPPY37', + 741: 'BTN_TRIGGER_HAPPY38', + 742: 'BTN_TRIGGER_HAPPY39', + 743: 'BTN_TRIGGER_HAPPY40'} + +KEY: Dict[int, Union[str, Tuple[str]]] = { 0: 'KEY_RESERVED', + 1: 'KEY_ESC', + 2: 'KEY_1', + 3: 'KEY_2', + 4: 'KEY_3', + 5: 'KEY_4', + 6: 'KEY_5', + 7: 'KEY_6', + 8: 'KEY_7', + 9: 'KEY_8', + 10: 'KEY_9', + 11: 'KEY_0', + 12: 'KEY_MINUS', + 13: 'KEY_EQUAL', + 14: 'KEY_BACKSPACE', + 15: 'KEY_TAB', + 16: 'KEY_Q', + 17: 'KEY_W', + 18: 'KEY_E', + 19: 'KEY_R', + 20: 'KEY_T', + 21: 'KEY_Y', + 22: 'KEY_U', + 23: 'KEY_I', + 24: 'KEY_O', + 25: 'KEY_P', + 26: 'KEY_LEFTBRACE', + 27: 'KEY_RIGHTBRACE', + 28: 'KEY_ENTER', + 29: 'KEY_LEFTCTRL', + 30: 'KEY_A', + 31: 'KEY_S', + 32: 'KEY_D', + 33: 'KEY_F', + 34: 'KEY_G', + 35: 'KEY_H', + 36: 'KEY_J', + 37: 'KEY_K', + 38: 'KEY_L', + 39: 'KEY_SEMICOLON', + 40: 'KEY_APOSTROPHE', + 41: 'KEY_GRAVE', + 42: 'KEY_LEFTSHIFT', + 43: 'KEY_BACKSLASH', + 44: 'KEY_Z', + 45: 'KEY_X', + 46: 'KEY_C', + 47: 'KEY_V', + 48: 'KEY_B', + 49: 'KEY_N', + 50: 'KEY_M', + 51: 'KEY_COMMA', + 52: 'KEY_DOT', + 53: 'KEY_SLASH', + 54: 'KEY_RIGHTSHIFT', + 55: 'KEY_KPASTERISK', + 56: 'KEY_LEFTALT', + 57: 'KEY_SPACE', + 58: 'KEY_CAPSLOCK', + 59: 'KEY_F1', + 60: 'KEY_F2', + 61: 'KEY_F3', + 62: 'KEY_F4', + 63: 'KEY_F5', + 64: 'KEY_F6', + 65: 'KEY_F7', + 66: 'KEY_F8', + 67: 'KEY_F9', + 68: 'KEY_F10', + 69: 'KEY_NUMLOCK', + 70: 'KEY_SCROLLLOCK', + 71: 'KEY_KP7', + 72: 'KEY_KP8', + 73: 'KEY_KP9', + 74: 'KEY_KPMINUS', + 75: 'KEY_KP4', + 76: 'KEY_KP5', + 77: 'KEY_KP6', + 78: 'KEY_KPPLUS', + 79: 'KEY_KP1', + 80: 'KEY_KP2', + 81: 'KEY_KP3', + 82: 'KEY_KP0', + 83: 'KEY_KPDOT', + 85: 'KEY_ZENKAKUHANKAKU', + 86: 'KEY_102ND', + 87: 'KEY_F11', + 88: 'KEY_F12', + 89: 'KEY_RO', + 90: 'KEY_KATAKANA', + 91: 'KEY_HIRAGANA', + 92: 'KEY_HENKAN', + 93: 'KEY_KATAKANAHIRAGANA', + 94: 'KEY_MUHENKAN', + 95: 'KEY_KPJPCOMMA', + 96: 'KEY_KPENTER', + 97: 'KEY_RIGHTCTRL', + 98: 'KEY_KPSLASH', + 99: 'KEY_SYSRQ', + 100: 'KEY_RIGHTALT', + 101: 'KEY_LINEFEED', + 102: 'KEY_HOME', + 103: 'KEY_UP', + 104: 'KEY_PAGEUP', + 105: 'KEY_LEFT', + 106: 'KEY_RIGHT', + 107: 'KEY_END', + 108: 'KEY_DOWN', + 109: 'KEY_PAGEDOWN', + 110: 'KEY_INSERT', + 111: 'KEY_DELETE', + 112: 'KEY_MACRO', + 113: ('KEY_MIN_INTERESTING', 'KEY_MUTE'), + 114: 'KEY_VOLUMEDOWN', + 115: 'KEY_VOLUMEUP', + 116: 'KEY_POWER', + 117: 'KEY_KPEQUAL', + 118: 'KEY_KPPLUSMINUS', + 119: 'KEY_PAUSE', + 120: 'KEY_SCALE', + 121: 'KEY_KPCOMMA', + 122: ('KEY_HANGEUL', 'KEY_HANGUEL'), + 123: 'KEY_HANJA', + 124: 'KEY_YEN', + 125: 'KEY_LEFTMETA', + 126: 'KEY_RIGHTMETA', + 127: 'KEY_COMPOSE', + 128: 'KEY_STOP', + 129: 'KEY_AGAIN', + 130: 'KEY_PROPS', + 131: 'KEY_UNDO', + 132: 'KEY_FRONT', + 133: 'KEY_COPY', + 134: 'KEY_OPEN', + 135: 'KEY_PASTE', + 136: 'KEY_FIND', + 137: 'KEY_CUT', + 138: 'KEY_HELP', + 139: 'KEY_MENU', + 140: 'KEY_CALC', + 141: 'KEY_SETUP', + 142: 'KEY_SLEEP', + 143: 'KEY_WAKEUP', + 144: 'KEY_FILE', + 145: 'KEY_SENDFILE', + 146: 'KEY_DELETEFILE', + 147: 'KEY_XFER', + 148: 'KEY_PROG1', + 149: 'KEY_PROG2', + 150: 'KEY_WWW', + 151: 'KEY_MSDOS', + 152: ('KEY_COFFEE', 'KEY_SCREENLOCK'), + 153: ('KEY_DIRECTION', 'KEY_ROTATE_DISPLAY'), + 154: 'KEY_CYCLEWINDOWS', + 155: 'KEY_MAIL', + 156: 'KEY_BOOKMARKS', + 157: 'KEY_COMPUTER', + 158: 'KEY_BACK', + 159: 'KEY_FORWARD', + 160: 'KEY_CLOSECD', + 161: 'KEY_EJECTCD', + 162: 'KEY_EJECTCLOSECD', + 163: 'KEY_NEXTSONG', + 164: 'KEY_PLAYPAUSE', + 165: 'KEY_PREVIOUSSONG', + 166: 'KEY_STOPCD', + 167: 'KEY_RECORD', + 168: 'KEY_REWIND', + 169: 'KEY_PHONE', + 170: 'KEY_ISO', + 171: 'KEY_CONFIG', + 172: 'KEY_HOMEPAGE', + 173: 'KEY_REFRESH', + 174: 'KEY_EXIT', + 175: 'KEY_MOVE', + 176: 'KEY_EDIT', + 177: 'KEY_SCROLLUP', + 178: 'KEY_SCROLLDOWN', + 179: 'KEY_KPLEFTPAREN', + 180: 'KEY_KPRIGHTPAREN', + 181: 'KEY_NEW', + 182: 'KEY_REDO', + 183: 'KEY_F13', + 184: 'KEY_F14', + 185: 'KEY_F15', + 186: 'KEY_F16', + 187: 'KEY_F17', + 188: 'KEY_F18', + 189: 'KEY_F19', + 190: 'KEY_F20', + 191: 'KEY_F21', + 192: 'KEY_F22', + 193: 'KEY_F23', + 194: 'KEY_F24', + 200: 'KEY_PLAYCD', + 201: 'KEY_PAUSECD', + 202: 'KEY_PROG3', + 203: 'KEY_PROG4', + 204: ('KEY_ALL_APPLICATIONS', 'KEY_DASHBOARD'), + 205: 'KEY_SUSPEND', + 206: 'KEY_CLOSE', + 207: 'KEY_PLAY', + 208: 'KEY_FASTFORWARD', + 209: 'KEY_BASSBOOST', + 210: 'KEY_PRINT', + 211: 'KEY_HP', + 212: 'KEY_CAMERA', + 213: 'KEY_SOUND', + 214: 'KEY_QUESTION', + 215: 'KEY_EMAIL', + 216: 'KEY_CHAT', + 217: 'KEY_SEARCH', + 218: 'KEY_CONNECT', + 219: 'KEY_FINANCE', + 220: 'KEY_SPORT', + 221: 'KEY_SHOP', + 222: 'KEY_ALTERASE', + 223: 'KEY_CANCEL', + 224: 'KEY_BRIGHTNESSDOWN', + 225: 'KEY_BRIGHTNESSUP', + 226: 'KEY_MEDIA', + 227: 'KEY_SWITCHVIDEOMODE', + 228: 'KEY_KBDILLUMTOGGLE', + 229: 'KEY_KBDILLUMDOWN', + 230: 'KEY_KBDILLUMUP', + 231: 'KEY_SEND', + 232: 'KEY_REPLY', + 233: 'KEY_FORWARDMAIL', + 234: 'KEY_SAVE', + 235: 'KEY_DOCUMENTS', + 236: 'KEY_BATTERY', + 237: 'KEY_BLUETOOTH', + 238: 'KEY_WLAN', + 239: 'KEY_UWB', + 240: 'KEY_UNKNOWN', + 241: 'KEY_VIDEO_NEXT', + 242: 'KEY_VIDEO_PREV', + 243: 'KEY_BRIGHTNESS_CYCLE', + 244: ('KEY_BRIGHTNESS_AUTO', 'KEY_BRIGHTNESS_ZERO'), + 245: 'KEY_DISPLAY_OFF', + 246: ('KEY_WIMAX', 'KEY_WWAN'), + 247: 'KEY_RFKILL', + 248: 'KEY_MICMUTE', + 352: 'KEY_OK', + 353: 'KEY_SELECT', + 354: 'KEY_GOTO', + 355: 'KEY_CLEAR', + 356: 'KEY_POWER2', + 357: 'KEY_OPTION', + 358: 'KEY_INFO', + 359: 'KEY_TIME', + 360: 'KEY_VENDOR', + 361: 'KEY_ARCHIVE', + 362: 'KEY_PROGRAM', + 363: 'KEY_CHANNEL', + 364: 'KEY_FAVORITES', + 365: 'KEY_EPG', + 366: 'KEY_PVR', + 367: 'KEY_MHP', + 368: 'KEY_LANGUAGE', + 369: 'KEY_TITLE', + 370: 'KEY_SUBTITLE', + 371: 'KEY_ANGLE', + 372: ('KEY_FULL_SCREEN', 'KEY_ZOOM'), + 373: 'KEY_MODE', + 374: 'KEY_KEYBOARD', + 375: ('KEY_ASPECT_RATIO', 'KEY_SCREEN'), + 376: 'KEY_PC', + 377: 'KEY_TV', + 378: 'KEY_TV2', + 379: 'KEY_VCR', + 380: 'KEY_VCR2', + 381: 'KEY_SAT', + 382: 'KEY_SAT2', + 383: 'KEY_CD', + 384: 'KEY_TAPE', + 385: 'KEY_RADIO', + 386: 'KEY_TUNER', + 387: 'KEY_PLAYER', + 388: 'KEY_TEXT', + 389: 'KEY_DVD', + 390: 'KEY_AUX', + 391: 'KEY_MP3', + 392: 'KEY_AUDIO', + 393: 'KEY_VIDEO', + 394: 'KEY_DIRECTORY', + 395: 'KEY_LIST', + 396: 'KEY_MEMO', + 397: 'KEY_CALENDAR', + 398: 'KEY_RED', + 399: 'KEY_GREEN', + 400: 'KEY_YELLOW', + 401: 'KEY_BLUE', + 402: 'KEY_CHANNELUP', + 403: 'KEY_CHANNELDOWN', + 404: 'KEY_FIRST', + 405: 'KEY_LAST', + 406: 'KEY_AB', + 407: 'KEY_NEXT', + 408: 'KEY_RESTART', + 409: 'KEY_SLOW', + 410: 'KEY_SHUFFLE', + 411: 'KEY_BREAK', + 412: 'KEY_PREVIOUS', + 413: 'KEY_DIGITS', + 414: 'KEY_TEEN', + 415: 'KEY_TWEN', + 416: 'KEY_VIDEOPHONE', + 417: 'KEY_GAMES', + 418: 'KEY_ZOOMIN', + 419: 'KEY_ZOOMOUT', + 420: 'KEY_ZOOMRESET', + 421: 'KEY_WORDPROCESSOR', + 422: 'KEY_EDITOR', + 423: 'KEY_SPREADSHEET', + 424: 'KEY_GRAPHICSEDITOR', + 425: 'KEY_PRESENTATION', + 426: 'KEY_DATABASE', + 427: 'KEY_NEWS', + 428: 'KEY_VOICEMAIL', + 429: 'KEY_ADDRESSBOOK', + 430: 'KEY_MESSENGER', + 431: ('KEY_BRIGHTNESS_TOGGLE', 'KEY_DISPLAYTOGGLE'), + 432: 'KEY_SPELLCHECK', + 433: 'KEY_LOGOFF', + 434: 'KEY_DOLLAR', + 435: 'KEY_EURO', + 436: 'KEY_FRAMEBACK', + 437: 'KEY_FRAMEFORWARD', + 438: 'KEY_CONTEXT_MENU', + 439: 'KEY_MEDIA_REPEAT', + 440: 'KEY_10CHANNELSUP', + 441: 'KEY_10CHANNELSDOWN', + 442: 'KEY_IMAGES', + 444: 'KEY_NOTIFICATION_CENTER', + 445: 'KEY_PICKUP_PHONE', + 446: 'KEY_HANGUP_PHONE', + 447: 'KEY_LINK_PHONE', + 448: 'KEY_DEL_EOL', + 449: 'KEY_DEL_EOS', + 450: 'KEY_INS_LINE', + 451: 'KEY_DEL_LINE', + 464: 'KEY_FN', + 465: 'KEY_FN_ESC', + 466: 'KEY_FN_F1', + 467: 'KEY_FN_F2', + 468: 'KEY_FN_F3', + 469: 'KEY_FN_F4', + 470: 'KEY_FN_F5', + 471: 'KEY_FN_F6', + 472: 'KEY_FN_F7', + 473: 'KEY_FN_F8', + 474: 'KEY_FN_F9', + 475: 'KEY_FN_F10', + 476: 'KEY_FN_F11', + 477: 'KEY_FN_F12', + 478: 'KEY_FN_1', + 479: 'KEY_FN_2', + 480: 'KEY_FN_D', + 481: 'KEY_FN_E', + 482: 'KEY_FN_F', + 483: 'KEY_FN_S', + 484: 'KEY_FN_B', + 485: 'KEY_FN_RIGHT_SHIFT', + 497: 'KEY_BRL_DOT1', + 498: 'KEY_BRL_DOT2', + 499: 'KEY_BRL_DOT3', + 500: 'KEY_BRL_DOT4', + 501: 'KEY_BRL_DOT5', + 502: 'KEY_BRL_DOT6', + 503: 'KEY_BRL_DOT7', + 504: 'KEY_BRL_DOT8', + 505: 'KEY_BRL_DOT9', + 506: 'KEY_BRL_DOT10', + 512: 'KEY_NUMERIC_0', + 513: 'KEY_NUMERIC_1', + 514: 'KEY_NUMERIC_2', + 515: 'KEY_NUMERIC_3', + 516: 'KEY_NUMERIC_4', + 517: 'KEY_NUMERIC_5', + 518: 'KEY_NUMERIC_6', + 519: 'KEY_NUMERIC_7', + 520: 'KEY_NUMERIC_8', + 521: 'KEY_NUMERIC_9', + 522: 'KEY_NUMERIC_STAR', + 523: 'KEY_NUMERIC_POUND', + 524: 'KEY_NUMERIC_A', + 525: 'KEY_NUMERIC_B', + 526: 'KEY_NUMERIC_C', + 527: 'KEY_NUMERIC_D', + 528: 'KEY_CAMERA_FOCUS', + 529: 'KEY_WPS_BUTTON', + 530: 'KEY_TOUCHPAD_TOGGLE', + 531: 'KEY_TOUCHPAD_ON', + 532: 'KEY_TOUCHPAD_OFF', + 533: 'KEY_CAMERA_ZOOMIN', + 534: 'KEY_CAMERA_ZOOMOUT', + 535: 'KEY_CAMERA_UP', + 536: 'KEY_CAMERA_DOWN', + 537: 'KEY_CAMERA_LEFT', + 538: 'KEY_CAMERA_RIGHT', + 539: 'KEY_ATTENDANT_ON', + 540: 'KEY_ATTENDANT_OFF', + 541: 'KEY_ATTENDANT_TOGGLE', + 542: 'KEY_LIGHTS_TOGGLE', + 560: 'KEY_ALS_TOGGLE', + 561: 'KEY_ROTATE_LOCK_TOGGLE', + 562: 'KEY_REFRESH_RATE_TOGGLE', + 576: 'KEY_BUTTONCONFIG', + 577: 'KEY_TASKMANAGER', + 578: 'KEY_JOURNAL', + 579: 'KEY_CONTROLPANEL', + 580: 'KEY_APPSELECT', + 581: 'KEY_SCREENSAVER', + 582: 'KEY_VOICECOMMAND', + 583: 'KEY_ASSISTANT', + 584: 'KEY_KBD_LAYOUT_NEXT', + 585: 'KEY_EMOJI_PICKER', + 586: 'KEY_DICTATE', + 587: 'KEY_CAMERA_ACCESS_ENABLE', + 588: 'KEY_CAMERA_ACCESS_DISABLE', + 589: 'KEY_CAMERA_ACCESS_TOGGLE', + 590: 'KEY_ACCESSIBILITY', + 591: 'KEY_DO_NOT_DISTURB', + 592: 'KEY_BRIGHTNESS_MIN', + 593: 'KEY_BRIGHTNESS_MAX', + 608: 'KEY_KBDINPUTASSIST_PREV', + 609: 'KEY_KBDINPUTASSIST_NEXT', + 610: 'KEY_KBDINPUTASSIST_PREVGROUP', + 611: 'KEY_KBDINPUTASSIST_NEXTGROUP', + 612: 'KEY_KBDINPUTASSIST_ACCEPT', + 613: 'KEY_KBDINPUTASSIST_CANCEL', + 614: 'KEY_RIGHT_UP', + 615: 'KEY_RIGHT_DOWN', + 616: 'KEY_LEFT_UP', + 617: 'KEY_LEFT_DOWN', + 618: 'KEY_ROOT_MENU', + 619: 'KEY_MEDIA_TOP_MENU', + 620: 'KEY_NUMERIC_11', + 621: 'KEY_NUMERIC_12', + 622: 'KEY_AUDIO_DESC', + 623: 'KEY_3D_MODE', + 624: 'KEY_NEXT_FAVORITE', + 625: 'KEY_STOP_RECORD', + 626: 'KEY_PAUSE_RECORD', + 627: 'KEY_VOD', + 628: 'KEY_UNMUTE', + 629: 'KEY_FASTREVERSE', + 630: 'KEY_SLOWREVERSE', + 631: 'KEY_DATA', + 632: 'KEY_ONSCREEN_KEYBOARD', + 633: 'KEY_PRIVACY_SCREEN_TOGGLE', + 634: 'KEY_SELECTIVE_SCREENSHOT', + 635: 'KEY_NEXT_ELEMENT', + 636: 'KEY_PREVIOUS_ELEMENT', + 637: 'KEY_AUTOPILOT_ENGAGE_TOGGLE', + 638: 'KEY_MARK_WAYPOINT', + 639: 'KEY_SOS', + 640: 'KEY_NAV_CHART', + 641: 'KEY_FISHING_CHART', + 642: 'KEY_SINGLE_RANGE_RADAR', + 643: 'KEY_DUAL_RANGE_RADAR', + 644: 'KEY_RADAR_OVERLAY', + 645: 'KEY_TRADITIONAL_SONAR', + 646: 'KEY_CLEARVU_SONAR', + 647: 'KEY_SIDEVU_SONAR', + 648: 'KEY_NAV_INFO', + 649: 'KEY_BRIGHTNESS_MENU', + 656: 'KEY_MACRO1', + 657: 'KEY_MACRO2', + 658: 'KEY_MACRO3', + 659: 'KEY_MACRO4', + 660: 'KEY_MACRO5', + 661: 'KEY_MACRO6', + 662: 'KEY_MACRO7', + 663: 'KEY_MACRO8', + 664: 'KEY_MACRO9', + 665: 'KEY_MACRO10', + 666: 'KEY_MACRO11', + 667: 'KEY_MACRO12', + 668: 'KEY_MACRO13', + 669: 'KEY_MACRO14', + 670: 'KEY_MACRO15', + 671: 'KEY_MACRO16', + 672: 'KEY_MACRO17', + 673: 'KEY_MACRO18', + 674: 'KEY_MACRO19', + 675: 'KEY_MACRO20', + 676: 'KEY_MACRO21', + 677: 'KEY_MACRO22', + 678: 'KEY_MACRO23', + 679: 'KEY_MACRO24', + 680: 'KEY_MACRO25', + 681: 'KEY_MACRO26', + 682: 'KEY_MACRO27', + 683: 'KEY_MACRO28', + 684: 'KEY_MACRO29', + 685: 'KEY_MACRO30', + 688: 'KEY_MACRO_RECORD_START', + 689: 'KEY_MACRO_RECORD_STOP', + 690: 'KEY_MACRO_PRESET_CYCLE', + 691: 'KEY_MACRO_PRESET1', + 692: 'KEY_MACRO_PRESET2', + 693: 'KEY_MACRO_PRESET3', + 696: 'KEY_KBD_LCD_MENU1', + 697: 'KEY_KBD_LCD_MENU2', + 698: 'KEY_KBD_LCD_MENU3', + 699: 'KEY_KBD_LCD_MENU4', + 700: 'KEY_KBD_LCD_MENU5', + 767: 'KEY_MAX', + 768: 'KEY_CNT'} + +ABS: Dict[int, Union[str, Tuple[str]]] = { 0: 'ABS_X', + 1: 'ABS_Y', + 2: 'ABS_Z', + 3: 'ABS_RX', + 4: 'ABS_RY', + 5: 'ABS_RZ', + 6: 'ABS_THROTTLE', + 7: 'ABS_RUDDER', + 8: 'ABS_WHEEL', + 9: 'ABS_GAS', + 10: 'ABS_BRAKE', + 16: 'ABS_HAT0X', + 17: 'ABS_HAT0Y', + 18: 'ABS_HAT1X', + 19: 'ABS_HAT1Y', + 20: 'ABS_HAT2X', + 21: 'ABS_HAT2Y', + 22: 'ABS_HAT3X', + 23: 'ABS_HAT3Y', + 24: 'ABS_PRESSURE', + 25: 'ABS_DISTANCE', + 26: 'ABS_TILT_X', + 27: 'ABS_TILT_Y', + 28: 'ABS_TOOL_WIDTH', + 32: 'ABS_VOLUME', + 33: 'ABS_PROFILE', + 40: 'ABS_MISC', + 46: 'ABS_RESERVED', + 47: 'ABS_MT_SLOT', + 48: 'ABS_MT_TOUCH_MAJOR', + 49: 'ABS_MT_TOUCH_MINOR', + 50: 'ABS_MT_WIDTH_MAJOR', + 51: 'ABS_MT_WIDTH_MINOR', + 52: 'ABS_MT_ORIENTATION', + 53: 'ABS_MT_POSITION_X', + 54: 'ABS_MT_POSITION_Y', + 55: 'ABS_MT_TOOL_TYPE', + 56: 'ABS_MT_BLOB_ID', + 57: 'ABS_MT_TRACKING_ID', + 58: 'ABS_MT_PRESSURE', + 59: 'ABS_MT_DISTANCE', + 60: 'ABS_MT_TOOL_X', + 61: 'ABS_MT_TOOL_Y', + 63: 'ABS_MAX', + 64: 'ABS_CNT'} + +REL: Dict[int, Union[str, Tuple[str]]] = { 0: 'REL_X', + 1: 'REL_Y', + 2: 'REL_Z', + 3: 'REL_RX', + 4: 'REL_RY', + 5: 'REL_RZ', + 6: 'REL_HWHEEL', + 7: 'REL_DIAL', + 8: 'REL_WHEEL', + 9: 'REL_MISC', + 10: 'REL_RESERVED', + 11: 'REL_WHEEL_HI_RES', + 12: 'REL_HWHEEL_HI_RES', + 15: 'REL_MAX', + 16: 'REL_CNT'} + +SW: Dict[int, Union[str, Tuple[str]]] = { 0: 'SW_LID', + 1: 'SW_TABLET_MODE', + 2: 'SW_HEADPHONE_INSERT', + 3: ('SW_RADIO', 'SW_RFKILL_ALL'), + 4: 'SW_MICROPHONE_INSERT', + 5: 'SW_DOCK', + 6: 'SW_LINEOUT_INSERT', + 7: 'SW_JACK_PHYSICAL_INSERT', + 8: 'SW_VIDEOOUT_INSERT', + 9: 'SW_CAMERA_LENS_COVER', + 10: 'SW_KEYPAD_SLIDE', + 11: 'SW_FRONT_PROXIMITY', + 12: 'SW_ROTATE_LOCK', + 13: 'SW_LINEIN_INSERT', + 14: 'SW_MUTE_DEVICE', + 15: 'SW_PEN_INSERTED', + 16: ('SW_MACHINE_COVER', 'SW_MAX'), + 17: 'SW_CNT'} + +MSC: Dict[int, Union[str, Tuple[str]]] = { 0: 'MSC_SERIAL', + 1: 'MSC_PULSELED', + 2: 'MSC_GESTURE', + 3: 'MSC_RAW', + 4: 'MSC_SCAN', + 5: 'MSC_TIMESTAMP', + 7: 'MSC_MAX', + 8: 'MSC_CNT'} + +LED: Dict[int, Union[str, Tuple[str]]] = { 0: 'LED_NUML', + 1: 'LED_CAPSL', + 2: 'LED_SCROLLL', + 3: 'LED_COMPOSE', + 4: 'LED_KANA', + 5: 'LED_SLEEP', + 6: 'LED_SUSPEND', + 7: 'LED_MUTE', + 8: 'LED_MISC', + 9: 'LED_MAIL', + 10: 'LED_CHARGING', + 15: 'LED_MAX', + 16: 'LED_CNT'} + +BTN: Dict[int, Union[str, Tuple[str]]] = { 256: ('BTN_0', 'BTN_MISC'), + 257: 'BTN_1', + 258: 'BTN_2', + 259: 'BTN_3', + 260: 'BTN_4', + 261: 'BTN_5', + 262: 'BTN_6', + 263: 'BTN_7', + 264: 'BTN_8', + 265: 'BTN_9', + 272: ('BTN_LEFT', 'BTN_MOUSE'), + 273: 'BTN_RIGHT', + 274: 'BTN_MIDDLE', + 275: 'BTN_SIDE', + 276: 'BTN_EXTRA', + 277: 'BTN_FORWARD', + 278: 'BTN_BACK', + 279: 'BTN_TASK', + 288: ('BTN_JOYSTICK', 'BTN_TRIGGER'), + 289: 'BTN_THUMB', + 290: 'BTN_THUMB2', + 291: 'BTN_TOP', + 292: 'BTN_TOP2', + 293: 'BTN_PINKIE', + 294: 'BTN_BASE', + 295: 'BTN_BASE2', + 296: 'BTN_BASE3', + 297: 'BTN_BASE4', + 298: 'BTN_BASE5', + 299: 'BTN_BASE6', + 303: 'BTN_DEAD', + 304: ('BTN_A', 'BTN_GAMEPAD', 'BTN_SOUTH'), + 305: ('BTN_B', 'BTN_EAST'), + 306: 'BTN_C', + 307: ('BTN_NORTH', 'BTN_X'), + 308: ('BTN_WEST', 'BTN_Y'), + 309: 'BTN_Z', + 310: 'BTN_TL', + 311: 'BTN_TR', + 312: 'BTN_TL2', + 313: 'BTN_TR2', + 314: 'BTN_SELECT', + 315: 'BTN_START', + 316: 'BTN_MODE', + 317: 'BTN_THUMBL', + 318: 'BTN_THUMBR', + 320: ('BTN_DIGI', 'BTN_TOOL_PEN'), + 321: 'BTN_TOOL_RUBBER', + 322: 'BTN_TOOL_BRUSH', + 323: 'BTN_TOOL_PENCIL', + 324: 'BTN_TOOL_AIRBRUSH', + 325: 'BTN_TOOL_FINGER', + 326: 'BTN_TOOL_MOUSE', + 327: 'BTN_TOOL_LENS', + 328: 'BTN_TOOL_QUINTTAP', + 329: 'BTN_STYLUS3', + 330: 'BTN_TOUCH', + 331: 'BTN_STYLUS', + 332: 'BTN_STYLUS2', + 333: 'BTN_TOOL_DOUBLETAP', + 334: 'BTN_TOOL_TRIPLETAP', + 335: 'BTN_TOOL_QUADTAP', + 336: ('BTN_GEAR_DOWN', 'BTN_WHEEL'), + 337: 'BTN_GEAR_UP', + 544: 'BTN_DPAD_UP', + 545: 'BTN_DPAD_DOWN', + 546: 'BTN_DPAD_LEFT', + 547: 'BTN_DPAD_RIGHT', + 704: ('BTN_TRIGGER_HAPPY', 'BTN_TRIGGER_HAPPY1'), + 705: 'BTN_TRIGGER_HAPPY2', + 706: 'BTN_TRIGGER_HAPPY3', + 707: 'BTN_TRIGGER_HAPPY4', + 708: 'BTN_TRIGGER_HAPPY5', + 709: 'BTN_TRIGGER_HAPPY6', + 710: 'BTN_TRIGGER_HAPPY7', + 711: 'BTN_TRIGGER_HAPPY8', + 712: 'BTN_TRIGGER_HAPPY9', + 713: 'BTN_TRIGGER_HAPPY10', + 714: 'BTN_TRIGGER_HAPPY11', + 715: 'BTN_TRIGGER_HAPPY12', + 716: 'BTN_TRIGGER_HAPPY13', + 717: 'BTN_TRIGGER_HAPPY14', + 718: 'BTN_TRIGGER_HAPPY15', + 719: 'BTN_TRIGGER_HAPPY16', + 720: 'BTN_TRIGGER_HAPPY17', + 721: 'BTN_TRIGGER_HAPPY18', + 722: 'BTN_TRIGGER_HAPPY19', + 723: 'BTN_TRIGGER_HAPPY20', + 724: 'BTN_TRIGGER_HAPPY21', + 725: 'BTN_TRIGGER_HAPPY22', + 726: 'BTN_TRIGGER_HAPPY23', + 727: 'BTN_TRIGGER_HAPPY24', + 728: 'BTN_TRIGGER_HAPPY25', + 729: 'BTN_TRIGGER_HAPPY26', + 730: 'BTN_TRIGGER_HAPPY27', + 731: 'BTN_TRIGGER_HAPPY28', + 732: 'BTN_TRIGGER_HAPPY29', + 733: 'BTN_TRIGGER_HAPPY30', + 734: 'BTN_TRIGGER_HAPPY31', + 735: 'BTN_TRIGGER_HAPPY32', + 736: 'BTN_TRIGGER_HAPPY33', + 737: 'BTN_TRIGGER_HAPPY34', + 738: 'BTN_TRIGGER_HAPPY35', + 739: 'BTN_TRIGGER_HAPPY36', + 740: 'BTN_TRIGGER_HAPPY37', + 741: 'BTN_TRIGGER_HAPPY38', + 742: 'BTN_TRIGGER_HAPPY39', + 743: 'BTN_TRIGGER_HAPPY40'} + +REP: Dict[int, Union[str, Tuple[str]]] = {0: 'REP_DELAY', 1: ('REP_MAX', 'REP_PERIOD'), 2: 'REP_CNT'} + +SND: Dict[int, Union[str, Tuple[str]]] = {0: 'SND_CLICK', 1: 'SND_BELL', 2: 'SND_TONE', 7: 'SND_MAX', 8: 'SND_CNT'} + +ID: Dict[int, Union[str, Tuple[str]]] = {0: 'ID_BUS', 1: 'ID_VENDOR', 2: 'ID_PRODUCT', 3: 'ID_VERSION'} + +EV: Dict[int, Union[str, Tuple[str]]] = { 0: 'EV_SYN', + 1: 'EV_KEY', + 2: 'EV_REL', + 3: 'EV_ABS', + 4: 'EV_MSC', + 5: 'EV_SW', + 17: 'EV_LED', + 18: 'EV_SND', + 20: 'EV_REP', + 21: 'EV_FF', + 22: 'EV_PWR', + 23: 'EV_FF_STATUS', + 31: 'EV_MAX', + 32: 'EV_CNT', + 257: 'EV_UINPUT', + 65537: 'EV_VERSION'} + +BUS: Dict[int, Union[str, Tuple[str]]] = { 1: 'BUS_PCI', + 2: 'BUS_ISAPNP', + 3: 'BUS_USB', + 4: 'BUS_HIL', + 5: 'BUS_BLUETOOTH', + 6: 'BUS_VIRTUAL', + 16: 'BUS_ISA', + 17: 'BUS_I8042', + 18: 'BUS_XTKBD', + 19: 'BUS_RS232', + 20: 'BUS_GAMEPORT', + 21: 'BUS_PARPORT', + 22: 'BUS_AMIGA', + 23: 'BUS_ADB', + 24: 'BUS_I2C', + 25: 'BUS_HOST', + 26: 'BUS_GSC', + 27: 'BUS_ATARI', + 28: 'BUS_SPI', + 29: 'BUS_RMI', + 30: 'BUS_CEC', + 31: 'BUS_INTEL_ISHTP', + 32: 'BUS_AMD_SFH'} + +SYN: Dict[int, Union[str, Tuple[str]]] = {0: 'SYN_REPORT', 1: 'SYN_CONFIG', 2: 'SYN_MT_REPORT', 3: 'SYN_DROPPED', 15: 'SYN_MAX', 16: 'SYN_CNT'} + +FF: Dict[int, Union[str, Tuple[str]]] = { 80: ('FF_EFFECT_MIN', 'FF_RUMBLE'), + 81: 'FF_PERIODIC', + 82: 'FF_CONSTANT', + 83: 'FF_SPRING', + 84: 'FF_FRICTION', + 85: 'FF_DAMPER', + 86: 'FF_INERTIA', + 87: ('FF_EFFECT_MAX', 'FF_RAMP'), + 88: ('FF_SQUARE', 'FF_WAVEFORM_MIN'), + 89: 'FF_TRIANGLE', + 90: 'FF_SINE', + 91: 'FF_SAW_UP', + 92: 'FF_SAW_DOWN', + 93: ('FF_CUSTOM', 'FF_WAVEFORM_MAX'), + 96: ('FF_GAIN', 'FF_MAX_EFFECTS'), + 97: 'FF_AUTOCENTER', + 127: 'FF_MAX', + 128: 'FF_CNT'} + +UI_FF: Dict[int, Union[str, Tuple[str]]] = {1: 'UI_FF_UPLOAD', 2: 'UI_FF_ERASE'} + +FF_STATUS: Dict[int, Union[str, Tuple[str]]] = {0: 'FF_STATUS_STOPPED', 1: ('FF_STATUS_MAX', 'FF_STATUS_PLAYING')} + +INPUT_PROP: Dict[int, Union[str, Tuple[str]]] = { 0: 'INPUT_PROP_POINTER', + 1: 'INPUT_PROP_DIRECT', + 2: 'INPUT_PROP_BUTTONPAD', + 3: 'INPUT_PROP_SEMI_MT', + 4: 'INPUT_PROP_TOPBUTTONPAD', + 5: 'INPUT_PROP_POINTING_STICK', + 6: 'INPUT_PROP_ACCELEROMETER', + 31: 'INPUT_PROP_MAX', + 32: 'INPUT_PROP_CNT'} + diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/ecodes_runtime.py b/CLI/venv/lib/python3.12/site-packages/evdev/ecodes_runtime.py new file mode 100644 index 0000000..47f3b23 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/ecodes_runtime.py @@ -0,0 +1,111 @@ +# pylint: disable=undefined-variable +""" +This modules exposes the integer constants defined in ``linux/input.h`` and +``linux/input-event-codes.h``. + +Exposed constants:: + + KEY, ABS, REL, SW, MSC, LED, BTN, REP, SND, ID, EV, + BUS, SYN, FF, FF_STATUS, INPUT_PROP + +This module also provides reverse and forward mappings of the names and values +of the above mentioned constants:: + + >>> evdev.ecodes.KEY_A + 30 + + >>> evdev.ecodes.ecodes['KEY_A'] + 30 + + >>> evdev.ecodes.KEY[30] + 'KEY_A' + + >>> evdev.ecodes.REL[0] + 'REL_X' + + >>> evdev.ecodes.EV[evdev.ecodes.EV_KEY] + 'EV_KEY' + + >>> evdev.ecodes.bytype[evdev.ecodes.EV_REL][0] + 'REL_X' + +Keep in mind that values in reverse mappings may point to one or more event +codes. For example:: + + >>> evdev.ecodes.FF[80] + ('FF_EFFECT_MIN', 'FF_RUMBLE') + + >>> evdev.ecodes.FF[81] + 'FF_PERIODIC' +""" + +from inspect import getmembers + +from . import _ecodes + +#: Mapping of names to values. +ecodes = {} + +prefixes = "KEY ABS REL SW MSC LED BTN REP SND ID EV BUS SYN FF_STATUS FF INPUT_PROP UI_FF".split() +prev_prefix = "" +g = globals() + +# eg. code: 'REL_Z', val: 2 +for code, val in getmembers(_ecodes): + for prefix in prefixes: # eg. 'REL' + if code.startswith(prefix): + ecodes[code] = val + # FF_STATUS codes should not appear in the FF reverse mapping + if not code.startswith(prev_prefix): + d = g.setdefault(prefix, {}) + # codes that share the same value will be added to a list. eg: + # >>> ecodes.FF_STATUS + # {0: 'FF_STATUS_STOPPED', 1: ['FF_STATUS_MAX', 'FF_STATUS_PLAYING']} + if val in d: + if isinstance(d[val], list): + d[val].append(code) + else: + d[val] = [d[val], code] + else: + d[val] = code + + prev_prefix = prefix + + +# Convert lists to tuples. +k, v = None, None +for prefix in prefixes: + for k, v in g[prefix].items(): + if isinstance(v, list): + g[prefix][k] = tuple(v) + + +#: Keys are a combination of all BTN and KEY codes. +keys = {} +keys.update(BTN) +keys.update(KEY) + +# make keys safe to use for the default list of uinput device +# capabilities +del keys[_ecodes.KEY_MAX] +del keys[_ecodes.KEY_CNT] + +#: Mapping of event types to other value/name mappings. +bytype = { + _ecodes.EV_KEY: keys, + _ecodes.EV_ABS: ABS, + _ecodes.EV_REL: REL, + _ecodes.EV_SW: SW, + _ecodes.EV_MSC: MSC, + _ecodes.EV_LED: LED, + _ecodes.EV_REP: REP, + _ecodes.EV_SND: SND, + _ecodes.EV_SYN: SYN, + _ecodes.EV_FF: FF, + _ecodes.EV_FF_STATUS: FF_STATUS, +} + +from evdev._ecodes import * + +# cheaper than whitelisting in an __all__ +del code, val, prefix, getmembers, g, d, k, v, prefixes, prev_prefix diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/eventio.py b/CLI/venv/lib/python3.12/site-packages/evdev/eventio.py new file mode 100644 index 0000000..bdb91a4 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/eventio.py @@ -0,0 +1,152 @@ +import fcntl +import functools +import os +import select +from typing import Iterator, Union + +from . import _input, _uinput, ecodes +from .events import InputEvent + + +# -------------------------------------------------------------------------- +class EvdevError(Exception): + pass + + +class EventIO: + """ + Base class for reading and writing input events. + + This class is used by :class:`InputDevice` and :class:`UInput`. + + - On, :class:`InputDevice` it used for reading user-generated events (e.g. + key presses, mouse movements) and writing feedback events (e.g. leds, + beeps). + + - On, :class:`UInput` it used for writing user-generated events (e.g. + key presses, mouse movements) and reading feedback events (e.g. leds, + beeps). + """ + + def fileno(self): + """ + Return the file descriptor to the open event device. This makes + it possible to pass instances directly to :func:`select.select()` and + :class:`asyncore.file_dispatcher`. + """ + return self.fd + + def read_loop(self) -> Iterator[InputEvent]: + """ + Enter an endless :func:`select.select()` loop that yields input events. + """ + + while True: + r, w, x = select.select([self.fd], [], []) + for event in self.read(): + yield event + + def read_one(self) -> Union[InputEvent, None]: + """ + Read and return a single input event as an instance of + :class:`InputEvent `. + + Return ``None`` if there are no pending input events. + """ + + # event -> (sec, usec, type, code, val) + event = _input.device_read(self.fd) + + if event: + return InputEvent(*event) + + def read(self) -> Iterator[InputEvent]: + """ + Read multiple input events from device. Return a generator object that + yields :class:`InputEvent ` instances. Raises + `BlockingIOError` if there are no available events at the moment. + """ + + # events -> ((sec, usec, type, code, val), ...) + events = _input.device_read_many(self.fd) + + for event in events: + yield InputEvent(*event) + + # pylint: disable=no-self-argument + def need_write(func): + """ + Decorator that raises :class:`EvdevError` if there is no write access to the + input device. + """ + + @functools.wraps(func) + def wrapper(*args): + fd = args[0].fd + if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR: + # pylint: disable=not-callable + return func(*args) + msg = 'no write access to device "%s"' % args[0].path + raise EvdevError(msg) + + return wrapper + + def write_event(self, event): + """ + Inject an input event into the input subsystem. Events are + queued until a synchronization event is received. + + Arguments + --------- + event: InputEvent + InputEvent instance or an object with an ``event`` attribute + (:class:`KeyEvent `, :class:`RelEvent + ` etc). + + Example + ------- + >>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1) + >>> ui.write_event(ev) + """ + + if hasattr(event, "event"): + event = event.event + + self.write(event.type, event.code, event.value) + + @need_write + def write(self, etype: int, code: int, value: int): + """ + Inject an input event into the input subsystem. Events are + queued until a synchronization event is received. + + Arguments + --------- + etype + event type (e.g. ``EV_KEY``). + + code + event code (e.g. ``KEY_A``). + + value + event value (e.g. 0 1 2 - depends on event type). + + Example + --------- + >>> ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down + >>> ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up + """ + + _uinput.write(self.fd, etype, code, value) + + def syn(self): + """ + Inject a ``SYN_REPORT`` event into the input subsystem. Events + queued by :func:`write()` will be fired. If possible, events + will be merged into an 'atomic' event. + """ + + self.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0) + + def close(self): + pass diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/eventio_async.py b/CLI/venv/lib/python3.12/site-packages/evdev/eventio_async.py new file mode 100644 index 0000000..4af1aab --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/eventio_async.py @@ -0,0 +1,106 @@ +import asyncio +import select +import sys + +from . import eventio +from .events import InputEvent + +# needed for compatibility +from .eventio import EvdevError + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing import Any as Self + + +class ReadIterator: + def __init__(self, device): + self.current_batch = iter(()) + self.device = device + + # Standard iterator protocol. + def __iter__(self) -> Self: + return self + + def __next__(self) -> InputEvent: + try: + # Read from the previous batch of events. + return next(self.current_batch) + except StopIteration: + r, w, x = select.select([self.device.fd], [], []) + self.current_batch = self.device.read() + return next(self.current_batch) + + def __aiter__(self) -> Self: + return self + + def __anext__(self) -> "asyncio.Future[InputEvent]": + future = asyncio.Future() + try: + # Read from the previous batch of events. + future.set_result(next(self.current_batch)) + except StopIteration: + + def next_batch_ready(batch): + try: + self.current_batch = batch.result() + future.set_result(next(self.current_batch)) + except Exception as e: + future.set_exception(e) + + self.device.async_read().add_done_callback(next_batch_ready) + return future + + +class EventIO(eventio.EventIO): + def _do_when_readable(self, callback): + loop = asyncio.get_event_loop() + + def ready(): + loop.remove_reader(self.fileno()) + callback() + + loop.add_reader(self.fileno(), ready) + + def _set_result(self, future, cb): + try: + future.set_result(cb()) + except Exception as error: + future.set_exception(error) + + def async_read_one(self): + """ + Asyncio coroutine to read and return a single input event as + an instance of :class:`InputEvent `. + """ + future = asyncio.Future() + self._do_when_readable(lambda: self._set_result(future, self.read_one)) + return future + + def async_read(self): + """ + Asyncio coroutine to read multiple input events from device. Return + a generator object that yields :class:`InputEvent ` + instances. + """ + future = asyncio.Future() + self._do_when_readable(lambda: self._set_result(future, self.read)) + return future + + def async_read_loop(self) -> ReadIterator: + """ + Return an iterator that yields input events. This iterator is + compatible with the ``async for`` syntax. + + """ + return ReadIterator(self) + + def close(self): + try: + loop = asyncio.get_event_loop() + loop.remove_reader(self.fileno()) + except RuntimeError: + # no event loop present, so there is nothing to + # remove the reader from. Ignore + pass diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/events.py b/CLI/venv/lib/python3.12/site-packages/evdev/events.py new file mode 100644 index 0000000..922bfe6 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/events.py @@ -0,0 +1,192 @@ +""" +This module provides the :class:`InputEvent` class, which closely +resembles the ``input_event`` struct defined in ``linux/input.h``: + +.. code-block:: c + + struct input_event { + struct timeval time; + __u16 type; + __u16 code; + __s32 value; + }; + +This module also defines several :class:`InputEvent` sub-classes that +know more about the different types of events (key, abs, rel etc). The +:data:`event_factory` dictionary maps event types to these classes. + +Assuming you use the :func:`evdev.util.categorize()` function to +categorize events according to their type, adding or replacing a class +for a specific event type becomes a matter of modifying +:data:`event_factory`. + +All classes in this module have reasonable ``str()`` and ``repr()`` +methods:: + + >>> print(event) + event at 1337197425.477827, code 04, type 04, val 458792 + >>> print(repr(event)) + InputEvent(1337197425L, 477827L, 4, 4, 458792L) + + >>> print(key_event) + key event at 1337197425.477835, 28 (KEY_ENTER), up + >>> print(repr(key_event)) + KeyEvent(InputEvent(1337197425L, 477835L, 1, 28, 0L)) +""" + +# event type descriptions have been taken mot-a-mot from: +# http://www.kernel.org/doc/Documentation/input/event-codes.txt + +# pylint: disable=no-name-in-module +from typing import Final +from .ecodes import ABS, EV_ABS, EV_KEY, EV_REL, EV_SYN, KEY, REL, SYN, keys + + +class InputEvent: + """A generic input event.""" + + __slots__ = "sec", "usec", "type", "code", "value" + + def __init__(self, sec, usec, type, code, value): + #: Time in seconds since epoch at which event occurred. + self.sec: int = sec + + #: Microsecond portion of the timestamp. + self.usec: int = usec + + #: Event type - one of ``ecodes.EV_*``. + self.type: int = type + + #: Event code related to the event type. + self.code: int = code + + #: Event value related to the event type. + self.value: int = value + + def timestamp(self) -> float: + """Return event timestamp as a float.""" + return self.sec + (self.usec / 1000000.0) + + def __str__(self): + msg = "event at {:f}, code {:02d}, type {:02d}, val {:02d}" + return msg.format(self.timestamp(), self.code, self.type, self.value) + + def __repr__(self): + msg = "{}({!r}, {!r}, {!r}, {!r}, {!r})" + return msg.format(self.__class__.__name__, self.sec, self.usec, self.type, self.code, self.value) + + +class KeyEvent: + """An event generated by a keyboard, button or other key-like devices.""" + + key_up: Final[int] = 0x0 + key_down: Final[int] = 0x1 + key_hold: Final[int] = 0x2 + + __slots__ = "scancode", "keycode", "keystate", "event" + + def __init__(self, event: InputEvent, allow_unknown: bool = False): + """ + The ``allow_unknown`` argument determines what to do in the event of an event code + for which a key code cannot be found. If ``False`` a ``KeyError`` will be raised. + If ``True`` the keycode will be set to the hex value of the event code. + """ + + self.scancode: int = event.code + + if event.value == 0: + self.keystate = KeyEvent.key_up + elif event.value == 2: + self.keystate = KeyEvent.key_hold + elif event.value == 1: + self.keystate = KeyEvent.key_down + + try: + self.keycode = keys[event.code] + except KeyError: + if allow_unknown: + self.keycode = "0x{:02X}".format(event.code) + else: + raise + + #: Reference to an :class:`InputEvent` instance. + self.event: InputEvent = event + + def __str__(self): + try: + ks = ("up", "down", "hold")[self.keystate] + except IndexError: + ks = "unknown" + + msg = "key event at {:f}, {} ({}), {}" + return msg.format(self.event.timestamp(), self.scancode, self.keycode, ks) + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, self.event) + + +class RelEvent: + """A relative axis event (e.g moving the mouse 5 units to the left).""" + + __slots__ = "event" + + def __init__(self, event: InputEvent): + #: Reference to an :class:`InputEvent` instance. + self.event: InputEvent = event + + def __str__(self): + msg = "relative axis event at {:f}, {}" + return msg.format(self.event.timestamp(), REL[self.event.code]) + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, self.event) + + +class AbsEvent: + """An absolute axis event (e.g the coordinates of a tap on a touchscreen).""" + + __slots__ = "event" + + def __init__(self, event: InputEvent): + #: Reference to an :class:`InputEvent` instance. + self.event: InputEvent = event + + def __str__(self): + msg = "absolute axis event at {:f}, {}" + return msg.format(self.event.timestamp(), ABS[self.event.code]) + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, self.event) + + +class SynEvent: + """ + A synchronization event. Used as markers to separate events. Events may be + separated in time or in space, such as with the multitouch protocol. + """ + + __slots__ = "event" + + def __init__(self, event: InputEvent): + #: Reference to an :class:`InputEvent` instance. + self.event: InputEvent = event + + def __str__(self): + msg = "synchronization event at {:f}, {}" + return msg.format(self.event.timestamp(), SYN[self.event.code]) + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, self.event) + + +#: A mapping of event types to :class:`InputEvent` sub-classes. Used +#: by :func:`evdev.util.categorize()` +event_factory = { + EV_KEY: KeyEvent, + EV_REL: RelEvent, + EV_ABS: AbsEvent, + EV_SYN: SynEvent, +} + + +__all__ = ("InputEvent", "KeyEvent", "RelEvent", "SynEvent", "AbsEvent", "event_factory") diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/evtest.py b/CLI/venv/lib/python3.12/site-packages/evdev/evtest.py new file mode 100644 index 0000000..6ea3bb5 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/evtest.py @@ -0,0 +1,181 @@ +""" +Usage: evtest [options] [, ...] + +Input device enumerator and event monitor. + +Running evtest without any arguments will let you select +from a list of all readable input devices. + +Options: + -h, --help Show this help message and exit. + -c, --capabilities List device capabilities and exit. + -g, --grab Other applications will not receive events from + the selected devices while evtest is running. + +Examples: + evtest /dev/input/event0 /dev/input/event1 +""" + +import atexit +import optparse +import re +import select +import sys +import termios + +from . import AbsInfo, InputDevice, ecodes, list_devices + + +def parseopt(): + parser = optparse.OptionParser(add_help_option=False) + parser.add_option("-h", "--help", action="store_true") + parser.add_option("-g", "--grab", action="store_true") + parser.add_option("-c", "--capabilities", action="store_true") + return parser.parse_args() + + +def main(): + opts, devices = parseopt() + if opts.help: + print(__doc__.strip()) + return 0 + + if not devices: + devices = select_devices() + else: + devices = [InputDevice(path) for path in devices] + + if opts.capabilities: + for device in devices: + print_capabilities(device) + return 0 + + if opts.grab: + for device in devices: + device.grab() + + # Disable tty echoing if stdin is a tty. + if sys.stdin.isatty(): + toggle_tty_echo(sys.stdin, enable=False) + atexit.register(toggle_tty_echo, sys.stdin, enable=True) + + print("Listening for events (press ctrl-c to exit) ...") + fd_to_device = {dev.fd: dev for dev in devices} + while True: + r, w, e = select.select(fd_to_device, [], []) + + for fd in r: + for event in fd_to_device[fd].read(): + print_event(event) + + +def select_devices(device_dir="/dev/input"): + """ + Select one or more devices from a list of accessible input devices. + """ + + def devicenum(device_path): + digits = re.findall(r"\d+$", device_path) + return [int(i) for i in digits] + + devices = sorted(list_devices(device_dir), key=devicenum) + devices = [InputDevice(path) for path in devices] + if not devices: + msg = "error: no input devices found (do you have rw permission on %s/*?)" + print(msg % device_dir, file=sys.stderr) + sys.exit(1) + + dev_format = "{0:<3} {1.path:<20} {1.name:<35} {1.phys:<35} {1.uniq:<4}" + dev_lines = [dev_format.format(num, dev) for num, dev in enumerate(devices)] + + print("ID {:<20} {:<35} {:<35} {}".format("Device", "Name", "Phys", "Uniq")) + print("-" * len(max(dev_lines, key=len))) + print("\n".join(dev_lines)) + print() + + choices = input("Select devices [0-%s]: " % (len(dev_lines) - 1)) + + try: + choices = choices.split() + choices = [devices[int(num)] for num in choices] + except ValueError: + choices = None + + if not choices: + msg = "error: invalid input - please enter one or more numbers separated by spaces" + print(msg, file=sys.stderr) + sys.exit(1) + + return choices + + +def print_capabilities(device): + capabilities = device.capabilities(verbose=True) + input_props = device.input_props(verbose=True) + + print("Device name: {.name}".format(device)) + print("Device info: {.info}".format(device)) + print("Repeat settings: {}\n".format(device.repeat)) + + if ("EV_LED", ecodes.EV_LED) in capabilities: + leds = ",".join(i[0] for i in device.leds(True)) + print("Active LEDs: %s" % leds) + + active_keys = ",".join(k[0] for k in device.active_keys(True)) + print("Active keys: %s\n" % active_keys) + + if input_props: + print("Input properties:") + for type, code in input_props: + print(" %s %s" % (type, code)) + print() + + print("Device capabilities:") + for type, codes in capabilities.items(): + print(" Type {} {}:".format(*type)) + for code in codes: + # code <- ('BTN_RIGHT', 273) or (['BTN_LEFT', 'BTN_MOUSE'], 272) + if isinstance(code[1], AbsInfo): + print(" Code {:<4} {}:".format(*code[0])) + print(" {}".format(code[1])) + else: + # Multiple names may resolve to one value. + s = ", ".join(code[0]) if isinstance(code[0], list) else code[0] + print(" Code {:<4} {}".format(s, code[1])) + print("") + + +def print_event(e): + if e.type == ecodes.EV_SYN: + if e.code == ecodes.SYN_MT_REPORT: + msg = "time {:<17} +++++++++++++ {} +++++++++++++" + elif e.code == ecodes.SYN_DROPPED: + msg = "time {:<17} !!!!!!!!!!!!! {} !!!!!!!!!!!!!" + else: + msg = "time {:<17} ------------- {} -------------" + print(msg.format(e.timestamp(), ecodes.SYN[e.code])) + else: + if e.type in ecodes.bytype: + codename = ecodes.bytype[e.type][e.code] + else: + codename = "?" + + evfmt = "time {:<17} type {} ({}), code {:<4} ({}), value {}" + print(evfmt.format(e.timestamp(), e.type, ecodes.EV[e.type], e.code, codename, e.value)) + + +def toggle_tty_echo(fh, enable=True): + flags = termios.tcgetattr(fh.fileno()) + if enable: + flags[3] |= termios.ECHO + else: + flags[3] &= ~termios.ECHO + termios.tcsetattr(fh.fileno(), termios.TCSANOW, flags) + + +if __name__ == "__main__": + try: + ret = main() + except (KeyboardInterrupt, EOFError): + ret = 0 + sys.exit(ret) diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/ff.py b/CLI/venv/lib/python3.12/site-packages/evdev/ff.py new file mode 100644 index 0000000..260c362 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/ff.py @@ -0,0 +1,198 @@ +import ctypes + +from . import ecodes + +_u8 = ctypes.c_uint8 +_u16 = ctypes.c_uint16 +_u32 = ctypes.c_uint32 +_s16 = ctypes.c_int16 +_s32 = ctypes.c_int32 + + +class Replay(ctypes.Structure): + """ + Defines scheduling of the force-feedback effect + @length: duration of the effect + @delay: delay before effect should start playing + """ + + _fields_ = [ + ("length", _u16), + ("delay", _u16), + ] + + +class Trigger(ctypes.Structure): + """ + Defines what triggers the force-feedback effect + @button: number of the button triggering the effect + @interval: controls how soon the effect can be re-triggered + """ + + _fields_ = [ + ("button", _u16), + ("interval", _u16), + ] + + +class Envelope(ctypes.Structure): + """ + Generic force-feedback effect envelope + @attack_length: duration of the attack (ms) + @attack_level: level at the beginning of the attack + @fade_length: duration of fade (ms) + @fade_level: level at the end of fade + + The @attack_level and @fade_level are absolute values; when applying + envelope force-feedback core will convert to positive/negative + value based on polarity of the default level of the effect. + Valid range for the attack and fade levels is 0x0000 - 0x7fff + """ + + _fields_ = [ + ("attack_length", _u16), + ("attack_level", _u16), + ("fade_length", _u16), + ("fade_level", _u16), + ] + + +class Constant(ctypes.Structure): + """ + Defines parameters of a constant force-feedback effect + @level: strength of the effect; may be negative + @envelope: envelope data + """ + + _fields_ = [ + ("level", _s16), + ("ff_envelope", Envelope), + ] + + +class Ramp(ctypes.Structure): + """ + Defines parameters of a ramp force-feedback effect + @start_level: beginning strength of the effect; may be negative + @end_level: final strength of the effect; may be negative + @envelope: envelope data + """ + + _fields_ = [ + ("start_level", _s16), + ("end_level", _s16), + ("ff_envelope", Envelope), + ] + + +class Condition(ctypes.Structure): + """ + Defines a spring or friction force-feedback effect + @right_saturation: maximum level when joystick moved all way to the right + @left_saturation: same for the left side + @right_coeff: controls how fast the force grows when the joystick moves to the right + @left_coeff: same for the left side + @deadband: size of the dead zone, where no force is produced + @center: position of the dead zone + """ + + _fields_ = [ + ("right_saturation", _u16), + ("left_saturation", _u16), + ("right_coeff", _s16), + ("left_coeff", _s16), + ("deadband", _u16), + ("center", _s16), + ] + + +class Periodic(ctypes.Structure): + """ + Defines parameters of a periodic force-feedback effect + @waveform: kind of the effect (wave) + @period: period of the wave (ms) + @magnitude: peak value + @offset: mean value of the wave (roughly) + @phase: 'horizontal' shift + @envelope: envelope data + @custom_len: number of samples (FF_CUSTOM only) + @custom_data: buffer of samples (FF_CUSTOM only) + """ + + _fields_ = [ + ("waveform", _u16), + ("period", _u16), + ("magnitude", _s16), + ("offset", _s16), + ("phase", _u16), + ("envelope", Envelope), + ("custom_len", _u32), + ("custom_data", ctypes.POINTER(_s16)), + ] + + +class Rumble(ctypes.Structure): + """ + Defines parameters of a periodic force-feedback effect + @strong_magnitude: magnitude of the heavy motor + @weak_magnitude: magnitude of the light one + + Some rumble pads have two motors of different weight. Strong_magnitude + represents the magnitude of the vibration generated by the heavy one. + """ + + _fields_ = [ + ("strong_magnitude", _u16), + ("weak_magnitude", _u16), + ] + + +class EffectType(ctypes.Union): + _fields_ = [ + ("ff_constant_effect", Constant), + ("ff_ramp_effect", Ramp), + ("ff_periodic_effect", Periodic), + ("ff_condition_effect", Condition * 2), # one for each axis + ("ff_rumble_effect", Rumble), + ] + + +class Effect(ctypes.Structure): + _fields_ = [ + ("type", _u16), + ("id", _s16), + ("direction", _u16), + ("ff_trigger", Trigger), + ("ff_replay", Replay), + ("u", EffectType), + ] + + +class UInputUpload(ctypes.Structure): + _fields_ = [ + ("request_id", _u32), + ("retval", _s32), + ("effect", Effect), + ("old", Effect), + ] + + +class UInputErase(ctypes.Structure): + _fields_ = [ + ("request_id", _u32), + ("retval", _s32), + ("effect_id", _u32), + ] + + +# ff_types = { +# ecodes.FF_CONSTANT, +# ecodes.FF_PERIODIC, +# ecodes.FF_RAMP, +# ecodes.FF_SPRING, +# ecodes.FF_FRICTION, +# ecodes.FF_DAMPER, +# ecodes.FF_RUMBLE, +# ecodes.FF_INERTIA, +# ecodes.FF_CUSTOM, +# } diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_c.py b/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_c.py new file mode 100644 index 0000000..15a6693 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_c.py @@ -0,0 +1,147 @@ +""" +Generate a Python extension module with the constants defined in linux/input.h. +""" + +import getopt +import os +import re +import sys + +# ----------------------------------------------------------------------------- +# The default header file locations to try. +headers = [ + "/usr/include/linux/input.h", + "/usr/include/linux/input-event-codes.h", + "/usr/include/linux/uinput.h", +] + +opts, args = getopt.getopt(sys.argv[1:], "", ["ecodes", "stubs", "reproducible"]) +if not opts: + print("usage: genecodes.py [--ecodes|--stubs] [--reproducible] ") + exit(2) + +if args: + headers = args + +reproducible = ("--reproducible", "") in opts + + +# ----------------------------------------------------------------------------- +macro_regex = r"#define\s+((?:KEY|ABS|REL|SW|MSC|LED|BTN|REP|SND|ID|EV|BUS|SYN|FF|UI_FF|INPUT_PROP)_\w+)" +macro_regex = re.compile(macro_regex) + +if reproducible: + uname = "hidden for reproducibility" +else: + # Uname without hostname. + uname = list(os.uname()) + uname = " ".join((uname[0], *uname[2:])) + + +# ----------------------------------------------------------------------------- +template_ecodes = r""" +#include +#ifdef __FreeBSD__ +#include +#include +#else +#include +#include +#endif + +/* Automatically generated by evdev.genecodes */ +/* Generated on %s */ +/* Generated from %s */ + +#define MODULE_NAME "_ecodes" +#define MODULE_HELP "linux/input.h macros" + +static PyMethodDef MethodTable[] = { + { NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + MODULE_NAME, + MODULE_HELP, + -1, /* m_size */ + MethodTable, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyMODINIT_FUNC +PyInit__ecodes(void) +{ + PyObject* m = PyModule_Create(&moduledef); + if (m == NULL) return NULL; + +%s + + return m; +} +""" + + +template_stubs = r""" +# Automatically generated by evdev.genecodes +# Generated on %s +# Generated from %s + +# pylint: skip-file + +ecodes: dict[str, int] +keys: dict[int, str|list[str]] +bytype: dict[int, dict[int, str|list[str]]] + +KEY: dict[int, str|list[str]] +ABS: dict[int, str|list[str]] +REL: dict[int, str|list[str]] +SW: dict[int, str|list[str]] +MSC: dict[int, str|list[str]] +LED: dict[int, str|list[str]] +BTN: dict[int, str|list[str]] +REP: dict[int, str|list[str]] +SND: dict[int, str|list[str]] +ID: dict[int, str|list[str]] +EV: dict[int, str|list[str]] +BUS: dict[int, str|list[str]] +SYN: dict[int, str|list[str]] +FF_STATUS: dict[int, str|list[str]] +FF_INPUT_PROP: dict[int, str|list[str]] + +%s +""" + + +def parse_headers(headers=headers): + for header in headers: + try: + fh = open(header) + except (IOError, OSError): + continue + + for line in fh: + macro = macro_regex.search(line) + if macro: + yield macro.group(1) + + +all_macros = list(parse_headers()) +if not all_macros: + print("no input macros found in: %s" % " ".join(headers), file=sys.stderr) + sys.exit(1) + +# pylint: disable=possibly-used-before-assignment, used-before-assignment +if ("--ecodes", "") in opts: + body = (" PyModule_AddIntMacro(m, %s);" % macro for macro in all_macros) + template = template_ecodes +elif ("--stubs", "") in opts: + body = ("%s: int" % macro for macro in all_macros) + template = template_stubs + +body = os.linesep.join(body) +text = template % (uname, headers if not reproducible else ["hidden for reproducibility"], body) +print(text.strip()) diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_py.py b/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_py.py new file mode 100644 index 0000000..f00020c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/genecodes_py.py @@ -0,0 +1,54 @@ +import sys +from unittest import mock +from pprint import PrettyPrinter + +sys.modules["evdev.ecodes"] = mock.Mock() +from evdev import ecodes_runtime as ecodes + +pprint = PrettyPrinter(indent=2, sort_dicts=True, width=120).pprint + + +print("# Automatically generated by evdev.genecodes_py") +print() +print('"""') +print(ecodes.__doc__.strip()) +print('"""') + +print() +print("from typing import Final, Dict, Tuple, Union") +print() + +for name, value in ecodes.ecodes.items(): + print(f"{name}: Final[int] = {value}") +print() + +entries = [ + ("ecodes", "Dict[str, int]", "#: Mapping of names to values."), + ("bytype", "Dict[int, Dict[int, Union[str, Tuple[str]]]]", "#: Mapping of event types to other value/name mappings."), + ("keys", "Dict[int, Union[str, Tuple[str]]]", "#: Keys are a combination of all BTN and KEY codes."), + ("KEY", "Dict[int, Union[str, Tuple[str]]]", None), + ("ABS", "Dict[int, Union[str, Tuple[str]]]", None), + ("REL", "Dict[int, Union[str, Tuple[str]]]", None), + ("SW", "Dict[int, Union[str, Tuple[str]]]", None), + ("MSC", "Dict[int, Union[str, Tuple[str]]]", None), + ("LED", "Dict[int, Union[str, Tuple[str]]]", None), + ("BTN", "Dict[int, Union[str, Tuple[str]]]", None), + ("REP", "Dict[int, Union[str, Tuple[str]]]", None), + ("SND", "Dict[int, Union[str, Tuple[str]]]", None), + ("ID", "Dict[int, Union[str, Tuple[str]]]", None), + ("EV", "Dict[int, Union[str, Tuple[str]]]", None), + ("BUS", "Dict[int, Union[str, Tuple[str]]]", None), + ("SYN", "Dict[int, Union[str, Tuple[str]]]", None), + ("FF", "Dict[int, Union[str, Tuple[str]]]", None), + ("UI_FF", "Dict[int, Union[str, Tuple[str]]]", None), + ("FF_STATUS", "Dict[int, Union[str, Tuple[str]]]", None), + ("INPUT_PROP", "Dict[int, Union[str, Tuple[str]]]", None) +] + +for key, annotation, doc in entries: + if doc: + print(doc) + + print(f"{key}: {annotation} = ", end="") + pprint(getattr(ecodes, key)) + print() \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/input.c b/CLI/venv/lib/python3.12/site-packages/evdev/input.c new file mode 100644 index 0000000..4ad0408 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/input.c @@ -0,0 +1,579 @@ + +/* + * Python bindings to certain linux input subsystem functions. + * + * While everything here can be implemented in pure Python with struct and + * fcntl.ioctl, imho, it is much more straightforward to do so in C. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#else +#include +#endif + +#ifndef input_event_sec +#define input_event_sec time.tv_sec +#define input_event_usec time.tv_usec +#endif + +#define MAX_NAME_SIZE 256 + +extern char* EV_NAME[EV_CNT]; +extern int EV_TYPE_MAX[EV_CNT]; +extern char** EV_TYPE_NAME[EV_CNT]; +extern char* BUS_NAME[]; + + +int test_bit(const char* bitmask, int bit) { + return bitmask[bit/8] & (1 << (bit % 8)); +} + + +// Read input event from a device and return a tuple that mimics input_event +static PyObject * +device_read(PyObject *self, PyObject *args) +{ + struct input_event event; + + // get device file descriptor (O_RDONLY|O_NONBLOCK) + int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0)); + + int n = read(fd, &event, sizeof(event)); + + if (n < 0) { + if (errno == EAGAIN) { + Py_INCREF(Py_None); + return Py_None; + } + + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + PyObject* sec = PyLong_FromLong(event.input_event_sec); + PyObject* usec = PyLong_FromLong(event.input_event_usec); + PyObject* val = PyLong_FromLong(event.value); + PyObject* type = PyLong_FromLong(event.type); + PyObject* code = PyLong_FromLong(event.code); + PyObject* py_input_event = PyTuple_Pack(5, sec, usec, type, code, val); + + return py_input_event; +} + + +// Read multiple input events from a device and return a list of tuples +static PyObject * +device_read_many(PyObject *self, PyObject *args) +{ + // get device file descriptor (O_RDONLY|O_NONBLOCK) + int fd = (int)PyLong_AsLong(PyTuple_GET_ITEM(args, 0)); + + PyObject* py_input_event = NULL; + PyObject* events = NULL; + PyObject* sec = NULL; + PyObject* usec = NULL; + PyObject* val = NULL; + PyObject* type = NULL; + PyObject* code = NULL; + + struct input_event event[64]; + + size_t event_size = sizeof(struct input_event); + ssize_t nread = read(fd, event, event_size*64); + + if (nread < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + // Construct a tuple of event tuples. Each tuple is the arguments to InputEvent. + size_t num_events = nread / event_size; + events = PyTuple_New(num_events); + for (size_t i = 0 ; i < num_events; i++) { + sec = PyLong_FromLong(event[i].input_event_sec); + usec = PyLong_FromLong(event[i].input_event_usec); + val = PyLong_FromLong(event[i].value); + type = PyLong_FromLong(event[i].type); + code = PyLong_FromLong(event[i].code); + + py_input_event = PyTuple_Pack(5, sec, usec, type, code, val); + PyTuple_SET_ITEM(events, i, py_input_event); + } + + return events; +} + + +// Get the event types and event codes that the input device supports +static PyObject * +ioctl_capabilities(PyObject *self, PyObject *args) +{ + int fd, ev_type, ev_code; + char ev_bits[EV_MAX/8 + 1], code_bits[KEY_MAX/8 + 1]; + struct input_absinfo absinfo; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + // @todo: figure out why fd gets zeroed on an ioctl after the + // refactoring and get rid of this workaround + const int _fd = fd; + + // Capabilities is a mapping of supported event types to lists of handled + // events e.g: {1: [272, 273, 274, 275], 2: [0, 1, 6, 8]} + PyObject* capabilities = PyDict_New(); + PyObject* eventcodes = NULL; + PyObject* evlong = NULL; + PyObject* capability = NULL; + PyObject* py_absinfo = NULL; + PyObject* absitem = NULL; + + memset(&ev_bits, 0, sizeof(ev_bits)); + + if (ioctl(_fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) + goto on_err; + + // Build a dictionary of the device's capabilities + for (ev_type=0 ; ev_type tuple(ABS_X, (0, 255, 0, 0)) + PyList_Append(eventcodes, absitem); + + Py_DECREF(absitem); + Py_DECREF(py_absinfo); + } + else { + evlong = PyLong_FromLong(ev_code); + PyList_Append(eventcodes, evlong); + } + + Py_DECREF(evlong); + } + } + // capabilities[EV_KEY] = [KEY_A, KEY_B, KEY_C, ...] + // capabilities[EV_ABS] = [(ABS_X, (0, 255, 0, 0)), ...] + PyDict_SetItem(capabilities, capability, eventcodes); + + Py_DECREF(capability); + Py_DECREF(eventcodes); + } + } + + return capabilities; + + on_err: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +// An all-in-one function for describing an input device +static PyObject * +ioctl_devinfo(PyObject *self, PyObject *args) +{ + int fd; + + struct input_id iid; + char name[MAX_NAME_SIZE]; + char phys[MAX_NAME_SIZE] = {0}; + char uniq[MAX_NAME_SIZE] = {0}; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + memset(&iid, 0, sizeof(iid)); + + if (ioctl(fd, EVIOCGID, &iid) < 0) goto on_err; + if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) goto on_err; + + // Some devices do not have a physical topology associated with them + ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys); + + // Some kernels have started reporting bluetooth controller MACs as phys. + // This lets us get the real physical address. As with phys, it may be blank. + ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq); + + return Py_BuildValue("hhhhsss", iid.bustype, iid.vendor, iid.product, iid.version, + name, phys, uniq); + + on_err: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +static PyObject * +ioctl_EVIOCGABS(PyObject *self, PyObject *args) +{ + int fd, ev_code; + struct input_absinfo absinfo; + PyObject* py_absinfo = NULL; + + int ret = PyArg_ParseTuple(args, "ii", &fd, &ev_code); + if (!ret) return NULL; + + memset(&absinfo, 0, sizeof(absinfo)); + ret = ioctl(fd, EVIOCGABS(ev_code), &absinfo); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + py_absinfo = Py_BuildValue("(iiiiii)", + absinfo.value, + absinfo.minimum, + absinfo.maximum, + absinfo.fuzz, + absinfo.flat, + absinfo.resolution); + return py_absinfo; +} + + +static PyObject * +ioctl_EVIOCSABS(PyObject *self, PyObject *args) +{ + int fd, ev_code; + struct input_absinfo absinfo; + + int ret = PyArg_ParseTuple(args, + "ii(iiiiii)", + &fd, + &ev_code, + &absinfo.value, + &absinfo.minimum, + &absinfo.maximum, + &absinfo.fuzz, + &absinfo.flat, + &absinfo.resolution); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCSABS(ev_code), &absinfo); + if (ret == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +ioctl_EVIOCGREP(PyObject *self, PyObject *args) +{ + int fd, ret; + unsigned int rep[REP_CNT] = {0}; + ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCGREP, &rep); + if (ret == -1) + return NULL; + + return Py_BuildValue("(ii)", rep[REP_DELAY], rep[REP_PERIOD]); +} + + +static PyObject * +ioctl_EVIOCSREP(PyObject *self, PyObject *args) +{ + int fd, ret; + unsigned int rep[REP_CNT] = {0}; + + ret = PyArg_ParseTuple(args, "iii", &fd, &rep[0], &rep[1]); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCSREP, &rep); + if (ret == -1) + return NULL; + + return Py_BuildValue("i", ret); +} + + +static PyObject * +ioctl_EVIOCGVERSION(PyObject *self, PyObject *args) +{ + int fd, ret, res; + ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCGVERSION, &res); + if (ret == -1) + return NULL; + + return Py_BuildValue("i", res); +} + + +static PyObject * +ioctl_EVIOCGRAB(PyObject *self, PyObject *args) +{ + int fd, ret, flag; + ret = PyArg_ParseTuple(args, "ii", &fd, &flag); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCGRAB, (intptr_t)flag); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +ioctl_EVIOCG_bits(PyObject *self, PyObject *args) +{ + int max, fd, evtype, ret; + + ret = PyArg_ParseTuple(args, "ii", &fd, &evtype); + if (!ret) return NULL; + + switch (evtype) { + case EV_LED: + max = LED_MAX; break; + case EV_SND: + max = SND_MAX; break; + case EV_KEY: + max = KEY_MAX; break; + case EV_SW: + max = SW_MAX; break; + default: + return NULL; + } + + char bytes[(max+7)/8]; + memset(bytes, 0, sizeof bytes); + + switch (evtype) { + case EV_LED: + ret = ioctl(fd, EVIOCGLED(sizeof(bytes)), &bytes); + break; + case EV_SND: + ret = ioctl(fd, EVIOCGSND(sizeof(bytes)), &bytes); + break; + case EV_KEY: + ret = ioctl(fd, EVIOCGKEY(sizeof(bytes)), &bytes); + break; + case EV_SW: + ret = ioctl(fd, EVIOCGSW(sizeof(bytes)), &bytes); + break; + } + + if (ret == -1) + return NULL; + + PyObject* res = PyList_New(0); + for (int i=0; i<=max; i++) { + if (test_bit(bytes, i)) { + PyList_Append(res, Py_BuildValue("i", i)); + } + } + + return res; +} + + +static PyObject * +ioctl_EVIOCGEFFECTS(PyObject *self, PyObject *args) +{ + int fd, ret, res; + ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + ret = ioctl(fd, EVIOCGEFFECTS, &res); + if (ret == -1) + return NULL; + + return Py_BuildValue("i", res); +} + +void print_ff_effect(struct ff_effect* effect) { + fprintf(stderr, + "ff_effect:\n" + " type: %d \n" + " id: %d \n" + " direction: %d\n" + " trigger: (%d, %d)\n" + " replay: (%d, %d)\n", + effect->type, effect->id, effect->direction, + effect->trigger.button, effect->trigger.interval, + effect->replay.length, effect->replay.delay + ); + + + switch (effect->type) { + case FF_CONSTANT: + fprintf(stderr, " constant: (%d, (%d, %d, %d, %d))\n", effect->u.constant.level, + effect->u.constant.envelope.attack_length, + effect->u.constant.envelope.attack_level, + effect->u.constant.envelope.fade_length, + effect->u.constant.envelope.fade_level); + break; + case FF_RUMBLE: + fprintf(stderr, " rumble: (%d, %d)\n", + effect->u.rumble.strong_magnitude, + effect->u.rumble.weak_magnitude); + break; + } +} + + +static PyObject * +upload_effect(PyObject *self, PyObject *args) +{ + int fd, ret; + PyObject* effect_data; + ret = PyArg_ParseTuple(args, "iO", &fd, &effect_data); + if (!ret) return NULL; + + void* data = PyBytes_AsString(effect_data); + struct ff_effect effect = {}; + memmove(&effect, data, sizeof(struct ff_effect)); + + // print_ff_effect(&effect); + + ret = ioctl(fd, EVIOCSFF, &effect); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("i", effect.id); +} + + +static PyObject * +erase_effect(PyObject *self, PyObject *args) +{ + int fd, ret; + PyObject* ff_id_obj; + ret = PyArg_ParseTuple(args, "iO", &fd, &ff_id_obj); + if (!ret) return NULL; + + long ff_id = PyLong_AsLong(ff_id_obj); + ret = ioctl(fd, EVIOCRMFF, ff_id); + if (ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +ioctl_EVIOCGPROP(PyObject *self, PyObject *args) +{ + int fd, ret; + + ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + char bytes[(INPUT_PROP_MAX+7)/8]; + memset(bytes, 0, sizeof bytes); + + ret = ioctl(fd, EVIOCGPROP(sizeof(bytes)), &bytes); + + if (ret == -1) + return NULL; + + PyObject* res = PyList_New(0); + for (int i=0; i + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#include +#else +#include +#include +#endif + +#ifndef input_event_sec +#define input_event_sec time.tv_sec +#define input_event_usec time.tv_usec +#endif + +// Workaround for installing on kernels newer than 4.4. +#ifndef FF_MAX_EFFECTS +#define FF_MAX_EFFECTS FF_GAIN; +#endif + +int _uinput_close(int fd) +{ + if (ioctl(fd, UI_DEV_DESTROY) < 0) { + int oerrno = errno; + close(fd); + errno = oerrno; + return -1; + } + + return close(fd); +} + + +static PyObject * +uinput_open(PyObject *self, PyObject *args) +{ + const char* devnode; + + int ret = PyArg_ParseTuple(args, "s", &devnode); + if (!ret) return NULL; + + int fd = open(devnode, O_RDWR | O_NONBLOCK); + if (fd < 0) { + PyErr_SetString(PyExc_OSError, "could not open uinput device in write mode"); + return NULL; + } + + return Py_BuildValue("i", fd); +} + + +static PyObject * +uinput_set_phys(PyObject *self, PyObject *args) +{ + int fd; + const char* phys; + + int ret = PyArg_ParseTuple(args, "is", &fd, &phys); + if (!ret) return NULL; + + if (ioctl(fd, UI_SET_PHYS, phys) < 0) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + +static PyObject * +uinput_set_prop(PyObject *self, PyObject *args) +{ + int fd; + uint16_t prop; + + int ret = PyArg_ParseTuple(args, "ih", &fd, &prop); + if (!ret) return NULL; + + if (ioctl(fd, UI_SET_PROPBIT, prop) < 0) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + +static PyObject * +uinput_get_sysname(PyObject *self, PyObject *args) +{ + int fd; + char sysname[64]; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + #ifdef UI_GET_SYSNAME + if (ioctl(fd, UI_GET_SYSNAME(sizeof(sysname)), &sysname) < 0) + goto on_err; + + return Py_BuildValue("s", &sysname); + #endif + + on_err: + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + +// Different kernel versions have different device setup methods. You can read +// more about it here: +// https://github.com/torvalds/linux/commit/052876f8e5aec887d22c4d06e54aa5531ffcec75 + +// Setup function for kernel >= v4.5 +#if defined(UI_DEV_SETUP) && defined(UI_ABS_SETUP) +static PyObject * +uinput_setup(PyObject *self, PyObject *args) { + int fd, len, i; + uint16_t vendor, product, version, bustype; + uint32_t max_effects; + + PyObject *absinfo = NULL, *item = NULL; + + struct uinput_abs_setup abs_setup; + + const char* name; + int ret = PyArg_ParseTuple(args, "isHHHHOI", &fd, &name, &vendor, + &product, &version, &bustype, &absinfo, &max_effects); + if (!ret) return NULL; + + // Setup absinfo: + len = PyList_Size(absinfo); + for (i=0; i (ABS_X, 0, 255, 0, 0, 0, 0) + item = PyList_GetItem(absinfo, i); + + memset(&abs_setup, 0, sizeof(abs_setup)); // Clear struct + abs_setup.code = PyLong_AsLong(PyList_GetItem(item, 0)); + abs_setup.absinfo.value = PyLong_AsLong(PyList_GetItem(item, 1)); + abs_setup.absinfo.minimum = PyLong_AsLong(PyList_GetItem(item, 2)); + abs_setup.absinfo.maximum = PyLong_AsLong(PyList_GetItem(item, 3)); + abs_setup.absinfo.fuzz = PyLong_AsLong(PyList_GetItem(item, 4)); + abs_setup.absinfo.flat = PyLong_AsLong(PyList_GetItem(item, 5)); + abs_setup.absinfo.resolution = PyLong_AsLong(PyList_GetItem(item, 6)); + + if(ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0) + goto on_err; + } + + // Setup evdev: + struct uinput_setup usetup; + + memset(&usetup, 0, sizeof(usetup)); + strncpy(usetup.name, name, sizeof(usetup.name) - 1); + usetup.id.vendor = vendor; + usetup.id.product = product; + usetup.id.version = version; + usetup.id.bustype = bustype; + usetup.ff_effects_max = max_effects; + + if(ioctl(fd, UI_DEV_SETUP, &usetup) < 0) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + +// Fallback setup function (Linux <= 4.5 and FreeBSD). +#else +static PyObject * +uinput_setup(PyObject *self, PyObject *args) { + int fd, len, i, abscode; + uint16_t vendor, product, version, bustype; + uint32_t max_effects; + + PyObject *absinfo = NULL, *item = NULL; + + struct uinput_user_dev uidev; + const char* name; + + int ret = PyArg_ParseTuple(args, "isHHHHOI", &fd, &name, &vendor, + &product, &version, &bustype, &absinfo, &max_effects); + if (!ret) return NULL; + + memset(&uidev, 0, sizeof(uidev)); + strncpy(uidev.name, name, sizeof(uidev.name) - 1); + uidev.id.vendor = vendor; + uidev.id.product = product; + uidev.id.version = version; + uidev.id.bustype = bustype; + uidev.ff_effects_max = max_effects; + + len = PyList_Size(absinfo); + for (i=0; i (ABS_X, 0, 255, 0, 0, 0, 0) + item = PyList_GetItem(absinfo, i); + abscode = (int)PyLong_AsLong(PyList_GetItem(item, 0)); + + /* min/max/fuzz/flat start from index 2 because index 1 is value */ + uidev.absmin[abscode] = PyLong_AsLong(PyList_GetItem(item, 2)); + uidev.absmax[abscode] = PyLong_AsLong(PyList_GetItem(item, 3)); + uidev.absfuzz[abscode] = PyLong_AsLong(PyList_GetItem(item, 4)); + uidev.absflat[abscode] = PyLong_AsLong(PyList_GetItem(item, 5)); + } + + if (write(fd, &uidev, sizeof(uidev)) != sizeof(uidev)) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} +#endif + + +static PyObject * +uinput_create(PyObject *self, PyObject *args) +{ + int fd; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + if (ioctl(fd, UI_DEV_CREATE) < 0) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + + +static PyObject * +uinput_close(PyObject *self, PyObject *args) +{ + int fd; + + int ret = PyArg_ParseTuple(args, "i", &fd); + if (!ret) return NULL; + + if (_uinput_close(fd) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + + +static PyObject * +uinput_write(PyObject *self, PyObject *args) +{ + int fd, type, code, value; + + int ret = PyArg_ParseTuple(args, "iiii", &fd, &type, &code, &value); + if (!ret) return NULL; + + struct input_event event; + struct timeval tval; + memset(&event, 0, sizeof(event)); + gettimeofday(&tval, 0); + event.input_event_usec = tval.tv_usec; + event.input_event_sec = tval.tv_sec; + event.type = type; + event.code = code; + event.value = value; + + if (write(fd, &event, sizeof(event)) != sizeof(event)) { + // @todo: elaborate + // PyErr_SetString(PyExc_OSError, "error writing event to uinput device"); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + + +static PyObject * +uinput_enable_event(PyObject *self, PyObject *args) +{ + int fd; + uint16_t type, code; + unsigned long req; + + int ret = PyArg_ParseTuple(args, "ihh", &fd, &type, &code); + if (!ret) return NULL; + + switch (type) { + case EV_KEY: req = UI_SET_KEYBIT; break; + case EV_ABS: req = UI_SET_ABSBIT; break; + case EV_REL: req = UI_SET_RELBIT; break; + case EV_MSC: req = UI_SET_MSCBIT; break; + case EV_SW: req = UI_SET_SWBIT; break; + case EV_LED: req = UI_SET_LEDBIT; break; + case EV_FF: req = UI_SET_FFBIT; break; + case EV_SND: req = UI_SET_SNDBIT; break; + default: + errno = EINVAL; + goto on_err; + } + + if (ioctl(fd, UI_SET_EVBIT, type) < 0) + goto on_err; + + if (ioctl(fd, req, code) < 0) + goto on_err; + + Py_RETURN_NONE; + + on_err: + _uinput_close(fd); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +} + +int _uinput_begin_upload(int fd, struct uinput_ff_upload *upload) +{ + return ioctl(fd, UI_BEGIN_FF_UPLOAD, upload); +} + +int _uinput_end_upload(int fd, struct uinput_ff_upload *upload) +{ + return ioctl(fd, UI_END_FF_UPLOAD, upload); +} + +int _uinput_begin_erase(int fd, struct uinput_ff_erase *upload) +{ + return ioctl(fd, UI_BEGIN_FF_ERASE, upload); +} + +int _uinput_end_erase(int fd, struct uinput_ff_erase *upload) +{ + return ioctl(fd, UI_END_FF_ERASE, upload); +} + + +static PyMethodDef MethodTable[] = { + { "open", uinput_open, METH_VARARGS, + "Open uinput device node."}, + + { "setup", uinput_setup, METH_VARARGS, + "Set an uinput device up."}, + + { "create", uinput_create, METH_VARARGS, + "Create an uinput device."}, + + { "close", uinput_close, METH_VARARGS, + "Destroy uinput device."}, + + { "write", uinput_write, METH_VARARGS, + "Write event to uinput device."}, + + { "enable", uinput_enable_event, METH_VARARGS, + "Enable a type of event."}, + + { "set_phys", uinput_set_phys, METH_VARARGS, + "Set physical path"}, + + { "get_sysname", uinput_get_sysname, METH_VARARGS, + "Obtain the sysname of the uinput device."}, + + { "set_prop", uinput_set_prop, METH_VARARGS, + "Set device input property"}, + + { NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_uinput", + "Python bindings for parts of linux/uinput.c", + -1, /* m_size */ + MethodTable, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +static PyObject * +moduleinit(void) +{ + PyObject* m = PyModule_Create(&moduledef); + if (m == NULL) return NULL; + + PyModule_AddIntConstant(m, "maxnamelen", UINPUT_MAX_NAME_SIZE); + return m; +} + +PyMODINIT_FUNC +PyInit__uinput(void) +{ + return moduleinit(); +} diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/uinput.py b/CLI/venv/lib/python3.12/site-packages/evdev/uinput.py new file mode 100644 index 0000000..2c69c2b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/uinput.py @@ -0,0 +1,375 @@ +import ctypes +import os +import platform +import re +import stat +import time +from collections import defaultdict +from typing import Union, Tuple, Dict, Sequence, Optional + +from . import _uinput, ecodes, ff, util +from .device import InputDevice, AbsInfo +from .events import InputEvent + +try: + from evdev.eventio_async import EventIO +except ImportError: + from evdev.eventio import EventIO + + +class UInputError(Exception): + pass + + +class UInput(EventIO): + """ + A userland input device and that can inject input events into the + linux input subsystem. + """ + + __slots__ = ( + "name", + "vendor", + "product", + "version", + "bustype", + "events", + "devnode", + "fd", + "device", + ) + + @classmethod + def from_device( + cls, + *devices: Union[InputDevice, Union[str, bytes, os.PathLike]], + filtered_types: Tuple[int] = (ecodes.EV_SYN, ecodes.EV_FF), + **kwargs, + ): + """ + Create an UInput device with the capabilities of one or more input + devices. + + Arguments + --------- + devices : InputDevice|str + Varargs of InputDevice instances or paths to input devices. + + filtered_types : Tuple[event type codes] + Event types to exclude from the capabilities of the uinput device. + + **kwargs + Keyword arguments to UInput constructor (i.e. name, vendor etc.). + """ + + device_instances = [] + for dev in devices: + if not isinstance(dev, InputDevice): + dev = InputDevice(str(dev)) + device_instances.append(dev) + + all_capabilities = defaultdict(set) + + if "max_effects" not in kwargs: + kwargs["max_effects"] = min([dev.ff_effects_count for dev in device_instances]) + + # Merge the capabilities of all devices into one dictionary. + for dev in device_instances: + for ev_type, ev_codes in dev.capabilities().items(): + all_capabilities[ev_type].update(ev_codes) + + for evtype in filtered_types: + if evtype in all_capabilities: + del all_capabilities[evtype] + + return cls(events=all_capabilities, **kwargs) + + def __init__( + self, + events: Optional[Dict[int, Sequence[int]]] = None, + name: str = "py-evdev-uinput", + vendor: int = 0x1, + product: int = 0x1, + version: int = 0x1, + bustype: int = 0x3, + devnode: str = "/dev/uinput", + phys: str = "py-evdev-uinput", + input_props=None, + # CentOS 7 has sufficiently old headers that FF_MAX_EFFECTS is not defined there, + # which causes the whole module to fail loading. Fallback on a hardcoded value of + # FF_MAX_EFFECTS if it is not defined in the ecodes. + max_effects=ecodes.ecodes.get("FF_MAX_EFFECTS", 96), + ): + """ + Arguments + --------- + events : dict + Dictionary of event types mapping to lists of event codes. The + event types and codes that the uinput device will be able to + inject - defaults to all key codes. + + name + The name of the input device. + + vendor + Vendor identifier. + + product + Product identifier. + + version + Version identifier. + + bustype + Bustype identifier. + + phys + Physical path. + + input_props + Input properties and quirks. + + max_effects + Maximum simultaneous force-feedback effects. + + Note + ---- + If you do not specify any events, the uinput device will be able + to inject only ``KEY_*`` and ``BTN_*`` event codes. + """ + + self.name: str = name #: Uinput device name. + self.vendor: int = vendor #: Device vendor identifier. + self.product: int = product #: Device product identifier. + self.version: int = version #: Device version identifier. + self.bustype: int = bustype #: Device bustype - e.g. ``BUS_USB``. + self.phys: str = phys #: Uinput device physical path. + self.devnode: str = devnode #: Uinput device node - e.g. ``/dev/uinput/``. + + if not events: + events = {ecodes.EV_KEY: ecodes.keys.keys()} + + self._verify() + + #: Write-only, non-blocking file descriptor to the uinput device node. + self.fd = _uinput.open(devnode) + + # Prepare the list of events for passing to _uinput.enable and _uinput.setup. + absinfo, prepared_events = self._prepare_events(events) + + # Set phys name + _uinput.set_phys(self.fd, phys) + + # Set properties + input_props = input_props or [] + for prop in input_props: + _uinput.set_prop(self.fd, prop) + + for etype, code in prepared_events: + _uinput.enable(self.fd, etype, code) + + _uinput.setup(self.fd, name, vendor, product, version, bustype, absinfo, max_effects) + + # Create the uinput device. + _uinput.create(self.fd) + + self.dll = ctypes.CDLL(_uinput.__file__) + self.dll._uinput_begin_upload.restype = ctypes.c_int + self.dll._uinput_end_upload.restype = ctypes.c_int + + #: An :class:`InputDevice ` instance + #: for the fake input device. ``None`` if the device cannot be + #: opened for reading and writing. + self.device: InputDevice = self._find_device(self.fd) + + def _prepare_events(self, events): + """Prepare events for passing to _uinput.enable and _uinput.setup""" + absinfo, prepared_events = [], [] + for etype, codes in events.items(): + for code in codes: + # Handle max, min, fuzz, flat. + if isinstance(code, (tuple, list, AbsInfo)): + # Flatten (ABS_Y, (0, 255, 0, 0, 0, 0)) to (ABS_Y, 0, 255, 0, 0, 0, 0). + f = [code[0]] + f.extend(code[1]) + # Ensure the tuple is always 6 ints long, since uinput.c:uinput_create + # does little in the way of checking the length. + f.extend([0] * (6 - len(code[1]))) + absinfo.append(f) + code = code[0] + prepared_events.append((etype, code)) + return absinfo, prepared_events + + def __enter__(self): + return self + + def __exit__(self, type, value, tb): + if hasattr(self, "fd"): + self.close() + + def __repr__(self): + # TODO: + v = (repr(getattr(self, i)) for i in ("name", "bustype", "vendor", "product", "version", "phys")) + return "{}({})".format(self.__class__.__name__, ", ".join(v)) + + def __str__(self): + msg = 'name "{}", bus "{}", vendor "{:04x}", product "{:04x}", version "{:04x}", phys "{}"\nevent types: {}' + + evtypes = [i[0] for i in self.capabilities(True).keys()] + msg = msg.format( + self.name, ecodes.BUS[self.bustype], self.vendor, self.product, self.version, self.phys, " ".join(evtypes) + ) + + return msg + + def close(self): + # Close the associated InputDevice, if it was previously opened. + if self.device is not None: + self.device.close() + + # Destroy the uinput device. + if self.fd > -1: + _uinput.close(self.fd) + self.fd = -1 + + def capabilities(self, verbose: bool = False, absinfo: bool = True): + """See :func:`capabilities `.""" + if self.device is None: + raise UInputError("input device not opened - cannot read capabilities") + + return self.device.capabilities(verbose, absinfo) + + def begin_upload(self, effect_id): + upload = ff.UInputUpload() + upload.effect_id = effect_id + + ret = self.dll._uinput_begin_upload(self.fd, ctypes.byref(upload)) + if ret: + raise UInputError("Failed to begin uinput upload: " + os.strerror(ret)) + + return upload + + def end_upload(self, upload): + ret = self.dll._uinput_end_upload(self.fd, ctypes.byref(upload)) + if ret: + raise UInputError("Failed to end uinput upload: " + os.strerror(ret)) + + def begin_erase(self, effect_id): + erase = ff.UInputErase() + erase.effect_id = effect_id + + ret = self.dll._uinput_begin_erase(self.fd, ctypes.byref(erase)) + if ret: + raise UInputError("Failed to begin uinput erase: " + os.strerror(ret)) + return erase + + def end_erase(self, erase): + ret = self.dll._uinput_end_erase(self.fd, ctypes.byref(erase)) + if ret: + raise UInputError("Failed to end uinput erase: " + os.strerror(ret)) + + def _verify(self): + """ + Verify that an uinput device exists and is readable and writable + by the current process. + """ + try: + m = os.stat(self.devnode)[stat.ST_MODE] + assert stat.S_ISCHR(m) + except (IndexError, OSError, AssertionError): + msg = '"{}" does not exist or is not a character device file - verify that the uinput module is loaded' + raise UInputError(msg.format(self.devnode)) + + if not os.access(self.devnode, os.W_OK): + msg = '"{}" cannot be opened for writing' + raise UInputError(msg.format(self.devnode)) + + if len(self.name) > _uinput.maxnamelen: + msg = "uinput device name must not be longer than {} characters" + raise UInputError(msg.format(_uinput.maxnamelen)) + + def _find_device(self, fd: int) -> InputDevice: + """ + Tries to find the device node. Will delegate this task to one of + several platform-specific functions. + """ + if platform.system() == "Linux": + try: + sysname = _uinput.get_sysname(fd) + return self._find_device_linux(sysname) + except OSError: + # UI_GET_SYSNAME returned an error code. We're likely dealing with + # an old kernel. Guess the device based on the filesystem. + pass + + # If we're not running or Linux or the above method fails for any reason, + # use the generic fallback method. + return self._find_device_fallback() + + def _find_device_linux(self, sysname: str) -> InputDevice: + """ + Tries to find the device node when running on Linux. + """ + + syspath = f"/sys/devices/virtual/input/{sysname}" + + # The sysfs entry for event devices should contain exactly one folder + # whose name matches the format "event[0-9]+". It is then assumed that + # the device node in /dev/input uses the same name. + regex = re.compile("event[0-9]+") + for entry in os.listdir(syspath): + if regex.fullmatch(entry): + device_path = f"/dev/input/{entry}" + break + else: # no break + raise FileNotFoundError() + + # It is possible that there is some delay before /dev/input/event* shows + # up on old systems that do not use devtmpfs, so if the device cannot be + # found, wait for a short amount and then try again once. + # + # Furthermore, even if devtmpfs is in use, it is possible that the device + # does show up immediately, but without the correct permissions that + # still need to be set by udev. Wait for up to two seconds for either the + # device to show up or the permissions to be set. + for attempt in range(19): + try: + return InputDevice(device_path) + except (FileNotFoundError, PermissionError): + time.sleep(0.1) + + # Last attempt. If this fails, whatever exception the last attempt raises + # shall be the exception that this function raises. + return InputDevice(device_path) + + def _find_device_fallback(self) -> Union[InputDevice, None]: + """ + Tries to find the device node when UI_GET_SYSNAME is not available or + we're running on a system sufficiently exotic that we do not know how + to interpret its return value. + """ + #:bug: the device node might not be immediately available + time.sleep(0.1) + + # There could also be another device with the same name already present, + # make sure to select the newest one. + # Strictly speaking, we cannot be certain that everything returned by list_devices() + # ends at event[0-9]+: it might return something like "/dev/input/events_all". Find + # the devices that have the expected structure and extract their device number. + path_number_pairs = [] + regex = re.compile("/dev/input/event([0-9]+)") + for path in util.list_devices("/dev/input/"): + regex_match = regex.fullmatch(path) + if not regex_match: + continue + device_number = int(regex_match[1]) + path_number_pairs.append((path, device_number)) + + # The modification date of the devnode is not reliable unfortunately, so we + # are sorting by the number in the name + path_number_pairs.sort(key=lambda pair: pair[1], reverse=True) + + for path, _ in path_number_pairs: + d = InputDevice(path) + if d.name == self.name: + return d diff --git a/CLI/venv/lib/python3.12/site-packages/evdev/util.py b/CLI/venv/lib/python3.12/site-packages/evdev/util.py new file mode 100644 index 0000000..db89a22 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/evdev/util.py @@ -0,0 +1,146 @@ +import collections +import glob +import os +import re +import stat +from typing import Union, List + +from . import ecodes +from .events import InputEvent, event_factory, KeyEvent, RelEvent, AbsEvent, SynEvent + + +def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]: + """List readable character devices in ``input_device_dir``.""" + + fns = glob.glob("{}/event*".format(input_device_dir)) + return list(filter(is_device, fns)) + + +def is_device(fn: Union[str, bytes, os.PathLike]) -> bool: + """Check if ``fn`` is a readable and writable character device.""" + + if not os.path.exists(fn): + return False + + m = os.stat(fn)[stat.ST_MODE] + if not stat.S_ISCHR(m): + return False + + if not os.access(fn, os.R_OK | os.W_OK): + return False + + return True + + +def categorize(event: InputEvent) -> Union[InputEvent, KeyEvent, RelEvent, AbsEvent, SynEvent]: + """ + Categorize an event according to its type. + + The :data:`event_factory ` dictionary + maps event types to sub-classes of :class:`InputEvent + `. If the event cannot be categorized, it + is returned unmodified.""" + + if event.type in event_factory: + return event_factory[event.type](event) + else: + return event + + +def resolve_ecodes_dict(typecodemap, unknown="?"): + """ + Resolve event codes and types to their verbose names. + + :param typecodemap: mapping of event types to lists of event codes. + :param unknown: symbol to which unknown types or codes will be resolved. + + Example + ------- + >>> resolve_ecodes_dict({ 1: [272, 273, 274] }) + { ('EV_KEY', 1): [('BTN_MOUSE', 272), + ('BTN_RIGHT', 273), + ('BTN_MIDDLE', 274)] } + + If ``typecodemap`` contains absolute axis info (instances of + :class:`AbsInfo ` ) the result would look + like: + + >>> resolve_ecodes_dict({ 3: [(0, AbsInfo(...))] }) + { ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] } + """ + + for etype, codes in typecodemap.items(): + type_name = ecodes.EV[etype] + + # ecodes.keys are a combination of KEY_ and BTN_ codes + if etype == ecodes.EV_KEY: + ecode_dict = ecodes.keys + else: + ecode_dict = getattr(ecodes, type_name.split("_")[-1]) + + resolved = resolve_ecodes(ecode_dict, codes, unknown) + yield (type_name, etype), resolved + + +def resolve_ecodes(ecode_dict, ecode_list, unknown="?"): + """ + Resolve event codes and types to their verbose names. + + Example + ------- + >>> resolve_ecodes(ecodes.BTN, [272, 273, 274]) + [(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)] + """ + res = [] + for ecode in ecode_list: + # elements with AbsInfo(), eg { 3 : [(0, AbsInfo(...)), (1, AbsInfo(...))] } + if isinstance(ecode, tuple): + if ecode[0] in ecode_dict: + l = ((ecode_dict[ecode[0]], ecode[0]), ecode[1]) + else: + l = ((unknown, ecode[0]), ecode[1]) + + # just ecodes, e.g: { 0 : [0, 1, 3], 1 : [30, 48] } + else: + if ecode in ecode_dict: + l = (ecode_dict[ecode], ecode) + else: + l = (unknown, ecode) + res.append(l) + + return res + + +def find_ecodes_by_regex(regex): + """ + Find ecodes matching a regex and return a mapping of event type to event codes. + + regex can be a pattern string or a compiled regular expression object. + + Example + ------- + >>> find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)') + {1: [411], 3: [10]} + >>> res = find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)') + >>> resolve_ecodes_dict(res) + { + ('EV_KEY', 1): [('KEY_BREAK', 411)], + ('EV_ABS', 3): [('ABS_BRAKE', 10)] + } + """ + + regex = re.compile(regex) # re.compile is idempotent + result = collections.defaultdict(list) + + for type_code, codes in ecodes.bytype.items(): + for code, names in codes.items(): + names = (names,) if isinstance(names, str) else names + for name in names: + if regex.match(name): + result[type_code].append(code) + break + + return dict(result) + + +__all__ = ("list_devices", "is_device", "categorize", "resolve_ecodes", "resolve_ecodes_dict", "find_ecodes_by_regex") diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/LICENSE.txt b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/LICENSE.txt new file mode 100644 index 0000000..4f3cb7b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Lucas Boppre Niehues + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/METADATA new file mode 100644 index 0000000..0bafc4c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/METADATA @@ -0,0 +1,101 @@ +Metadata-Version: 2.1 +Name: keyboard +Version: 0.13.5 +Summary: Hook and simulate keyboard events on Windows and Linux +Home-page: https://github.com/boppreh/keyboard +Author: BoppreH +Author-email: boppreh@gmail.com +License: MIT +Keywords: keyboard hook simulate hotkey +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: Unix +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +Description-Content-Type: text/markdown +Requires-Dist: pyobjc ; sys_platform == "darwin" + + +keyboard +======== + +Take full control of your keyboard with this small Python library. Hook global events, register hotkeys, simulate key presses and much more. + +## Features + +- **Global event hook** on all keyboards (captures keys regardless of focus). +- **Listen** and **send** keyboard events. +- Works with **Windows** and **Linux** (requires sudo), with experimental **OS X** support (thanks @glitchassassin!). +- **Pure Python**, no C modules to be compiled. +- **Zero dependencies**. Trivial to install and deploy, just copy the files. +- **Python 2 and 3**. +- Complex hotkey support (e.g. `ctrl+shift+m, ctrl+space`) with controllable timeout. +- Includes **high level API** (e.g. [record](#keyboard.record) and [play](#keyboard.play), [add_abbreviation](#keyboard.add_abbreviation)). +- Maps keys as they actually are in your layout, with **full internationalization support** (e.g. `Ctrl+ç`). +- Events automatically captured in separate thread, doesn't block main program. +- Tested and documented. +- Doesn't break accented dead keys (I'm looking at you, pyHook). +- Mouse support available via project [mouse](https://github.com/boppreh/mouse) (`pip install mouse`). + +## Usage + +Install the [PyPI package](https://pypi.python.org/pypi/keyboard/): + + pip install keyboard + +or clone the repository (no installation required, source files are sufficient): + + git clone https://github.com/boppreh/keyboard + +or [download and extract the zip](https://github.com/boppreh/keyboard/archive/master.zip) into your project folder. + +Then check the [API docs below](https://github.com/boppreh/keyboard#api) to see what features are available. + + +## Example + + +```py +import keyboard + +keyboard.press_and_release('shift+s, space') + +keyboard.write('The quick brown fox jumps over the lazy dog.') + +keyboard.add_hotkey('ctrl+shift+a', print, args=('triggered', 'hotkey')) + +# Press PAGE UP then PAGE DOWN to type "foobar". +keyboard.add_hotkey('page up, page down', lambda: keyboard.write('foobar')) + +# Blocks until you press esc. +keyboard.wait('esc') + +# Record events until 'esc' is pressed. +recorded = keyboard.record(until='esc') +# Then replay back at three times the speed. +keyboard.play(recorded, speed_factor=3) + +# Type @@ then press space to replace with abbreviation. +keyboard.add_abbreviation('@@', 'my.long.email@example.com') + +# Block forever, like `while True`. +keyboard.wait() +``` + +## Known limitations: + +- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21) +- Media keys on Linux may appear nameless (scan-code only) or not at all. [#20](https://github.com/boppreh/keyboard/issues/20) +- Key suppression/blocking only available on Windows. [#22](https://github.com/boppreh/keyboard/issues/22) +- To avoid depending on X, the Linux parts reads raw device files (`/dev/input/input*`) +but this requires root. +- Other applications, such as some games, may register hooks that swallow all +key events. In this case `keyboard` will be unable to report events. +- This program makes no attempt to hide itself, so don't use it for keyloggers or online gaming bots. Be responsible. + + diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/RECORD new file mode 100644 index 0000000..b14a077 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/RECORD @@ -0,0 +1,39 @@ +keyboard-0.13.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +keyboard-0.13.5.dist-info/LICENSE.txt,sha256=K_FKUlVV0FqAHC0sKJAVBPt2q-58LX6_tM_HUI198Pc,1077 +keyboard-0.13.5.dist-info/METADATA,sha256=qdTVFmZpvjgDt65k7TGam77g3iiw3o1pgBrwWDRL-6w,3955 +keyboard-0.13.5.dist-info/RECORD,, +keyboard-0.13.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +keyboard-0.13.5.dist-info/WHEEL,sha256=v8slff5hmCpvciQ3G55d2d1CnOBupjDFJHDE2dUb1Ao,97 +keyboard-0.13.5.dist-info/top_level.txt,sha256=c5wzGrDqCQG1WTTAnxmIHqUWNvjPR9E1TLvrIfpzE-E,9 +keyboard/__init__.py,sha256=ZNeZFyglHAH2S8R5fQEKSYetMzgAr0-F-F9KUBH9r4E,43578 +keyboard/__main__.py,sha256=hT5QQiFEKZ7U9009Ox0JMONeON4vzhHwS7X-J5KU38M,378 +keyboard/__pycache__/__init__.cpython-312.pyc,, +keyboard/__pycache__/__main__.cpython-312.pyc,, +keyboard/__pycache__/_canonical_names.cpython-312.pyc,, +keyboard/__pycache__/_darwinkeyboard.cpython-312.pyc,, +keyboard/__pycache__/_darwinmouse.cpython-312.pyc,, +keyboard/__pycache__/_generic.cpython-312.pyc,, +keyboard/__pycache__/_keyboard_event.cpython-312.pyc,, +keyboard/__pycache__/_keyboard_tests.cpython-312.pyc,, +keyboard/__pycache__/_mouse_event.cpython-312.pyc,, +keyboard/__pycache__/_mouse_tests.cpython-312.pyc,, +keyboard/__pycache__/_nixcommon.cpython-312.pyc,, +keyboard/__pycache__/_nixkeyboard.cpython-312.pyc,, +keyboard/__pycache__/_nixmouse.cpython-312.pyc,, +keyboard/__pycache__/_winkeyboard.cpython-312.pyc,, +keyboard/__pycache__/_winmouse.cpython-312.pyc,, +keyboard/__pycache__/mouse.cpython-312.pyc,, +keyboard/_canonical_names.py,sha256=_V7K9lmF5z0eMbdMHr85KWoE_SC79zoeYfYB3n914pE,29474 +keyboard/_darwinkeyboard.py,sha256=nmDPlMPM2iE5ioZJpZf40GJgdFWta_xKnbwIv3efzAM,18124 +keyboard/_darwinmouse.py,sha256=YoD2RmGEnCoptlKn9Tbzg3k9pBVsosetxxQ5Fo3fb8E,6515 +keyboard/_generic.py,sha256=DMB0E7Sc4XvnGL_7B9mDbKioGgMSIUiwCkuGV1vDTrY,2176 +keyboard/_keyboard_event.py,sha256=Spsn28-Tbv50fGB8YBVVvzdaYP3Qd8DDJ_OHrMltskM,1630 +keyboard/_keyboard_tests.py,sha256=TKsNk_ZEGGe7RBb48SZp9QG6l9a0M_FeQ_vyrTQ4x9c,36830 +keyboard/_mouse_event.py,sha256=zRQGO6M6nbA-jvhI0yz4HzvQNcScF48PZ9iRegcTVjQ,422 +keyboard/_mouse_tests.py,sha256=jeXMAm8NCnM1xfoMacfj0Rqves8Zs7mehZHT8c0weaw,10014 +keyboard/_nixcommon.py,sha256=WLzMzpb7SB03Wpohzoh4BbLBZZMre_NHKfRrRdjhb_k,6053 +keyboard/_nixkeyboard.py,sha256=jBnwq-yVNb9j67P9OpeR7WBt1J6499VW_Uia3FDFRQo,5882 +keyboard/_nixmouse.py,sha256=rgcxW1Y0xljbk_Ljtqc08PLe9F9_jCki-oQUz-LvHcI,3518 +keyboard/_winkeyboard.py,sha256=13TcS23FQ9cLH6IUIuPG2tc8436DqjGfQo01_spDEaQ,20607 +keyboard/_winmouse.py,sha256=_8t4jDlnVRqeKr0HvtTbvnD8xwElmpGFtqOlZbIAbwM,5817 +keyboard/mouse.py,sha256=Eq50w6QnyYAGiJ_Y7ERmU-jQlYO7NT0aSFMkR-Fnwnc,7639 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/REQUESTED b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/WHEEL new file mode 100644 index 0000000..d4fe38c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/top_level.txt new file mode 100644 index 0000000..c253983 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard-0.13.5.dist-info/top_level.txt @@ -0,0 +1 @@ +keyboard diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__init__.py b/CLI/venv/lib/python3.12/site-packages/keyboard/__init__.py new file mode 100644 index 0000000..4a87715 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/__init__.py @@ -0,0 +1,1157 @@ +# -*- coding: utf-8 -*- +""" +keyboard +======== + +Take full control of your keyboard with this small Python library. Hook global events, register hotkeys, simulate key presses and much more. + +## Features + +- **Global event hook** on all keyboards (captures keys regardless of focus). +- **Listen** and **send** keyboard events. +- Works with **Windows** and **Linux** (requires sudo), with experimental **OS X** support (thanks @glitchassassin!). +- **Pure Python**, no C modules to be compiled. +- **Zero dependencies**. Trivial to install and deploy, just copy the files. +- **Python 2 and 3**. +- Complex hotkey support (e.g. `ctrl+shift+m, ctrl+space`) with controllable timeout. +- Includes **high level API** (e.g. [record](#keyboard.record) and [play](#keyboard.play), [add_abbreviation](#keyboard.add_abbreviation)). +- Maps keys as they actually are in your layout, with **full internationalization support** (e.g. `Ctrl+ç`). +- Events automatically captured in separate thread, doesn't block main program. +- Tested and documented. +- Doesn't break accented dead keys (I'm looking at you, pyHook). +- Mouse support available via project [mouse](https://github.com/boppreh/mouse) (`pip install mouse`). + +## Usage + +Install the [PyPI package](https://pypi.python.org/pypi/keyboard/): + + pip install keyboard + +or clone the repository (no installation required, source files are sufficient): + + git clone https://github.com/boppreh/keyboard + +or [download and extract the zip](https://github.com/boppreh/keyboard/archive/master.zip) into your project folder. + +Then check the [API docs below](https://github.com/boppreh/keyboard#api) to see what features are available. + + +## Example + + +```py +import keyboard + +keyboard.press_and_release('shift+s, space') + +keyboard.write('The quick brown fox jumps over the lazy dog.') + +keyboard.add_hotkey('ctrl+shift+a', print, args=('triggered', 'hotkey')) + +# Press PAGE UP then PAGE DOWN to type "foobar". +keyboard.add_hotkey('page up, page down', lambda: keyboard.write('foobar')) + +# Blocks until you press esc. +keyboard.wait('esc') + +# Record events until 'esc' is pressed. +recorded = keyboard.record(until='esc') +# Then replay back at three times the speed. +keyboard.play(recorded, speed_factor=3) + +# Type @@ then press space to replace with abbreviation. +keyboard.add_abbreviation('@@', 'my.long.email@example.com') + +# Block forever, like `while True`. +keyboard.wait() +``` + +## Known limitations: + +- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21) +- Media keys on Linux may appear nameless (scan-code only) or not at all. [#20](https://github.com/boppreh/keyboard/issues/20) +- Key suppression/blocking only available on Windows. [#22](https://github.com/boppreh/keyboard/issues/22) +- To avoid depending on X, the Linux parts reads raw device files (`/dev/input/input*`) +but this requires root. +- Other applications, such as some games, may register hooks that swallow all +key events. In this case `keyboard` will be unable to report events. +- This program makes no attempt to hide itself, so don't use it for keyloggers or online gaming bots. Be responsible. +""" +from __future__ import print_function as _print_function + +version = '0.13.5' + +import re as _re +import itertools as _itertools +import collections as _collections +from threading import Thread as _Thread, Lock as _Lock +import time as _time +# Python2... Buggy on time changes and leap seconds, but no other good option (https://stackoverflow.com/questions/1205722/how-do-i-get-monotonic-time-durations-in-python). +_time.monotonic = getattr(_time, 'monotonic', None) or _time.time + +try: + # Python2 + long, basestring + _is_str = lambda x: isinstance(x, basestring) + _is_number = lambda x: isinstance(x, (int, long)) + import Queue as _queue + # threading.Event is a function in Python2 wrappin _Event (?!). + from threading import _Event as _UninterruptibleEvent +except NameError: + # Python3 + _is_str = lambda x: isinstance(x, str) + _is_number = lambda x: isinstance(x, int) + import queue as _queue + from threading import Event as _UninterruptibleEvent +_is_list = lambda x: isinstance(x, (list, tuple)) + +# Just a dynamic object to store attributes for the closures. +class _State(object): pass + +# The "Event" class from `threading` ignores signals when waiting and is +# impossible to interrupt with Ctrl+C. So we rewrite `wait` to wait in small, +# interruptible intervals. +class _Event(_UninterruptibleEvent): + def wait(self): + while True: + if _UninterruptibleEvent.wait(self, 0.5): + break + +import platform as _platform +if _platform.system() == 'Windows': + from. import _winkeyboard as _os_keyboard +elif _platform.system() == 'Linux': + from. import _nixkeyboard as _os_keyboard +elif _platform.system() == 'Darwin': + from. import _darwinkeyboard as _os_keyboard +else: + raise OSError("Unsupported platform '{}'".format(_platform.system())) + +from ._keyboard_event import KEY_DOWN, KEY_UP, KeyboardEvent +from ._generic import GenericListener as _GenericListener +from ._canonical_names import all_modifiers, sided_modifiers, normalize_name + +_modifier_scan_codes = set() +def is_modifier(key): + """ + Returns True if `key` is a scan code or name of a modifier key. + """ + if _is_str(key): + return key in all_modifiers + else: + if not _modifier_scan_codes: + scan_codes = (key_to_scan_codes(name, False) for name in all_modifiers) + _modifier_scan_codes.update(*scan_codes) + return key in _modifier_scan_codes + +_pressed_events_lock = _Lock() +_pressed_events = {} +_physically_pressed_keys = _pressed_events +_logically_pressed_keys = {} +class _KeyboardListener(_GenericListener): + transition_table = { + #Current state of the modifier, per `modifier_states`. + #| + #| Type of event that triggered this modifier update. + #| | + #| | Type of key that triggered this modiier update. + #| | | + #| | | Should we send a fake key press? + #| | | | + #| | | => | Accept the event? + #| | | | | + #| | | | | Next state. + #v v v v v v + ('free', KEY_UP, 'modifier'): (False, True, 'free'), + ('free', KEY_DOWN, 'modifier'): (False, False, 'pending'), + ('pending', KEY_UP, 'modifier'): (True, True, 'free'), + ('pending', KEY_DOWN, 'modifier'): (False, True, 'allowed'), + ('suppressed', KEY_UP, 'modifier'): (False, False, 'free'), + ('suppressed', KEY_DOWN, 'modifier'): (False, False, 'suppressed'), + ('allowed', KEY_UP, 'modifier'): (False, True, 'free'), + ('allowed', KEY_DOWN, 'modifier'): (False, True, 'allowed'), + + ('free', KEY_UP, 'hotkey'): (False, None, 'free'), + ('free', KEY_DOWN, 'hotkey'): (False, None, 'free'), + ('pending', KEY_UP, 'hotkey'): (False, None, 'suppressed'), + ('pending', KEY_DOWN, 'hotkey'): (False, None, 'suppressed'), + ('suppressed', KEY_UP, 'hotkey'): (False, None, 'suppressed'), + ('suppressed', KEY_DOWN, 'hotkey'): (False, None, 'suppressed'), + ('allowed', KEY_UP, 'hotkey'): (False, None, 'allowed'), + ('allowed', KEY_DOWN, 'hotkey'): (False, None, 'allowed'), + + ('free', KEY_UP, 'other'): (False, True, 'free'), + ('free', KEY_DOWN, 'other'): (False, True, 'free'), + ('pending', KEY_UP, 'other'): (True, True, 'allowed'), + ('pending', KEY_DOWN, 'other'): (True, True, 'allowed'), + # Necessary when hotkeys are removed after beign triggered, such as + # TestKeyboard.test_add_hotkey_multistep_suppress_modifier. + ('suppressed', KEY_UP, 'other'): (False, False, 'allowed'), + ('suppressed', KEY_DOWN, 'other'): (True, True, 'allowed'), + ('allowed', KEY_UP, 'other'): (False, True, 'allowed'), + ('allowed', KEY_DOWN, 'other'): (False, True, 'allowed'), + } + + def init(self): + _os_keyboard.init() + + self.active_modifiers = set() + self.blocking_hooks = [] + self.blocking_keys = _collections.defaultdict(list) + self.nonblocking_keys = _collections.defaultdict(list) + self.blocking_hotkeys = _collections.defaultdict(list) + self.nonblocking_hotkeys = _collections.defaultdict(list) + self.filtered_modifiers = _collections.Counter() + self.is_replaying = False + + # Supporting hotkey suppression is harder than it looks. See + # https://github.com/boppreh/keyboard/issues/22 + self.modifier_states = {} # "alt" -> "allowed" + + def pre_process_event(self, event): + for key_hook in self.nonblocking_keys[event.scan_code]: + key_hook(event) + + with _pressed_events_lock: + hotkey = tuple(sorted(_pressed_events)) + for callback in self.nonblocking_hotkeys[hotkey]: + callback(event) + + return event.scan_code or (event.name and event.name != 'unknown') + + def direct_callback(self, event): + """ + This function is called for every OS keyboard event and decides if the + event should be blocked or not, and passes a copy of the event to + other, non-blocking, listeners. + + There are two ways to block events: remapped keys, which translate + events by suppressing and re-emitting; and blocked hotkeys, which + suppress specific hotkeys. + """ + # Pass through all fake key events, don't even report to other handlers. + if self.is_replaying: + return True + + if not all(hook(event) for hook in self.blocking_hooks): + return False + + event_type = event.event_type + scan_code = event.scan_code + + # Update tables of currently pressed keys and modifiers. + with _pressed_events_lock: + if event_type == KEY_DOWN: + if is_modifier(scan_code): self.active_modifiers.add(scan_code) + _pressed_events[scan_code] = event + hotkey = tuple(sorted(_pressed_events)) + if event_type == KEY_UP: + self.active_modifiers.discard(scan_code) + if scan_code in _pressed_events: del _pressed_events[scan_code] + + # Mappings based on individual keys instead of hotkeys. + for key_hook in self.blocking_keys[scan_code]: + if not key_hook(event): + return False + + # Default accept. + accept = True + + if self.blocking_hotkeys: + if self.filtered_modifiers[scan_code]: + origin = 'modifier' + modifiers_to_update = set([scan_code]) + else: + modifiers_to_update = self.active_modifiers + if is_modifier(scan_code): + modifiers_to_update = modifiers_to_update | {scan_code} + callback_results = [callback(event) for callback in self.blocking_hotkeys[hotkey]] + if callback_results: + accept = all(callback_results) + origin = 'hotkey' + else: + origin = 'other' + + for key in sorted(modifiers_to_update): + transition_tuple = (self.modifier_states.get(key, 'free'), event_type, origin) + should_press, new_accept, new_state = self.transition_table[transition_tuple] + if should_press: press(key) + if new_accept is not None: accept = new_accept + self.modifier_states[key] = new_state + + if accept: + if event_type == KEY_DOWN: + _logically_pressed_keys[scan_code] = event + elif event_type == KEY_UP and scan_code in _logically_pressed_keys: + del _logically_pressed_keys[scan_code] + + # Queue for handlers that won't block the event. + self.queue.put(event) + + return accept + + def listen(self): + _os_keyboard.listen(self.direct_callback) + +_listener = _KeyboardListener() + +def key_to_scan_codes(key, error_if_missing=True): + """ + Returns a list of scan codes associated with this key (name or scan code). + """ + if _is_number(key): + return (key,) + elif _is_list(key): + return sum((key_to_scan_codes(i) for i in key), ()) + elif not _is_str(key): + raise ValueError('Unexpected key type ' + str(type(key)) + ', value (' + repr(key) + ')') + + normalized = normalize_name(key) + if normalized in sided_modifiers: + left_scan_codes = key_to_scan_codes('left ' + normalized, False) + right_scan_codes = key_to_scan_codes('right ' + normalized, False) + return left_scan_codes + tuple(c for c in right_scan_codes if c not in left_scan_codes) + + try: + # Put items in ordered dict to remove duplicates. + t = tuple(_collections.OrderedDict((scan_code, True) for scan_code, modifier in _os_keyboard.map_name(normalized))) + e = None + except (KeyError, ValueError) as exception: + t = () + e = exception + + if not t and error_if_missing: + raise ValueError('Key {} is not mapped to any known key.'.format(repr(key)), e) + else: + return t + +def parse_hotkey(hotkey): + """ + Parses a user-provided hotkey into nested tuples representing the + parsed structure, with the bottom values being lists of scan codes. + Also accepts raw scan codes, which are then wrapped in the required + number of nestings. + + Example: + + parse_hotkey("alt+shift+a, alt+b, c") + # Keys: ^~^ ^~~~^ ^ ^~^ ^ ^ + # Steps: ^~~~~~~~~~^ ^~~~^ ^ + + # ((alt_codes, shift_codes, a_codes), (alt_codes, b_codes), (c_codes,)) + """ + if _is_number(hotkey) or len(hotkey) == 1: + scan_codes = key_to_scan_codes(hotkey) + step = (scan_codes,) + steps = (step,) + return steps + elif _is_list(hotkey): + if not any(map(_is_list, hotkey)): + step = tuple(key_to_scan_codes(k) for k in hotkey) + steps = (step,) + return steps + return hotkey + + steps = [] + for step in _re.split(r',\s?', hotkey): + keys = _re.split(r'\s?\+\s?', step) + steps.append(tuple(key_to_scan_codes(key) for key in keys)) + return tuple(steps) + +def send(hotkey, do_press=True, do_release=True): + """ + Sends OS events that perform the given *hotkey* hotkey. + + - `hotkey` can be either a scan code (e.g. 57 for space), single key + (e.g. 'space') or multi-key, multi-step hotkey (e.g. 'alt+F4, enter'). + - `do_press` if true then press events are sent. Defaults to True. + - `do_release` if true then release events are sent. Defaults to True. + + send(57) + send('ctrl+alt+del') + send('alt+F4, enter') + send('shift+s') + + Note: keys are released in the opposite order they were pressed. + """ + _listener.is_replaying = True + + parsed = parse_hotkey(hotkey) + for step in parsed: + if do_press: + for scan_codes in step: + _os_keyboard.press(scan_codes[0]) + + if do_release: + for scan_codes in reversed(step): + _os_keyboard.release(scan_codes[0]) + + _listener.is_replaying = False + +# Alias. +press_and_release = send + +def press(hotkey): + """ Presses and holds down a hotkey (see `send`). """ + send(hotkey, True, False) + +def release(hotkey): + """ Releases a hotkey (see `send`). """ + send(hotkey, False, True) + +def is_pressed(hotkey): + """ + Returns True if the key is pressed. + + is_pressed(57) #-> True + is_pressed('space') #-> True + is_pressed('ctrl+space') #-> True + """ + _listener.start_if_necessary() + + if _is_number(hotkey): + # Shortcut. + with _pressed_events_lock: + return hotkey in _pressed_events + + steps = parse_hotkey(hotkey) + if len(steps) > 1: + raise ValueError("Impossible to check if multi-step hotkeys are pressed (`a+b` is ok, `a, b` isn't).") + + # Convert _pressed_events into a set + with _pressed_events_lock: + pressed_scan_codes = set(_pressed_events) + for scan_codes in steps[0]: + if not any(scan_code in pressed_scan_codes for scan_code in scan_codes): + return False + return True + +def call_later(fn, args=(), delay=0.001): + """ + Calls the provided function in a new thread after waiting some time. + Useful for giving the system some time to process an event, without blocking + the current execution flow. + """ + thread = _Thread(target=lambda: (_time.sleep(delay), fn(*args))) + thread.start() + +_hooks = {} +def hook(callback, suppress=False, on_remove=lambda: None): + """ + Installs a global listener on all available keyboards, invoking `callback` + each time a key is pressed or released. + + The event passed to the callback is of type `keyboard.KeyboardEvent`, + with the following attributes: + + - `name`: an Unicode representation of the character (e.g. "&") or + description (e.g. "space"). The name is always lower-case. + - `scan_code`: number representing the physical key, e.g. 55. + - `time`: timestamp of the time the event occurred, with as much precision + as given by the OS. + + Returns the given callback for easier development. + """ + if suppress: + _listener.start_if_necessary() + append, remove = _listener.blocking_hooks.append, _listener.blocking_hooks.remove + else: + append, remove = _listener.add_handler, _listener.remove_handler + + append(callback) + def remove_(): + del _hooks[callback] + del _hooks[remove_] + remove(callback) + on_remove() + _hooks[callback] = _hooks[remove_] = remove_ + return remove_ + +def on_press(callback, suppress=False): + """ + Invokes `callback` for every KEY_DOWN event. For details see `hook`. + """ + return hook(lambda e: e.event_type == KEY_UP or callback(e), suppress=suppress) + +def on_release(callback, suppress=False): + """ + Invokes `callback` for every KEY_UP event. For details see `hook`. + """ + return hook(lambda e: e.event_type == KEY_DOWN or callback(e), suppress=suppress) + +def hook_key(key, callback, suppress=False): + """ + Hooks key up and key down events for a single key. Returns the event handler + created. To remove a hooked key use `unhook_key(key)` or + `unhook_key(handler)`. + + Note: this function shares state with hotkeys, so `clear_all_hotkeys` + affects it as well. + """ + _listener.start_if_necessary() + store = _listener.blocking_keys if suppress else _listener.nonblocking_keys + scan_codes = key_to_scan_codes(key) + for scan_code in scan_codes: + store[scan_code].append(callback) + + def remove_(): + del _hooks[callback] + del _hooks[key] + del _hooks[remove_] + for scan_code in scan_codes: + store[scan_code].remove(callback) + _hooks[callback] = _hooks[key] = _hooks[remove_] = remove_ + return remove_ + +def on_press_key(key, callback, suppress=False): + """ + Invokes `callback` for KEY_DOWN event related to the given key. For details see `hook`. + """ + return hook_key(key, lambda e: e.event_type == KEY_UP or callback(e), suppress=suppress) + +def on_release_key(key, callback, suppress=False): + """ + Invokes `callback` for KEY_UP event related to the given key. For details see `hook`. + """ + return hook_key(key, lambda e: e.event_type == KEY_DOWN or callback(e), suppress=suppress) + +def unhook(remove): + """ + Removes a previously added hook, either by callback or by the return value + of `hook`. + """ + _hooks[remove]() +unhook_key = unhook + +def unhook_all(): + """ + Removes all keyboard hooks in use, including hotkeys, abbreviations, word + listeners, `record`ers and `wait`s. + """ + _listener.start_if_necessary() + _listener.blocking_keys.clear() + _listener.nonblocking_keys.clear() + del _listener.blocking_hooks[:] + del _listener.handlers[:] + unhook_all_hotkeys() + +def block_key(key): + """ + Suppresses all key events of the given key, regardless of modifiers. + """ + return hook_key(key, lambda e: False, suppress=True) +unblock_key = unhook_key + +def remap_key(src, dst): + """ + Whenever the key `src` is pressed or released, regardless of modifiers, + press or release the hotkey `dst` instead. + """ + def handler(event): + if event.event_type == KEY_DOWN: + press(dst) + else: + release(dst) + return False + return hook_key(src, handler, suppress=True) +unremap_key = unhook_key + +def parse_hotkey_combinations(hotkey): + """ + Parses a user-provided hotkey. Differently from `parse_hotkey`, + instead of each step being a list of the different scan codes for each key, + each step is a list of all possible combinations of those scan codes. + """ + def combine_step(step): + # A single step may be composed of many keys, and each key can have + # multiple scan codes. To speed up hotkey matching and avoid introducing + # event delays, we list all possible combinations of scan codes for these + # keys. Hotkeys are usually small, and there are not many combinations, so + # this is not as insane as it sounds. + return (tuple(sorted(scan_codes)) for scan_codes in _itertools.product(*step)) + + return tuple(tuple(combine_step(step)) for step in parse_hotkey(hotkey)) + +def _add_hotkey_step(handler, combinations, suppress): + """ + Hooks a single-step hotkey (e.g. 'shift+a'). + """ + container = _listener.blocking_hotkeys if suppress else _listener.nonblocking_hotkeys + + # Register the scan codes of every possible combination of + # modfiier + main key. Modifiers have to be registered in + # filtered_modifiers too, so suppression and replaying can work. + for scan_codes in combinations: + for scan_code in scan_codes: + if is_modifier(scan_code): + _listener.filtered_modifiers[scan_code] += 1 + container[scan_codes].append(handler) + + def remove(): + for scan_codes in combinations: + for scan_code in scan_codes: + if is_modifier(scan_code): + _listener.filtered_modifiers[scan_code] -= 1 + container[scan_codes].remove(handler) + return remove + +_hotkeys = {} +def add_hotkey(hotkey, callback, args=(), suppress=False, timeout=1, trigger_on_release=False): + """ + Invokes a callback every time a hotkey is pressed. The hotkey must + be in the format `ctrl+shift+a, s`. This would trigger when the user holds + ctrl, shift and "a" at once, releases, and then presses "s". To represent + literal commas, pluses, and spaces, use their names ('comma', 'plus', + 'space'). + + - `args` is an optional list of arguments to passed to the callback during + each invocation. + - `suppress` defines if successful triggers should block the keys from being + sent to other programs. + - `timeout` is the amount of seconds allowed to pass between key presses. + - `trigger_on_release` if true, the callback is invoked on key release instead + of key press. + + The event handler function is returned. To remove a hotkey call + `remove_hotkey(hotkey)` or `remove_hotkey(handler)`. + before the hotkey state is reset. + + Note: hotkeys are activated when the last key is *pressed*, not released. + Note: the callback is executed in a separate thread, asynchronously. For an + example of how to use a callback synchronously, see `wait`. + + Examples: + + # Different but equivalent ways to listen for a spacebar key press. + add_hotkey(' ', print, args=['space was pressed']) + add_hotkey('space', print, args=['space was pressed']) + add_hotkey('Space', print, args=['space was pressed']) + # Here 57 represents the keyboard code for spacebar; so you will be + # pressing 'spacebar', not '57' to activate the print function. + add_hotkey(57, print, args=['space was pressed']) + + add_hotkey('ctrl+q', quit) + add_hotkey('ctrl+alt+enter, space', some_callback) + """ + if args: + callback = lambda callback=callback: callback(*args) + + _listener.start_if_necessary() + + steps = parse_hotkey_combinations(hotkey) + + event_type = KEY_UP if trigger_on_release else KEY_DOWN + if len(steps) == 1: + # Deciding when to allow a KEY_UP event is far harder than I thought, + # and any mistake will make that key "sticky". Therefore just let all + # KEY_UP events go through as long as that's not what we are listening + # for. + handler = lambda e: (event_type == KEY_DOWN and e.event_type == KEY_UP and e.scan_code in _logically_pressed_keys) or (event_type == e.event_type and callback()) + remove_step = _add_hotkey_step(handler, steps[0], suppress) + def remove_(): + remove_step() + del _hotkeys[hotkey] + del _hotkeys[remove_] + del _hotkeys[callback] + # TODO: allow multiple callbacks for each hotkey without overwriting the + # remover. + _hotkeys[hotkey] = _hotkeys[remove_] = _hotkeys[callback] = remove_ + return remove_ + + state = _State() + state.remove_catch_misses = None + state.remove_last_step = None + state.suppressed_events = [] + state.last_update = float('-inf') + + def catch_misses(event, force_fail=False): + if ( + event.event_type == event_type + and state.index + and event.scan_code not in allowed_keys_by_step[state.index] + ) or ( + timeout + and _time.monotonic() - state.last_update >= timeout + ) or force_fail: # Weird formatting to ensure short-circuit. + + state.remove_last_step() + + for event in state.suppressed_events: + if event.event_type == KEY_DOWN: + press(event.scan_code) + else: + release(event.scan_code) + del state.suppressed_events[:] + + index = 0 + set_index(0) + return True + + def set_index(new_index): + state.index = new_index + + if new_index == 0: + # This is done for performance reasons, avoiding a global key hook + # that is always on. + state.remove_catch_misses = lambda: None + elif new_index == 1: + state.remove_catch_misses() + # Must be `suppress=True` to ensure `send` has priority. + state.remove_catch_misses = hook(catch_misses, suppress=True) + + if new_index == len(steps) - 1: + def handler(event): + if event.event_type == KEY_UP: + remove() + set_index(0) + accept = event.event_type == event_type and callback() + if accept: + return catch_misses(event, force_fail=True) + else: + state.suppressed_events[:] = [event] + return False + remove = _add_hotkey_step(handler, steps[state.index], suppress) + else: + # Fix value of next_index. + def handler(event, new_index=state.index+1): + if event.event_type == KEY_UP: + remove() + set_index(new_index) + state.suppressed_events.append(event) + return False + remove = _add_hotkey_step(handler, steps[state.index], suppress) + state.remove_last_step = remove + state.last_update = _time.monotonic() + return False + set_index(0) + + allowed_keys_by_step = [ + set().union(*step) + for step in steps + ] + + def remove_(): + state.remove_catch_misses() + state.remove_last_step() + del _hotkeys[hotkey] + del _hotkeys[remove_] + del _hotkeys[callback] + # TODO: allow multiple callbacks for each hotkey without overwriting the + # remover. + _hotkeys[hotkey] = _hotkeys[remove_] = _hotkeys[callback] = remove_ + return remove_ +register_hotkey = add_hotkey + +def remove_hotkey(hotkey_or_callback): + """ + Removes a previously hooked hotkey. Must be called with the value returned + by `add_hotkey`. + """ + _hotkeys[hotkey_or_callback]() +unregister_hotkey = clear_hotkey = remove_hotkey + +def unhook_all_hotkeys(): + """ + Removes all keyboard hotkeys in use, including abbreviations, word listeners, + `record`ers and `wait`s. + """ + # Because of "alises" some hooks may have more than one entry, all of which + # are removed together. + _listener.blocking_hotkeys.clear() + _listener.nonblocking_hotkeys.clear() +unregister_all_hotkeys = remove_all_hotkeys = clear_all_hotkeys = unhook_all_hotkeys + +def remap_hotkey(src, dst, suppress=True, trigger_on_release=False): + """ + Whenever the hotkey `src` is pressed, suppress it and send + `dst` instead. + + Example: + + remap('alt+w', 'ctrl+up') + """ + def handler(): + active_modifiers = sorted(modifier for modifier, state in _listener.modifier_states.items() if state == 'allowed') + for modifier in active_modifiers: + release(modifier) + send(dst) + for modifier in reversed(active_modifiers): + press(modifier) + return False + return add_hotkey(src, handler, suppress=suppress, trigger_on_release=trigger_on_release) +unremap_hotkey = remove_hotkey + +def stash_state(): + """ + Builds a list of all currently pressed scan codes, releases them and returns + the list. Pairs well with `restore_state` and `restore_modifiers`. + """ + # TODO: stash caps lock / numlock /scrollock state. + with _pressed_events_lock: + state = sorted(_pressed_events) + for scan_code in state: + _os_keyboard.release(scan_code) + return state + +def restore_state(scan_codes): + """ + Given a list of scan_codes ensures these keys, and only these keys, are + pressed. Pairs well with `stash_state`, alternative to `restore_modifiers`. + """ + _listener.is_replaying = True + + with _pressed_events_lock: + current = set(_pressed_events) + target = set(scan_codes) + for scan_code in current - target: + _os_keyboard.release(scan_code) + for scan_code in target - current: + _os_keyboard.press(scan_code) + + _listener.is_replaying = False + +def restore_modifiers(scan_codes): + """ + Like `restore_state`, but only restores modifier keys. + """ + restore_state((scan_code for scan_code in scan_codes if is_modifier(scan_code))) + +def write(text, delay=0, restore_state_after=True, exact=None): + """ + Sends artificial keyboard events to the OS, simulating the typing of a given + text. Characters not available on the keyboard are typed as explicit unicode + characters using OS-specific functionality, such as alt+codepoint. + + To ensure text integrity, all currently pressed keys are released before + the text is typed, and modifiers are restored afterwards. + + - `delay` is the number of seconds to wait between keypresses, defaults to + no delay. + - `restore_state_after` can be used to restore the state of pressed keys + after the text is typed, i.e. presses the keys that were released at the + beginning. Defaults to True. + - `exact` forces typing all characters as explicit unicode (e.g. + alt+codepoint or special events). If None, uses platform-specific suggested + value. + """ + if exact is None: + exact = _platform.system() == 'Windows' + + state = stash_state() + + # Window's typing of unicode characters is quite efficient and should be preferred. + if exact: + for letter in text: + if letter in '\n\b': + send(letter) + else: + _os_keyboard.type_unicode(letter) + if delay: _time.sleep(delay) + else: + for letter in text: + try: + entries = _os_keyboard.map_name(normalize_name(letter)) + scan_code, modifiers = next(iter(entries)) + except (KeyError, ValueError): + _os_keyboard.type_unicode(letter) + continue + + for modifier in modifiers: + press(modifier) + + _os_keyboard.press(scan_code) + _os_keyboard.release(scan_code) + + for modifier in modifiers: + release(modifier) + + if delay: + _time.sleep(delay) + + if restore_state_after: + restore_modifiers(state) + +def wait(hotkey=None, suppress=False, trigger_on_release=False): + """ + Blocks the program execution until the given hotkey is pressed or, + if given no parameters, blocks forever. + """ + if hotkey: + lock = _Event() + remove = add_hotkey(hotkey, lambda: lock.set(), suppress=suppress, trigger_on_release=trigger_on_release) + lock.wait() + remove_hotkey(remove) + else: + while True: + _time.sleep(1e6) + +def get_hotkey_name(names=None): + """ + Returns a string representation of hotkey from the given key names, or + the currently pressed keys if not given. This function: + + - normalizes names; + - removes "left" and "right" prefixes; + - replaces the "+" key name with "plus" to avoid ambiguity; + - puts modifier keys first, in a standardized order; + - sort remaining keys; + - finally, joins everything with "+". + + Example: + + get_hotkey_name(['+', 'left ctrl', 'shift']) + # "ctrl+shift+plus" + """ + if names is None: + _listener.start_if_necessary() + with _pressed_events_lock: + names = [e.name for e in _pressed_events.values()] + else: + names = [normalize_name(name) for name in names] + clean_names = set(e.replace('left ', '').replace('right ', '').replace('+', 'plus') for e in names) + # https://developer.apple.com/macos/human-interface-guidelines/input-and-output/keyboard/ + # > List modifier keys in the correct order. If you use more than one modifier key in a + # > hotkey, always list them in this order: Control, Option, Shift, Command. + modifiers = ['ctrl', 'alt', 'shift', 'windows'] + sorting_key = lambda k: (modifiers.index(k) if k in modifiers else 5, str(k)) + return '+'.join(sorted(clean_names, key=sorting_key)) + +def read_event(suppress=False): + """ + Blocks until a keyboard event happens, then returns that event. + """ + queue = _queue.Queue(maxsize=1) + hooked = hook(queue.put, suppress=suppress) + while True: + event = queue.get() + unhook(hooked) + return event + +def read_key(suppress=False): + """ + Blocks until a keyboard event happens, then returns that event's name or, + if missing, its scan code. + """ + event = read_event(suppress) + return event.name or event.scan_code + +def read_hotkey(suppress=True): + """ + Similar to `read_key()`, but blocks until the user presses and releases a + hotkey (or single key), then returns a string representing the hotkey + pressed. + + Example: + + read_hotkey() + # "ctrl+shift+p" + """ + queue = _queue.Queue() + fn = lambda e: queue.put(e) or e.event_type == KEY_DOWN + hooked = hook(fn, suppress=suppress) + while True: + event = queue.get() + if event.event_type == KEY_UP: + unhook(hooked) + with _pressed_events_lock: + names = [e.name for e in _pressed_events.values()] + [event.name] + return get_hotkey_name(names) + +def get_typed_strings(events, allow_backspace=True): + """ + Given a sequence of events, tries to deduce what strings were typed. + Strings are separated when a non-textual key is pressed (such as tab or + enter). Characters are converted to uppercase according to shift and + capslock status. If `allow_backspace` is True, backspaces remove the last + character typed. + + This function is a generator, so you can pass an infinite stream of events + and convert them to strings in real time. + + Note this functions is merely an heuristic. Windows for example keeps per- + process keyboard state such as keyboard layout, and this information is not + available for our hooks. + + get_type_strings(record()) #-> ['This is what', 'I recorded', ''] + """ + backspace_name = 'delete' if _platform.system() == 'Darwin' else 'backspace' + + shift_pressed = False + capslock_pressed = False + string = '' + for event in events: + name = event.name + + # Space is the only key that we _parse_hotkey to the spelled out name + # because of legibility. Now we have to undo that. + if event.name == 'space': + name = ' ' + + if 'shift' in event.name: + shift_pressed = event.event_type == 'down' + elif event.name == 'caps lock' and event.event_type == 'down': + capslock_pressed = not capslock_pressed + elif allow_backspace and event.name == backspace_name and event.event_type == 'down': + string = string[:-1] + elif event.event_type == 'down': + if len(name) == 1: + if shift_pressed ^ capslock_pressed: + name = name.upper() + string = string + name + else: + yield string + string = '' + yield string + +_recording = None +def start_recording(recorded_events_queue=None): + """ + Starts recording all keyboard events into a global variable, or the given + queue if any. Returns the queue of events and the hooked function. + + Use `stop_recording()` or `unhook(hooked_function)` to stop. + """ + recorded_events_queue = recorded_events_queue or _queue.Queue() + global _recording + _recording = (recorded_events_queue, hook(recorded_events_queue.put)) + return _recording + +def stop_recording(): + """ + Stops the global recording of events and returns a list of the events + captured. + """ + global _recording + if not _recording: + raise ValueError('Must call "start_recording" before.') + recorded_events_queue, hooked = _recording + unhook(hooked) + return list(recorded_events_queue.queue) + +def record(until='escape', suppress=False, trigger_on_release=False): + """ + Records all keyboard events from all keyboards until the user presses the + given hotkey. Then returns the list of events recorded, of type + `keyboard.KeyboardEvent`. Pairs well with + `play(events)`. + + Note: this is a blocking function. + Note: for more details on the keyboard hook and events see `hook`. + """ + start_recording() + wait(until, suppress=suppress, trigger_on_release=trigger_on_release) + return stop_recording() + +def play(events, speed_factor=1.0): + """ + Plays a sequence of recorded events, maintaining the relative time + intervals. If speed_factor is <= 0 then the actions are replayed as fast + as the OS allows. Pairs well with `record()`. + + Note: the current keyboard state is cleared at the beginning and restored at + the end of the function. + """ + state = stash_state() + + last_time = None + for event in events: + if speed_factor > 0 and last_time is not None: + _time.sleep((event.time - last_time) / speed_factor) + last_time = event.time + + key = event.scan_code or event.name + press(key) if event.event_type == KEY_DOWN else release(key) + + restore_modifiers(state) +replay = play + +_word_listeners = {} +def add_word_listener(word, callback, triggers=['space'], match_suffix=False, timeout=2): + """ + Invokes a callback every time a sequence of characters is typed (e.g. 'pet') + and followed by a trigger key (e.g. space). Modifiers (e.g. alt, ctrl, + shift) are ignored. + + - `word` the typed text to be matched. E.g. 'pet'. + - `callback` is an argument-less function to be invoked each time the word + is typed. + - `triggers` is the list of keys that will cause a match to be checked. If + the user presses some key that is not a character (len>1) and not in + triggers, the characters so far will be discarded. By default the trigger + is only `space`. + - `match_suffix` defines if endings of words should also be checked instead + of only whole words. E.g. if true, typing 'carpet'+space will trigger the + listener for 'pet'. Defaults to false, only whole words are checked. + - `timeout` is the maximum number of seconds between typed characters before + the current word is discarded. Defaults to 2 seconds. + + Returns the event handler created. To remove a word listener use + `remove_word_listener(word)` or `remove_word_listener(handler)`. + + Note: all actions are performed on key down. Key up events are ignored. + Note: word matches are **case sensitive**. + """ + state = _State() + state.current = '' + state.time = -1 + + def handler(event): + name = event.name + if event.event_type == KEY_UP or name in all_modifiers: return + + if timeout and event.time - state.time > timeout: + state.current = '' + state.time = event.time + + matched = state.current == word or (match_suffix and state.current.endswith(word)) + if name in triggers and matched: + callback() + state.current = '' + elif len(name) > 1: + state.current = '' + else: + state.current += name + + hooked = hook(handler) + def remove(): + hooked() + del _word_listeners[word] + del _word_listeners[handler] + del _word_listeners[remove] + _word_listeners[word] = _word_listeners[handler] = _word_listeners[remove] = remove + # TODO: allow multiple word listeners and removing them correctly. + return remove + +def remove_word_listener(word_or_handler): + """ + Removes a previously registered word listener. Accepts either the word used + during registration (exact string) or the event handler returned by the + `add_word_listener` or `add_abbreviation` functions. + """ + _word_listeners[word_or_handler]() + +def add_abbreviation(source_text, replacement_text, match_suffix=False, timeout=2): + """ + Registers a hotkey that replaces one typed text with another. For example + + add_abbreviation('tm', u'™') + + Replaces every "tm" followed by a space with a ™ symbol (and no space). The + replacement is done by sending backspace events. + + - `match_suffix` defines if endings of words should also be checked instead + of only whole words. E.g. if true, typing 'carpet'+space will trigger the + listener for 'pet'. Defaults to false, only whole words are checked. + - `timeout` is the maximum number of seconds between typed characters before + the current word is discarded. Defaults to 2 seconds. + + For more details see `add_word_listener`. + """ + replacement = '\b'*(len(source_text)+1) + replacement_text + callback = lambda: write(replacement) + return add_word_listener(source_text, callback, match_suffix=match_suffix, timeout=timeout) + +# Aliases. +register_word_listener = add_word_listener +register_abbreviation = add_abbreviation +remove_abbreviation = remove_word_listener \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__main__.py b/CLI/venv/lib/python3.12/site-packages/keyboard/__main__.py new file mode 100644 index 0000000..3acc6f6 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/__main__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +import keyboard +import fileinput +import json +import sys + +def print_event_json(event): + print(event.to_json(ensure_ascii=sys.stdout.encoding != 'utf-8')) + sys.stdout.flush() +keyboard.hook(print_event_json) + +parse_event_json = lambda line: keyboard.KeyboardEvent(**json.loads(line)) +keyboard.play(parse_event_json(line) for line in fileinput.input()) \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3480b53d24160470cd2e7829163e442a144e17cc GIT binary patch literal 53753 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__main__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..effa3e2d4cca6e96bfd0d2fc03bc07d64b61613a GIT binary patch literal 1261 zcmahIOK1~8^v!0HrqzuR>#v|GXb*cxSF30R>A_UQC_Sin2uRpwr_H9@-DPG|jZ}yt zs33Z?9u*2ID(FE}5cI4UV_Pa)FXBaSVlV2+H=C}eRq!$M=Djy>-hbYxY6l?Pdh)t_ zmH>Q`Oa$>IVsRRYDKNn#HWZpCDUgs?3QBm!3Ncf;2nDJDgGy*KGSfU6y^r=K5HMq? znFuvgO<5~8=|#XhQc1T;oAmu9(I74mA62dp#svjhoQ*uqq84cnic2$(|eVk1&#}_jB z?w=?1amUvOxi!K1^b;0$J-su;Qo!{RFXYr`#eBdWs(+J3p`diF|o`uLr~ z?ZSLdf1{`W*`Y>H?s9gfV{n!p{6O0-<gS9pjs%67_7O7Q~xs@@t1lM>QLF&8p1?cm^-z zkcvE_uQ5W%Cs?xp=>=G|03F|`LN+tk)s$b4Lve+%jNpf-gV;-k!? U%}+CrGc!96%&NIL$c4Us0a8W*d;kCd literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_canonical_names.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_canonical_names.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7970af7952ea635256c356d6dda4167c834c7488 GIT binary patch literal 51763 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

5+?;Wu+ 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%0D9IoXQEKFNVQnB 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

hIxP0Ktg2BLm zE5;pggiaZ(qxM59`gl$rIH2bgzWHpd=Fo{i+E|IvDPbm>y@pBD`JYHFy^S_9hGb6w;hKz@?%Y%d{gJcquWh=n?skk zuYMtR^)`R?_SVpCnb5Oa*_G=#@8!mt2KlDJEzh8wa&0TSdc6k^`(eIicr2*e%&uM7Fg-MGjy}Jg`-N?zH*RySSjY(vKdRE}F{r9% zEilp?&ItEDF6y*WR*Z27o`b&-O0jpTU5!qk|H$Id574`{#rhmEJ7yY(bor50CpfH!z?iK^>;nk;oidqj;E)!H|( zImim`P`}VQV!C`@m%m!@fv)oNZWX$4$gLu}^f{~={-~60NFot@3lkJ=D&%#At8E|X zs?^(52_(ojZQ>Vg3U>a9qa}XVwn*bIvv@R1Zz;S@KR>T)w;4~4&&TCj9z7R~53D*o zuodGcTE*}r}4`U4z9H0P6V%s@iSEQp!Qc{7M!QFBdHSCjf3mx3aCkLw$b8UF1a z1n}#xJzzZaQm;IQ=#-01af7lUd%l8l5ekm`!J@>tiF58=*In2>#8cfZt=&TC0=Iva zv|%KIb?hJtDzI{)Z<#e<;9ECEGn+Sc&FTw*_$7F091Nz}-aBPydSig!4XoD9BUk&e6SLb>nT@)K~w@c{E?{dV%j0763&}U>nkT- zI`O;ht4&*(#XDI!o4IGAS!XwmXLoe2dsm~n(wMG-*HwI=JMiQH%0l(u1Hn%lK*b)^ z;b853q#;y(b*g5)M4PC>HlWn`)kJMgI8&+z#4B{h+xIZCFfO$KyqjP)-~>&b6nm@z zD#Em)Un=4={Pq*hEj)YZs92Fm&twgMk2T{Teb2y|)R3|QEScuR6Nj2w4*|FP33R*H zV-gJlPRSX9=(Q=EK)Ixziz@U;7!Cq(kQiA6`{69XI0LLLp)6Gxq$?s=f=2~>Q;8xZ zeA5aR3=S>PAkhUdibD;UI{@WCq5dOGunt}x9lAVyU3Dz9;h{N$v_1 zeHZ>hXw^>1YYn`s;kyg5#w&c|m8k3Lol8U;KEzuNtABOhqcg{Jb-b=_ z{pfp@8~#{pFW=hx@Qcybk!bVi=GAL_^R> zlQH)aA(%r+n#1+W;njy=_rljiK^QpS4EZ=d#GxR=En}K#0FHa{BOWb$77nh(@XfK1 z*&p;V{r(%Ak6RRU*cQPu0WLva_z^RV6F*8e1aC~S;EIf@u4qXok{c0VP-apX;E}bF zd-^fY=5QbrJ|V0&70h7x!);zt0-39#+SD}sEw9)MNQpz43Bm5 z8oGmCdG;|y0*~kPgBtqez23(Zz8~Mv9iwyZEj*^+^$|x?j$Bj9R+(ky%3@!BEw%*+jSfGTCRPjM8zsu PtSY0kQTt~NG{FB0IvuT2 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_darwinmouse.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_darwinmouse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f641a427f07695f361bf27fb02a5f77f8480c2ae GIT binary patch literal 10159 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_generic.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_generic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0157cec03f86feb40cdde9a4f68901c4b8c31887 GIT binary patch literal 3836 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 T&%t`U#C4GmLp}U;+Qa_`6|`vO literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_keyboard_tests.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_keyboard_tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9992cda5b3292260e8d00d8a85b438cebdd3f036 GIT binary patch literal 86670 zcmeIb34B%8eJB1_>1qKY3r+W@dE#o+|sr?Q}_+dXj!hz-?Nl?acRg&fV{M zivT-LCzlUD-FNS~=bro9&+q)sIe#*0RK5pC|L^?qu|I#&cJ6-@uUo`x`tGlml|GC8ss_NN%fiL~6}DlIQg_d*mG1 z+vI8VHF>}2m2>5QaW2Vu#(BP6V4N4Co>5KSMxQ*IUGw3&A~{dHR%~1=kqfkIV~lHK z)@xHEQzBE@6VtROCRv`S z(4Mefn;xl%OlMEb(4H7?d19vag!NiwWM-t2JuyprVyxwfD(wmDwb_xX$ZYn+9PNp6 z{RyqK@w>@)q*^O8)ltUyjWTn!GC6t~;Jikw%X)2|vz)7p@5p?4nOq0{t;M}u&~d@F zg_c_De4Z^HdC~J8d2z&l{8^pm=HIXT`T3EBkwx;76LUNsWejTaA8$0v=x1NoPQ0Eo z{xkmS<>6Ienf!gtGKkRF7-@(_E5b^oB7CwPm*k4hXmeXrMeJ02MJ&>AtgZRE&Pa4s ze*XN5o$aS8S|TSSEfu@>RVWd{xNTlVbEDBhwAXw?{#AsOZH>sy;aH^Q%)E-$=GNwh6T}5dB-~<9D%{c>J5!tg9N;! zbUN;O&r8?+$x%BrhG67LN;@_k4sG0ha91*i&YpNY8DvCGdc#TY(f3GuCA|&r5kDur z>v8i~b7Sni|AQmx-SFPOvA^~2{VVe; z(0hgW`yQ$AtG;BQt-URh%$GYmTACYxF}Z=7q#yJ~`j)#J0ABXQ2r2A1>pAN??Tr?B zJuyvVdpu{oWw<9>;92ik|25y&wHo&UpSu()UL8p0Gct!_XF4Luyl6wXE!5C1N6;LI zO)?N`ZjDs?6hZ;D4PrvF7_AN{HMpeACoqpdEkKm&ufTEd>AKdoSlvdY`DA2K-Tr2! zy`wp{GYru@7E$WzcW$eLh@7lzX+B!laVB=Gy=`&r!bNq_=2&Dt1ocF?DH5&IIlImf z{t!u1w6^0+GQSmK!(~EQh<7fbms2ykJ?|Dw?B9N)`mI$@zu7go_kgXsve zPd=q?d3sPjHrO6b6vPGtvAZbmX)q9pAB13rB)iGNqUyQ+gpN&o0%o*~c4B8NaHN7;ldnZtz{q7&p2OHHUy z762y4M4?DRqE^i%PkttEmL#LhI6ac-0CZ{61fZBmBtNA<*HQP z_r#Di^S0k3EmRhvbOZj|4u&nF`pftRg~)K#qpZOnR-Corp0v6p+{)m#DWcPuKMn=!9!0CKGPJh zKNerm-2GuSlfGSHZ4n`DBQ07xIkJ*I8KqhWzN6Zis zQygUPSr2rP3&qe$@BI*0ull)eVQPgG43y0Z{83gCpb8o8!4QFlV_`*z{7onoh4%vF zU!Om`XtTO#^PA@q&mJ3$ox1Jue8OArd*9>P>fPvr5?H*+*Dat1wU7SarFK}EMx+d6 zugNOazFo>@JOj146n~OIW;U;SlirB1tzi_376Ej7E=_!O>MK*P_~T{sv?j5d82uVh z!Z>t&bawzveAyH69Py&d=aaqYtoUUgU_ky=IRHm6Ct^lB)n`%d-LJpo8W)Qq4MMbE#u?q=vd)N9IvC2@WtiLPu(4bajr@!4>u#Ss*U} zTqrLDTtv?Ak;U?2z$Nk$z@_q1z-96>z~%CCz!mZez?Je!z*X`pz(?dq09VVa0oTZD z03Vef1zany1zabu16(h!2izcU0IZkm0XNDU0XNB;05{8<0k_Co*p;n-Tjgzl+vM$l z+vOdAJLH{!JLSg!ACq?h?vi%{?v@`1d|ciGxJTX#xL4i>xKG{>xLa);1T&rz$fLW0H2bd27Fq62Jjg<1Q?Q^1$Ha@U;9fz%%k$z%Kb5;K$^T1D=&X0eDXC z2K>1ENx)CYp91Wbe+lrD^7DY7l0OajOY$!RJ} z0QedCbAX?fKhNNcfEVOmz|YAS0Y5K)0q{lni-5iIOMn;UF9Ci*{xaYf<(C0plKTL^ zB)HBEKaF@MfSu3c#0h%dX^pLwd3SGJC5VzFgp(O+bz!)Itt-u*3Z)S zI*zQLHG)891zA5k#(YLUJ8pz*^eY~Z`Mu3n3>uix{IBZ5WTCao$W13RMEN0f4BHhM zJ+Nd^h*_nGto1CD!G;#_L~>%N8I5|0%r5aAKp%9^A9CU@#hqJ<-uM#>Ri_+Hop*4xrofevW5U*;h(>cE4L#_Lb>_ zh2?KgopC`*NRt^?R;W_NuvDc=RS9VhyHc%6)x%PqD%B;Vh3v{4Rhly_)v8i$LV{Zh zUM^FmvSDeODosmB)7h0tsx-;C^7hPG7o;Jng7NyU27^J-9`g7Yvwz0H?8mL8P>7DR zhDU&&8NURmJZ_$gIuNEGan5ggOxcRWS-$r>!f}`-ZLRZOc>JvIle5Ty zI2SnUIc~%)&BuM7vjMYi{e5)xtWW=?N1RZ%(F$GsGkn#Eh2f0Rm$j);QZW=iy-S?| z#KXPE$^CU4^qprt8x7IY+t2&Q6)0`1lU&cm_<#2-zz&ZW^`7-SjZV)w?^!Q#t@AK@ zmBt!ullDzND{qfwB`9qhwPmc#rU2-s&bqiB5MYk9IAw$)4O^yBfiYa7*-2 zobVo-<%<5)$Em{Q0DtTGr*6+%b3Zm1jSVdP*6P<+zq#VA#XGLn5ANANc<4#B=E=k} z;lZN~!$(`yqpk60+J#{c$$vlI-rR=2K17m;JiLjlH`g^iW8+v$ zC~n>D>7V%IYAECFXuCKI3DW`&?b1Jb@C)oXBYe$K<5HqrHQ9%jq=)mARdiR1wTD=&F-nYrD2Rsg zq)%?|Dsp_zDHMrb1Rx7r$}Mc)V+m>QpN*dMZfV7EX{B0P*}o@VI=g4nyG0X*i>9kZ z(}#-|sznP2W+jSNyjwhFxVTa+uIzszQC#znxt^lQw0rUMcP4zSXY1RA#lwZ= zYGL^+hc36qr!0B>*p1WiWm^-4+jLd>eNu*8^>IZyOO<8~NweKXo=gnWdtb$gwI^iq zH*vMzqdSMOCfU>CJLiK2q3);SIO~lW0TDUSjQEwvR6;67IUdAM-3aQ^aoPKMuc>XI z3xc~k3HyKaTE*-cyzfNJ&m#!AX2%_@7j17-PS8CnpA5FNhvjH87c`_h=;;&18DSL# zXHi0cLD8ZZ+&9h!taw+sjl7P#&(rh7BA|8gq)RLM4-fd`#Y=jE-;>6^Efo$+6IE$q z-?+=8)QX)0fp6u%o_}NMAFTQIn%`X;U$6t$hNQ>bL@|ufNmOk0yhPp8jh?5gn3@ts zt;}GeND-NaOh-CY(Hy8E&EpL4UhXJ(458L`xw)}9qC}JVT$J`JosncgbJVzlPBB9) z_3N#ADLIZI%~F!dQr8SOVx48qQ&kjx1bR!$hfC+GrE~9iym>2nHbM$s+9uA1aI@E!SHod zZDU%22c^q8aK7H-c?xoT&I_Fa3wqL{crO%~*k*Rz=eFbL{9+Ac>Yw9mL>-N>945oV zOCs%o11w*!(`Yt++x!A*JM#-5W2RpK9cQ*#v)~0(2U&0yD&<kY9O0|Gs>)nt>dg_*JKc;rj;BDlJQbyF8?aOwhvQEz<8svCQ5 zY#b_FPl{lJ0H-d9aVw@D6|H8E#GAx{NS zetN$`0RpI7c1|6B1ge<>!E`YrhqIGAJq8j0^6udm)D@xJuZja$QT$(ss zwpcA&JWwAmTXCZ@A+1eut7=GEpN79B_~0KQT0AIK1G>MGfscZEIUDVBb}7_vhQDIi z;bd^%)@_^jW7q*>zRBGB-MjYh-Mv%!9E!QZ8?(|-zO7wp#h`arMDALYE%nW3euX$7 zl!61c#LHISh$N(qZVpIuYjeEpkv9$vuQ{l$!DwkXzUJtV)Zk{6pBtg2Q8x%JBOHx{ zL27qLV^tb|NE2i6VX(iDsoVE#<$KjsQ$)&Pqt@MnnLk z`}HZ*ol)lPwB_Q9}Xs)@1J$=1C#AYYs=1k;+SORsZXg8gQh_Xb!Spa zw9!u$xunP`_I}M^C#ze^diMw_kt@&b5;>N(3(Tz)S}5L^cL^vZ{E7PV!h*kr*F~oQ z2>ixxFdMXLNZRE#G#@dsqudJgv{FdkWU(pdGB+n1B}URYK&VP3ZFQ!!olF$glC;&4 zwAGQc)d{36h}u|BXBSTHkFCT#9Ud@3G>YtN75<2=X$tLbrWt0X-Ob|P#G6tv(g0(m zr9a;u3-9s4W&AARl=^(t7^_ey7-sG8B?~){dlb>eK3zs&B4b5skx;a`6~UCQS#CZQ z6#M@O%>tjXRxPW&5{;v?cf{$kn75u9k~X9fJeJa6F;DhzdGrZ5}>sg&8 z3)(UWPFA$zraa1e?Q{AZMnk$6)1s&0@ znhYqn7XAZ5Js{vW)!=GmV;^uM#PHD; zu>hWBIM3*RqE_uNor!ba3?&UEe$JPnq!Bu>bqZ=lh4HrVKGw2bROLFMjJXk>)N`&htNp-~})Qdhdh zVKPV!i&)e^WatN&qXB~+X3+Np75)YQ22ZH(kjz6dHi;sdEMSjnKXSwR$x;2JfuBU_ z18As3PZ=n4b5i7VnE4M?8F)!6_aC&FOcgIg19=|{xzhGcO zeEiCuf_KME8XhxG9W(FBzWA7hJ-L~FyTo;{4iUsHw^j}w2oE+KAKZRou#M8JyS(dt z_|xXyKz}y*cG91XzFqWZyLY$mA3UDC$9-w|`Gf3<1%Mi+3z@KZm`99t0vr_z=G6TB;x*#G94c-hLqM>1HT)2P8ZE+rH^qg%>GsnUy+Kyb}L zQM+}&ia~4gn3dlK01la0kT9^J5hzV25jhCjb+*K8BUM#y7MCND4wf=#Md#uS{4RRv zzo7xq`2aLpRW@8wrIu9nN8=?mJvlDsy+XF;M*fgg|1;u5hCV~%D8vt9-V^wzjQ3d5 zQAYpNEILToNnvPy^Aqv1wS(&q3`qyw=rH_E$|`$Me^Xb_6vRX{jd2mC`Dr;=n~{eW zVce9=N5Y4etm<;vOBoZH1$eyDo;xNg5+@W)25{Kgd1@JH!Lo%z(xNoqe=^RX&7B7Z{~T^FH?m< z6_UYo95G@!b{r?S+i{3gA?gw2wP&cu=+T(%f$`B@7_!0D5>u^=?UVk_P?(hLQKtYf zo$I8fk-@0Xtl(@f&S12a`AfVwx*5R2=P%V?%)R8lSdfs)Z7z#pp%T)fk!$1U@sg2J z(!>>TZkQ}oq#fzA=|r?+2LE2J)~!OfiCME;SsNN=Dkp=$J2{o{{4AgO(CF4F3zws?OzH{bQVSjs7=umO-s^ zf76XQ&ewvBy%a_N7VnBuTA>5Wm+CJTC8P>BdmoOMEgzE7W$6AV)HYIFXXIlVduE4T zl8x49shLJHT2G$I@8eB6Sr{=G*Z(T6DqkhAlz`Bqo96UGTG6#?X3@D&W4O7cYhGHf z#Zmf4cu%w*z$A{JbWcK>=pMbF!$!ZRsfE+}a}tHKY4mFjjegCc(XTo8qJ*n&j9*{k z|HG2t`bqWye8VGbL!r#wRoN%|uKD#j1zt)Kq#7JYlf}-&4EiyPquC|uULXX`x)=Mg z%!VYl^WFrOvuMYJILvyBMlivH@J$mX+ho%KD2y;pJ(lEJ1xQmC zzKyqP{vxKLy*TRpsNRPDjRX6Kq*bKc;dS@=UaE&3*fJ!Qr_nvnqMod9>c18k2~M5E zDP+3$Z&u#NA3X;4Q=D5+=EN3{+`AAUirl*j-9^>W3IKHDE!aU6^breohNOuf5zK7f zp8_*NKH@`!){oY>Q8Yv-DE5yc>}(p4M}nP0s3R-B$x0TREOQ!6sngg+iw&9V;^Y+W zKUqJNB_9d=Cuf;|CQM9o@X4lu$dI(!;FI1BpDS{+NdOPA(fK1;Awo9{*{CC{=&)Y9 zE->5isx$(V&(u5f54$F~H95QSFQ_6~4!{Lt^!d@fQOt@pKK7-0p-}t`zBZYwF*W~U zp&%5pFV>mA%>B*Ut^Y$`&Er;V-Y%OqH8vql$@JZZ={bfPGPCy6Q%HpeH&*XOCfNhAPeIU!0I;TM(7mrhFzVWId>z zj#00R9b~o5`N9GlelLd-uWQ1Zmd)iplA%zNIdX^!m=10-r;}fCsv4dY!_r2zWLJPi`y?nFYda$Of9V*lIFVAk-?~Efs4$H z3fzy-p4-{gj(e-ZLh8i5LWXUvlct-t90$^wi^<)Z;f?(0@qlT4jA`jJ*da$@@4PsKV|1PD zD#272_Un3mUJvS{dW@yl_De1PQDfQu{iD zAhoObPVZ^2NKUXQ2l%+b7c!nlOZ31ny&dY~1pe?9FF%g6t3I~422(10U|Um%NHOee zi;0Fi*pf`>)EuQnK@mDI^&)$u%&Hpo^&9&3yn5i31O59Fh1E2hee-8F_lD2!`21$3 z8aHEcCn?(5!8|~o%`l$Ynx{|;wU`FI)#+{0r@%X6i$p1p)7NO)aVlxY>AH4&R?kP_ zeKTkKMYHprWhPKve~&kirYsrL6S$B=x^g0PW%0xp&z(Ql_r#Sa5=D!90-6CfF;t8j^Vr!y^ZVi?B9k(Gt)SC zgW$2BnMOC2s+Pnm14C z5BmGD^N;mSf3@nBs{X}S{QYwih4U?1{d1e&9$WhIvWv_5_FY^vSjg8P+pkPR9b)Cq zG_^&y{}3aJ<-sEe(@9IAz?x2kb}-t_k+Q;qLW z6fJV8ajrBq7x>|+a6~z494b8Zn;we#CQczV-lg#iQs0*RQ^RS%E$v_qI(n66Cku`z z354S?M*vONmBl`Qa5`A$%(qMI4Rxcy$mL4c{HMK21$jiG-XUa&KG<=Xjn(VG%E&Au zDPZxAYVZ_WqSq}#kK$I>3OBE{w`uVgp?9P&NA?IY;UZK4ChXrhT)9N8Tr#ldTL)f0 zaARM*a{XJCZ8zoN%?H%Y2L=xw8a~*d9&AWNTH~ABy7~IP`Y?~Azs@2$_8{D|yi>^2 zaP`uZT&9b8mmm#SRBjbDc?NGX3tH0hgYiji38~%2zQTAd^?Ml0eI6&77>?HdWkY5f zGp34Bn?VVa;bgXjb>eP^9J9wk&$P6(J|{cr4eZO6bu@P|fvO^Z@rQ=yKK7B*1k;UUfi z3+Yx4fg}NE$dJcl4HE0k5XEC%h1TeN%fj`12}*U+k{huhwon60uA6jeYk$L)Me&l_ z!Q#5>Gu7gy*P|H8al4Vf&_mYbBAq8w>LHS$6naRo^a@C)4K}#>YrRfI(mwKV)iSke z*}!w(I{Es^8_{@G{aaOSw*tdk52;%Z4IVx+d^n;WjwG5|<6E8DC*OQYCjG;MQf7Hk zP|Cc!jv8pyHMDGRygWNyL!8fa%`f95b83Zd*0Na8fZ|k^fx+zO*rWfQ%+)gBZ1xW= zmN%sA zEnCWLBob0Q6W*e0?Sz#q`(lb(IHj-o>eNKx3d+A&N%Sy(kUOe|h3^|F?qc zJ@)Ji!<1lSqzCAH%9ur?i(KYlqRu3&D^-BDIgS)zLL*$6vI}P92*!-yq1|Uf&Dp=t z5|+esgek`nE732+#^`5Q<1)uInfLjn#x7g7KwYW+4)gCw0-_Jz7KFaA766%ao7j3pM|JeRWyl9@Kv&B;LUA-)ui^+!^QkJnf zAXqFL&$`Mo50A z6e=QxN-_tu9jc0?3&#lCVNn<<+96g|lBue!Njf7^lX)iYETandr>ruzGKI>ue23YZ z`~3>2x%_l$ZYSt7GBuYX^2A1EwQdhaGg)kY9x7K@$ACD&7Ge@C3TJ2uz2D)`eg{co zPzID;`%yq?;>&9q2K(3aEdO)s1 zPf+_vi&Fb^jpoan!$tv2oi-pRiXO3OwU_oKq%x5rvMIK-V+DFin|d1J=+E z+q2i_zH#Vg^wx&>qTPcFA5TboT=fWbpD~_$0a(Z!K9arq2(OLLM-V_V`|ac!nR>|X zDDhD)@}g{}p4ft!`fi+jBqB^o4RNI_Cd&d!f|YU6E8=NU4f8{t1_{C4BbhWPyLZ_Ph-D>l44r0xz4J{ul>wncrmCDC>=zWY?S)-m9D zNXbI$D=l7x;Xu%IlA~r{K?^ZWiP5Yw>$BG8cFlG7TvC;l=|f1ZK*ks!Pf?{QeGT!M zrxMa>T@3i(8s?Qy^1Z&zg^lz^PoWo8Wez$~=PsKpBw^UedmmvZroC(}CI$M?VoxhG zAl$8hbw)Zy_~-GbD|>$X$*WJ^SPxdxxI|O8q-6Eb6YF0xZ`1HB#i1v@{+EsHdMiZh ze+dgVQR8SF!p0lw%r&P`*rd181^Slz?7 z-Dp#fwk0}F#`hSCO3OtZZGV$fRqeqmSVUG+P-ArkWocbkg-}W?C1^~6O>EGW5pB5B z?~l)NDI;Oz+vq9mLOq$4kj@<`*EXQ&7CX$I0JDnp9(I^k7CxNF${OJW(~?@#0TDIN zSi*dVW$4HVVCXHeZyl7PHL1QQ#dY(|kRE;f(~N~nJX0i(X%*r=3r{$@z6G6p2!u+( zm8FcjWG;ISS%J)xt>8l^qZ!*6HFiyQbBuAbjhLkkRY5t?S|pX~n96>vMN-|9t7|4L zDa4Y3Vb@hor;Hguwu9-xgfz=h3#FC}Nz>i2b;I^uM`N;QyOcvMDac_mp-Gq&gcdOs z0;=NfoaxN*F%B(5dJoW>lA@+Vq7jZyOEG8@!cIWVO`YwXQPH#%K{4X(=xR<(eT$hs zB%e=n5Fr&Q2gVFZOWdR}EKYWd9GR<>j94e+qwVal`^_fN*mXm0>6b}Hi)53ncO2#_ zDkEkYd#h40maUZ8DumyDfTkcXjOEJaDUsH2hh5NVo^yjG+C?#_B&6LaihMUF?KyZ9 zd!pNfod>*)qWV&Yf~h;sGG~Zeo|mQei||53>#zTAd@;H5`7~9 z9Tvx^*{qA}cc$8j7i@aq(0%9ulU`}{fS}mNiLx6wWlcTM?|0G4lIbTH2^~8mEp=1R z&<5H02PX9%nl`Y>zex$E8w|;3zl^d_(!B+AoO~R&5V?K~D%wcGd z%Xmp_j7v;BYh<7FQ6# zv6tv0RL-@bGS-i^-K!m_L?C&`Wq&4F=UVoIWxaGLHEo~ULo=D3dCy7TdL7-ozoeMx zW|Gd-t7+;|Bc89lr=eBf8dJ3Po}nt>_q(*9qpI5sHHX6>ebS^>wdL# zar(aVHyC4!{R49|*OAydhX|nI&I76F@=<(9w|tBOrVub^!z754^?5LZ zqnCRZnhF;MGX%wcjVQ4kpJb|GS{X;DO4OlS>{P)lqcqkJM%}JtoQT73-P6O=Wb!)M zArl<4g+|5~Klyl9;1-*DF3g+7OM4k)AzyR6aE%6Ndy z*s?k(M_R%NKjLT8jj5mh(ViQhUkfj^7PawCh$)ID(G3Aij^fiewkQ$uM)mk)UP~B5 zY_aCnh_y4KbmAqVK(;1~w5SrgCclAFQ3`y(qLfa2dE3QpU)+Hulnt?5a-|bJ)D$|A z_jUO;%a@kCy7HBkzw*eHGIjEzflXN9$ITp+zsI^4U%|;kvp@zTn1V8?wWQZ2Or};@d1!)0Hg*sAs9!d5h*Gf19UQJ7ttF55TeB+1A|9E=NMx zS-YjVp*bd+S1vAjjp(!kFEK5Dtbd8k@;`m;*v*-@>J#H0PwWjPPDF2eJnMY*Y&B}% zW4`x2o_$`nHubpFOH-33V+48$Cm$YxTsirLcs)Dp@(I%9?&_ol{?Tii4P(^#2Xg2B z=ru+kC{j~>G6&2gjUh>{sIZ7gSO>1 zL{YhK63zJb8LZDoo5d%j8Jfo9^KPxFg|sT`0<~;Gylm0+`ZxTqW972dZo=iD@l24q zagu!}Fmt-Oj_#4H$H&p`Oz>8I8DH)a1RbGPtn$SW=ZRP?y=&Go5ao82S<}#2`G?1Z%hWJ33=LNQd?J zNr_Y(9Q=;YL`9o$Vf>!kRh<_)c9t`cjU0Cwsw)5LwI`(q= z#rFQD8-c|5HA97uGI?hS^}y73@=aSK%q57V*8o9N45sXU#!KATyoCZJ7d*F zT6;s!bw)ZP$>1LLCojfoARTxSFULYp;Ye$H8&-EA4avPjT0DVi$YemKWqS!8#cGdO znW!V&!1pju`tkOwK{k%1yhsnQ>bzJq3N48eD_7uH$5B(jq7NJiT@&4L2Y%;w2^*in zla%OCJn`kCi$%l5v((~Q@#5J%!S{XMytO}&D&Hv_(>FU&IHSjlHE(*n7o@kPJPJ`> z$osxyMHpIWJ@C^0i+PvksKqlbZ@gCe+O~vL3w5g{SdV+P?3J=Bi~Gv3==Jr|>+&%kV!^kKZY^u5g>E!3lX*0Q)uyQ;k+LqI0pTG>&vBqz5zsH$pS6kut$Ip+h#mvN zu3T{Sleog;#>^LS+AkggqLN69W1WL8K?ult{}vIX3bk?{11mnf)NpC$#iqXJ%#?LK zMwxz5&HsW*vNuhcBEzQhZI4qp(2LeP51`lZE6iG$wzG}mr0GFlMzwkmnikUHF5s`z znMr_r`spM9pMu5^3~7rV6HP%g@BRs@FgJW+!+ALuim11giVj(h|p-AT>} z@0$^-Exf@*(qxcxXpO#%77gzvb0Q}rZLz4fl9o2qW8oMsu;p&u$vB4H{U4|&+Kksi zTrK_UG3A#I^+&I)$6kkH7GFQ|CX(E4?HPRhKz!-J!IDEgIT}m#Hui=264J(i52CyJ zn(32NX;L=bZiB)80`0K+PIieh*@(#=nR9lqU-}R3g%}YpcF$lN_RElE_j7D?+VGQ% zDm|9j5C)SRH#{A)oS9#uI|jtgj?TM(SC>D$zJhPKQlMM{0hC`QY8H~oM1PJO%pap# zK9>7cx|xfcY<0yGxSkBqZZh0fm%yfmVrP&Nf*~jcHaegpD)fdU4UNB6I!A{C=;R0V3Vt~$A(BXAD z`v!oGFZgntZdx16DB7boP4Rc=1>|}|r&zcnJ^kx%F2z=a@0Lut1YVhOc?sAl{R10s zVnYDI{)7g*yonZM%Pyt?Vnj@*KimWsm>jdWW$KROV;Eo9fQZe68e{ziO=INqk!6$4 zECf$FLZR?Zb`sPEP$LS46AiVx)1>Y38&?)LpiCc+(2TH(&L9wXokKH0%dZp0czlO2Qw|B|>u zPbw5zhbO@hZ+wd9#Zs6j1hNY5*qZ`I#ilYUd!$AOEKT?g`I*&!av zfqq5%>9BSUFbtN!C9Km&2AG@PBKmr5;}hBh&gH!GsI8-vZf*rD?}|(QfY3>k3)vtT z?}k#8Z=qVYaA5Jkta#aq8#9L_-s`tb${-hsdG2JY?++hMz{1x|j97eaW_#d{GB1~$ zCgmalTAEdPgMhOu!#8elexsh5A>7$EW#JzZPNw300-U_HXluM|+pR~3q$6%;;vt|! z^Xbq6I1?B=Ne8qBOuKTc9wAH)ALdsNK7 zBB^AD+h^15GaITX(94;BV}?V1-0<1VyL!~dZr!o(;ysBoV9il&7djTiZctdjE{O_w zDxzWk6^g{WtlV@Kws!HF(%#BvL_?|t3ty!xf0qcb1n*~xodxv*FCE}hh%fuq;+cAy z18vBmI|lKx#REr%q;+nx7^vm-3f5Nqfa{TnvI2DN~{4tjPiuJUs^!pJ(^>xe4e-m|2=%fiH*C6IMDKp zYsl%JsSXVrS<1#k7pit(l@&y1s%%r?TzbP+Np-^LWF%Lw% zOcyA{QF(;`jRPrPAwaozju9oN0J1nalfqZ2a6f=^?1-nkTRusY?rypLQ>x<>|3L95 zQf=B%BYG>Vk-QuJaz_8b{~=_H1uc!IWI3~6AJaDd*B(sgLszjrCMu8D&{`~(of zaX|XY9GCFZDt+eou3y=Lq+VwFdDyZR8YMJDqZx3PG= zSR@5I-k6WLBr*uI=^6wc9$&4FuO3*E7{6kuaAh_!d3Dr%h$AzF>E(})L743qjar#^ z{q!*%AVtbC+*Ko%K7a3CYgSC3ZP<3~z@FE~3wO9Q#Ez!9{zB|Bi(Pu7_kjwU@-}E> zGkg-`DVjhpw0bq}fiV36mw=Us1#GrDe)d3VV*Ik9LcSMmCZorqBS|z=Xs1RoXHjoN z*QC@9ETZ76#1lWspJzV(ALAt5CJI=eG0@^|#rUm}x)jv4BvO}hkh(3Wjg0m*=+T38dhiog&LafFK zSqMv#A>DHvW?R`dK}HF-)AD}sD2=`(1E<2xF}C-S*=w+RWrFSQ=?N^6+SuHN`8qBp zokC1OhKv+vVJWR{e_{9AQ>OQ9{M@e8>L0zEQew#Tp4Skny&7=j>L{<_!6>=1&mvKW z=jre{ZMKGr=Cs)gOs0mDBTNou*;MRGGMaWJneh+U!D&|NWF3c_Wh{9(^_8i}G)~ji z*^6d>G_^T2tbk*!>3Hb}kgVJf*J&JZ>Nw1FJ%^hmaH!B4L2{lfUCYy@MgPl!osKRJ zjl40piuzOc>sE=^RkS)=)?GqQd!tY=j=j`^yUbpP=86SOS4{b9Vt&?j5LyYr`lpO{ zv8hmVODNjeK>2zuQLHA8o{R4$jyAILS}(TtZ~BdGuWcJ>=-(EvTy=AQV*K{E#_zo) z4;AhcODHoKG#|tKhU(GTcxkNv$7X7j(bMEl@#G@5m3zvr5}zmO{zB0_Nq4E)^w~55 zP8vvo^U8^<;r3ci~6O5T;3eR=VTwL?;!Ti^}z zG=L_NdD6FmILBt_w0K&*7K7x>rNy`K0|rTuI$$b!Gl@Wyl4KQLaI+DN(rZV`fDx9m ziBoQhh{1k5nb`)>u!NbJ%4{LIUyj542-qflUv9R=iDspkcq9X~leySR3D(ZC@C7~R z5{@OrB@}Hj?Nr~)D**%!X!jK)uzqfbSQtnSV6M_zD#qzQMD5D=QQTpjv^jueM!5j9 zE!wBM9WBQ?#;>`QGLN|*VJq!}dOnwE?G|Tn`jHYb8SW5M;fN7RE%(tZEYrikTbId1D2ytE8+(-_~dRz*lplt8< zXe`nJrOLNZ3t^PG{glZ*`qF-Di5MhD-JWX`zFziL^{N56n=k*U>33~ywS4mhrUFbB z85?JYcn91$GC7yI;pVex8rQY_KELWw`i42|8`wM!wv2PVIvq9vX)NY+j?m?O>bN<= zHFJ!Cs;{7$7d$W6+)|xLpUF5^v4_?+McU-^(s?gt8qofff1*}6&kF7A|u{T z`jPF<{8yeI*{!+Sj5l}P2NjhjYy~Z5(0U@Sw*K#xCBMDq>Y5uRH|pax>)xt);>|68 zv<-i-I-t(7Xff^U8l~-jFb6Z4(|+`L1Y-}>Nl@W+H?3=vJb` ze4s<411-36>GbflMe4Lg1B>6ty;Yf*wmTs`Zjxl*kW`k2BvoLsOpN}4lcZ3mFKKR* zK=yPulUyLNpo>aQKR-nC$wax1mI!@-`kr#og#65WCqgoqn=S!c+`zMZ8WwBQm&5u$ zB&-fzF-K}opnipBx+cdoHn(6hI?|(!Oe3X^?mBo%p_tDDu*wc%m1C$_#40P^ICv|T zn6^J5J)yG-A0FC#dGRaT6Vhy4H50pP)Uul4vPadjN8jkWRimz@?bOt@hX;>5sjhuW zEqi(}^z4unc5|8GAN+T;B@>sWQm0v@EaM~jA?p2zLUbbj(XF|zO7y=e)w!W&ESzU} zBYKNG9w9dh_&4qQDT?7ZEN?A!+``XhiwA_6nqIy3lwV_vaarnph+k7^AI}z<$81|* zXbbbJv!SP>1%hCc<;yc*6xsk?)gPe&TpQ@aR;Ktqw@KWdsT1l@`Evf83d_DJOWujyYOMazr$0h%zt;6NDYI*H&`C7Gn?Qr>K zwS05Dd~19nrX;d1gQL`XwS4_>`BoK0%D2ZS?np>GnPMULf$EyCme0SUB&0>}NTX>E zWFdP^JuTz5NUc~jT(L>5*fdnhvAJs5+$$S|VVYkkD$xEHiV8^ZIMl??y`n-)?Or~cMo|-Nq-@5cQ}ociB8ixo z4%3fjUbSI0S#$)xDjm!l5cneI5Rb(s3T6w5<{XN$WpwXD_o?*15Bz@00dpMLyx$?@ zf*~f$cb7X}fS+l-s|Ug7!}*>EX@S7=xetsAG841MC{hSVLr3VTd8Sjv0_#5p{`piR z1mipkIa*2{iZe$`$)U4c0_0dJ5&`n2_$(Qh#;a!i_KbQf(k6E;bBC(3c`l3=ME?~n zu)0=uZAZy@xt9VL3ojj1iz~J52^^kO8h^{;1*LSCc*N$TCIwhO?`{c6FKy_u}E zpk>qxM52Sja5M--bB44)KHm#N*s*7vn8af&DC+FLCl_ZG6FSu#J7z`#y4Jb5EK_L6 zUc(9Ew;D7`>-Muq-L7j}ZpcGYJ$cwX74#I+K%=yv2-f6Hx4XidsOe`-opezld(_{g zD6?`Fsw$=Ufss2iq-{p@Sd@kllW7!2QAaQ)x#K>F8KR**jPhX{9GX01P`T^SgAzGa z&22<{8c)bf{8MUi)n#zN+-qB|Z@Ierjm_%34R0=1=WQO6wzwlXhO}P!+3|xBjd0Ms z5KUr-nC9B@b`C3I(wvq$aLMlGhd^$m{dMho*px=4&k>QA;EOX8Ifls?mk(Y$@Y*xi zH>$H%3`sl**ET29Aniv`)D1PxRDg}psn$(_^T0%1TdFrb*_o)*h?a{1*53~Un4(U! zzmFk3yDGP+4%A0$k7Oy^jO_Jl@$738u8+Su^^Jg9z50!iT8(K@kEN0Ae*sT@By@c- zmuG~(abj+<&3QkLrpAU7iw<|VX3`{()HK_lhjrn(KVBwmwPGaqwnV# z63t}Q$V5wL4kJ{am_$fN>hJvm0pw4x1lHHE0m07jkmUZKqOho^MAiD(;u9IK1Q zh=#12A?d)wq1#{K1tYW950P$$oC++g;kKoVLE2?FjXO6B$h?}#onz9>Y_V|F!upX* zGbI5=lqgnI(QWeM52(OhHU1K@$w8^0 zylW=CLNh!wo#1M#1a}GMDWwRSX-}Ld8dN%HP>*!B>9#Og;HCBC?2Q4G(ZOtN0YA4wGeatsHnouj8BD*A$Juhr`;}TCLEBX0tF)Yx_IIvxU=`0pvrF!fFQOp_i*nD}*!2X*Xv4D(d zss>**c`bGmNJGIt#aE8dhT8IzGYN=wic^MZgLZ0*#LiHnrf+Pgdj@JN6G#NbJ~5-O zNpoRTY<3zV8+)n{jhCdglolFWpXwzNZvZ{4PLoMu-De8)9!*GPVuH(;mRxKWZtrJ^ z?5&?qf*TvJoQX&*RJyL|2NsHH^Uc`yIYjF8(+^TV_$8vYGgLh? zYG+W+*`&7GlMe6K_L0A16Le#Wm1w;mhgug2x?v0~f^O?5nOu-U0U4#u8tjg`Sp!RL z?aHO>ka-nhi*exU!etmtUSdkZ)EPov;v=kL4Ik}nY-~Plu##YeHJj(YLY#ESp*OZ& zK6N8-Gd9E$&a@?pu!w%&qJ%UxjqWhlj@B047n=_wX8uxE+T=mzOfjmN)FeH|4tCw( z6Z&PNC_FGS^$ol*hrkn`4m%YmR->nDUP;=`SiF{Ge1jK^>aaFu4^5%MR4S&+tbI2l zUD+&ccF#>mlJS+{Xs}Lve`PHAtm{|AF*rq{fI0AcRU>LmR+)y z3eDnWT|=j^D(mRZdH|jttIcj)5X08mA&b#SAv?xpn00|reXCTR>B%O3ln1tL5G&eBa-$T7rZ z9ZqzM$Tx`lbn~|9TiagWc0>N=?ryQfVCNVXKFY$pv4l;w`iD!vHl!D@Y`$Yenj)JD z2M7%`exBYC_U($#tG^W)lJ@Jqp=kya(#(+y)0=pu)khb3iuT^?2NbI}`WU9S$h^Wd z@qKGgMEMc4LW-EvVccR%!X*9JC4lexH^jlqj3J%-nI@e#!z2w&xy&Zdb-)j@DjeTwMwSBKm8O!5C4!aPe)V6hc8mN_UwKVMGUhS!GnR_srGIwVJ9 zU4rGbQ=X_b^3JqjgZx!8Qa_Ry=fIpOCca! znn;f$@zRJkv04nTfc<(XwYZr@b1Fs5!jvN87&GZZD6Z4f@eX#dj77wYkDE5p6mJY? zqWpg*&UqmV(KR^-Nm=u+ow|PV>c^3jRkz{I$&(}`yy zYF#AJ*s9jGCfZ_ZT`bXgMy)&ZzQ^-1?|R=)Je~#XX;=CUzHRKsHns=EcEKJHhE8}E zt;~iUUBSY%4u^H91M_9{!G6*R`>VYQEx}hE;QaxUbV=NGIT4j^;%Lb>n8eQQ8R)Yx zgJ`=SxkV(Jfj3&UE1ZiPaN*YJ`V~w04M`KzxE04f5bT+PX=C`qgf+fum_<8|NGIxe zFc6nXCpsValWfoycu5|TCZ|E$E`~Nlm!J!shq-u`c&{tHGj8?O5GD5SdXL5|s=f42 zc?QkAYTfs$tRsv>EzN}u;q#9+w}oTq3`AWV$MY0YmJdZ6!fmKQj)?LUvUu!&5DICx z2FIpHkEmsj+}IE=TYGbI`Xu~^k3HqTqd7_l4Rc{*7L&g;pT*Y1>ssU%z)a7m>F`ib z`~J-Ru<<}%_>UMDUG-J_SZNh#4(n-!W2JJI#X$nj-794EvPvx^uAo7-$2 z-1_8@^wftfe_e%qfQEHo!Vp6rR<#Qd#t4NnF;gK$gd5*6Umx+H2d_+ZS#AW~V zP&#z(ikIyee5`RuYWlFz$@8#&Hzks|VNCs*EU!Xj7&AOFoDLnE<7M@On+~SmkL}^> zCz4BAO&)R>!5`&~lvtUcK@NGgiQYBnS~U_ev_Jb!Iy~*fZhnJ1#B4*^9IONU6`Z8p zV~R?!Lu3WBwUN55%(^_ji4L~bAiT*G@|np((oWAI0wc4K#$(?j)bjjScw*)vV`L%U z*gCxW8FlqDgP}-#bz{7&Dbf7gPccgF-ANuV{kiS&Jm%ZyyGy_JGY9wyfdfo^6-I?m z;Upy$G<=v_EiDCZVutH`-01P3674Vtnz6_?`)76HW_lK4wD}Yk06&bH2+ybehdrmf z%GdBXT;gBFALXkASg`zAG{9w&dA>|)F=lg$Bdr~=Golp$@Y?8Nv;r1pRLStD zsp_bym%8Gk=KjRv&0CCR`-cl_)xuh=%T&1Nr+!@eDP3nb?lMnrbNA%7X&)T#JJYQ9CwOY3N#(uSI!_5r|X^UB4?4?7)Q|iY}xouo%^mspxc4Y4H-Y*xX8UnFWm1dy*K3buzA0eK8 zZuaX$*-Q!zJB!R$wj}u>k)$dUNqF*-FhAPBCpTl3q$7=gQMYk?D8o=j5|S0ye4Q9^ zhT@OWKFc~WEI1@WcG9(iu0T=@pJIjEr$|o}{mK7DBw2tqS*2v>wb?f|Vh>ndO3YPY zF7H>1tFIyZ@R2mG=>=5xp)tD=@v{qojU1i$$aGUYghLswL?!|L*&_K_WR=_X8$I=R zg!j1)yt}j$6NM!h;8-bK!PpRo4;AC~c&=fgHzs@NE%UC~3D88;9%Sz-Mq&UL1Y7Xh>S%76ilh`22_kVT3aw4d(B{ zo9qH$j(AuJQ>_sOS=As+70E>!OOTo-i&&Q@JzDiNC)&>y`P5xmWarxD#8JUrqK##d zX=czFZ3g$!48swV=h+X`H8caN0^%5iGs#4yOj5y_6fKvAGW-y(iYZtMPv}gFY96Q8 zY;h(H3C+Ig{c=Elj1r^nu;2RA_Z;ms{yt;a{Mv4R)ecP|~mP zpW*3$Bu+dDq*#rnSb39{2wV=S6-yG*Qqzr`I9&FD_?dr!Mtx|eH-#Z!>~63Q`(?6w zit$-i$}lDF8ce~!LORTxi@hr&bw}AwZ1Oiiha$A@uB1suay~Ion0}KXX)@E}|C?B5 zV+NMtnI(GmP5`U!U2eEG^R=dH4X>TJKJ&Hq>#|z4D!uRZp)!C$Rz|RNq%}%9jFfRb zQw=r-_!y9x&TcWM`m50HE>zeZFM`jY->MeR zyCz>>a<%!5z}2=l_N%q)-<+e?ZcpE@WK%b=ON>QnihXo-cZ4m`i>m7UG(W3!0=q_oxe=;_}>kWTyC-Wk)GW*enG?O!uCB%QW zm+&Ml(_%7Z$5`J;XvLW1UizFDKs!EPgK$!zPuQ4hxN^3N_11R@c7t`bLNDw?&Cw(L zpNOQ=Y%PP^^aJQcUJG}67 zCk!U@!sjzWdcdJ}WDsqEKc?46abs*BWq5Xajo4DeB0M9B7-I#62D26(%zlW%#aOg! zy*QR(=gzkFkiLcvb*IfdagwnDu%XgJ?7j%CRcKiSHh)z45;(*?<>|9@zk^CT} z$>1i6YV(aS*>r!K^i-vg9!LAS7T?E5<&iX-D?%9?ooJn!@N{XvjvYYp!X=wM*z&frL_zkV&XQjHMI+VCOX*<+nwpocWK6alHJ!R~MmHzLn4A%SX5=|sv65WE6k@O=?zcBlly!i~qoP4{O znntn)8-rw2WlJINK}(|K=V=?u@eFghv!kWCf!4IMyF;Q3^HgQah(0q=v(}5}PRTX+ z9*fvSQvLUkv?xuCkJb?S**F~*OdH)Oe2sP>RgJKQgXt`iCdXlhp3+SiF!kckOb>pP zos|>=FLtefjBjk*XV-vJ1saev9Mgc+LN%8x5$ZZP{!GSZsnV?eNJ5(D(tAcX;6ZiW%&{BR`oFU_STEUioiTV)@gYm_2)&nd zVU=_dGpqEIkM1~9bPR&ma&*0+|J8B=8mtw7+z+!?%^m-B+4#uX;w-|x^=!9HA@e&~ z*cy&C977+KmUS_^*UD$eC2)HKJp0tm>Gn5^vQINTGmE4o4Af=o5$qq5Hn=5&CGby{g{zpT X_e zv!7D3JR2GpWcsIlU>*qw<;r9!Aj0?&iAO@JeBf^H=&>8-`oA+bxM6XwvIK3a{z_5` zh1$Zckx(d^AEH#?&K5c^427P<_K5tBvJXX-X9%#6LMNS(>!f^w08P+Q&J*}NfiDtx znZQ>Fyh`9Qf!`o-mB7~t{6_-cB=9W)-zM+}1inMy|0nQW0)qtJA}~zgdj$TRz+V#h zYXW~u;O_|hJ%Kv}{)xan0{=qb-w42O^eBD;IRpv_6cLz2ppw8G0`mzhAh49cDgx^W z)DzfBU4k-CV}q|_|F9XD}g^I@ZSii1cnHFkHG&V@B;#WOW^MayieeN z6ZlsG9ukZ~0>uQz5Ew^b0)a9DlL^ow&dM|bGYQNkFpoeTfrSJX6Ie=MIe}FKHV~j4 zt`*u|S=m8g7lFqK>?805frA8&5O|6}m_P%8MgqqO94F91fVN^$ItWlQmvV~083Jbs ze4Icxflm>5p1|h_e1X812)s<-R|vdH;A;fd5Wlcc+X6bX;H4`B{XrSmeZlSQ3WxLQW{n2C z!QI|F0bj80PL5YARnN*k!Qfs7cK~{W2T?F5__*)RXm1eL@z6$g{SbqT>B1tabpe5e z1n|=jfcLW|uB4xHsDV@HZkYil8fWa<6ncU+aLye`3eLP!S{$srGou8cQhRJQe*)!D z=_uSN9}O_o7o1Kv^t-{}j5~$?;LO1ZUsL58`K`k0Wovo%|fUU~~Wg-^qwOgC1t2ucb3q`*wymM$U3V0$z{r&?z=bcknBKaRVR0T+$B0=)XN;!+^xNzXN=mFnxnO`|2B?l42|vf+#@*4l z#wCk{itJBoxVbG9QfMVAZk3iKb3-Ayy@4C0#?Dx$0;8lr>QKJ3tvN;!Y92wO&`Po> zg#3r2?O}{mMNUTAVhVMHc%Y1C3Ghw7S@7%$`niI@BLFaS?NQ@d*+0pk916F@lEF^)CkNN@Q~50_{%tCmD~F;T z;f6>u7f;ZM!urQ7zC#kpeQcDI1(+<^kPg>2b{-eqbl)f3?IqkV4&3VNRFozc_ObNIF&zi;Pw zf>O`Io})dpd&+L-(iO>iC6BJ;Tdx$*l|p{yR8MnHZQr6krEkt)-pt#h=+6vu9hOW%BUYSo0b-r+UUEJd@s;w#58Z{`T~m;pxlO>C4S)Q{S1|Z2p@3 zPKD*yl%M!KRhxX~?HNCjJkprnIeqo<+={`R>D~T!a!Y!v`ew#+rw-;!>-N8$o8Pne zlc%}^bp0U~%P;Lc)c3J?e$8OsyzZQL@bf_5lkxoO!MwTMIdA6|_l`e5zdQGxf^oga z`U~R)^9S>5`On6_mUuzUVE(-B+_wwH^e#WYwp)59Z*1?@zDPW;a!{Jp9i*R|`!>b% zW(-O*yMu4%jqd3@KN)W+p47LZ|H*jq!q->bXuNqMzIg9o(Z24&cZ$mT=JfA~7cF>w z?u`RCpNucsGdOy0cL9HUZoFX5V1Bj!_NI72)nNW?{45;bd%Ax@ys-M}s)5EEP4Sw| zg9TfdjgY~-u%Cib#12r literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_mouse_event.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_mouse_event.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a017d268cf47a5b6438a77682cf28a317d6c6de GIT binary patch literal 702 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixcommon.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixcommon.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bbaf07d6cf4e1dc5bc4f84c4e810b906da6cab76 GIT binary patch literal 9110 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 EAIbs5`v3p{ literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixkeyboard.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixkeyboard.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..add07b099a1c6ca7e5e2d202d5cf6db15b6d5583 GIT binary patch literal 8005 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 D-$~Lt literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixmouse.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_nixmouse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b67e02eb2abeff34d9ff3ce307ccb89195c65abf GIT binary patch literal 5546 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_winmouse.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/keyboard/__pycache__/_winmouse.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d29bbfded118afe294f8e144da0f5732873b460 GIT binary patch literal 7782 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_canonical_names.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_canonical_names.py new file mode 100644 index 0000000..003fd3b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_canonical_names.py @@ -0,0 +1,1246 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +try: + basestring +except NameError: + basestring = str + +import platform + +# Defaults to Windows canonical names (platform-specific overrides below) +canonical_names = { + 'escape': 'esc', + 'return': 'enter', + 'del': 'delete', + 'control': 'ctrl', + + 'left arrow': 'left', + 'up arrow': 'up', + 'down arrow': 'down', + 'right arrow': 'right', + + ' ': 'space', # Prefer to spell out keys that would be hard to read. + '\x1b': 'esc', + '\x08': 'backspace', + '\n': 'enter', + '\t': 'tab', + '\r': 'enter', + + 'scrlk': 'scroll lock', + 'prtscn': 'print screen', + 'prnt scrn': 'print screen', + 'snapshot': 'print screen', + 'ins': 'insert', + 'pause break': 'pause', + 'ctrll lock': 'caps lock', + 'capslock': 'caps lock', + 'number lock': 'num lock', + 'numlock': 'num lock', + 'space bar': 'space', + 'spacebar': 'space', + 'linefeed': 'enter', + 'win': 'windows', + + # Mac keys + 'command': 'windows', + 'cmd': 'windows', + 'control': 'ctrl', + 'option': 'alt', + + 'app': 'menu', + 'apps': 'menu', + 'application': 'menu', + 'applications': 'menu', + + 'pagedown': 'page down', + 'pageup': 'page up', + 'pgdown': 'page down', + 'pgup': 'page up', + + 'play/pause': 'play/pause media', + + 'num multiply': '*', + 'num divide': '/', + 'num add': '+', + 'num plus': '+', + 'num minus': '-', + 'num sub': '-', + 'num enter': 'enter', + 'num 0': '0', + 'num 1': '1', + 'num 2': '2', + 'num 3': '3', + 'num 4': '4', + 'num 5': '5', + 'num 6': '6', + 'num 7': '7', + 'num 8': '8', + 'num 9': '9', + + 'left win': 'left windows', + 'right win': 'right windows', + 'left control': 'left ctrl', + 'right control': 'right ctrl', + 'left menu': 'left alt', # Windows... + 'altgr': 'alt gr', + + # https://www.x.org/releases/X11R7.6/doc/libX11/Compose/en_US.UTF-8.html + # https://svn.apache.org/repos/asf/xmlgraphics/commons/tags/commons-1_0/src/java/org/apache/xmlgraphics/fonts/Glyphs.java + # Note this list has plenty of uppercase letters that are not being used + # at the moment, as normalization forces names to be lowercase. + "Aacute": "Á", + "aacute": "á", + "Aacutesmall": "", + "abovedot": "˙", + "Abreve": "Ă", + "abreve": "ă", + "Abreveacute": "Ắ", + "abreveacute": "ắ", + "Abrevebelowdot": "Ặ", + "abrevebelowdot": "ặ", + "Abrevegrave": "Ằ", + "abrevegrave": "ằ", + "Abrevehook": "Ẳ", + "abrevehook": "ẳ", + "Abrevetilde": "Ẵ", + "abrevetilde": "ẵ", + "Acircumflex": "Â", + "acircumflex": "â", + "Acircumflexacute": "Ấ", + "acircumflexacute": "ấ", + "Acircumflexbelowdot": "Ậ", + "acircumflexbelowdot": "ậ", + "Acircumflexgrave": "Ầ", + "acircumflexgrave": "ầ", + "Acircumflexhook": "Ẩ", + "acircumflexhook": "ẩ", + "Acircumflexsmall": "", + "Acircumflextilde": "Ẫ", + "acircumflextilde": "ẫ", + "acute": "´", + "Acute": "", + "acutecomb": "́", + "Acutesmall": "", + "add": "+", + "Adiaeresis": "Ä", + "adiaeresis": "ä", + "Adieresis": "Ä", + "adieresis": "ä", + "Adieresissmall": "", + "ae": "æ", + "AE": "Æ", + "AEacute": "Ǽ", + "aeacute": "ǽ", + "AEsmall": "", + "afii00208": "―", + "afii10017": "А", + "afii10018": "Б", + "afii10019": "В", + "afii10020": "Г", + "afii10021": "Д", + "afii10022": "Е", + "afii10023": "Ё", + "afii10024": "Ж", + "afii10025": "З", + "afii10026": "И", + "afii10027": "Й", + "afii10028": "К", + "afii10029": "Л", + "afii10030": "М", + "afii10031": "Н", + "afii10032": "О", + "afii10033": "П", + "afii10034": "Р", + "afii10035": "С", + "afii10036": "Т", + "afii10037": "У", + "afii10038": "Ф", + "afii10039": "Х", + "afii10040": "Ц", + "afii10041": "Ч", + "afii10042": "Ш", + "afii10043": "Щ", + "afii10044": "Ъ", + "afii10045": "Ы", + "afii10046": "Ь", + "afii10047": "Э", + "afii10048": "Ю", + "afii10049": "Я", + "afii10050": "Ґ", + "afii10051": "Ђ", + "afii10052": "Ѓ", + "afii10053": "Є", + "afii10054": "Ѕ", + "afii10055": "І", + "afii10056": "Ї", + "afii10057": "Ј", + "afii10058": "Љ", + "afii10059": "Њ", + "afii10060": "Ћ", + "afii10061": "Ќ", + "afii10062": "Ў", + "afii10063": "", + "afii10064": "", + "afii10065": "а", + "afii10066": "б", + "afii10067": "в", + "afii10068": "г", + "afii10069": "д", + "afii10070": "е", + "afii10071": "ё", + "afii10072": "ж", + "afii10073": "з", + "afii10074": "и", + "afii10075": "й", + "afii10076": "к", + "afii10077": "л", + "afii10078": "м", + "afii10079": "н", + "afii10080": "о", + "afii10081": "п", + "afii10082": "р", + "afii10083": "с", + "afii10084": "т", + "afii10085": "у", + "afii10086": "ф", + "afii10087": "х", + "afii10088": "ц", + "afii10089": "ч", + "afii10090": "ш", + "afii10091": "щ", + "afii10092": "ъ", + "afii10093": "ы", + "afii10094": "ь", + "afii10095": "э", + "afii10096": "ю", + "afii10097": "я", + "afii10098": "ґ", + "afii10099": "ђ", + "afii10100": "ѓ", + "afii10101": "є", + "afii10102": "ѕ", + "afii10103": "і", + "afii10104": "ї", + "afii10105": "ј", + "afii10106": "љ", + "afii10107": "њ", + "afii10108": "ћ", + "afii10109": "ќ", + "afii10110": "ў", + "afii10145": "Џ", + "afii10146": "Ѣ", + "afii10147": "Ѳ", + "afii10148": "Ѵ", + "afii10192": "", + "afii10193": "џ", + "afii10194": "ѣ", + "afii10195": "ѳ", + "afii10196": "ѵ", + "afii10831": "", + "afii10832": "", + "afii10846": "ә", + "afii299": "‎", + "afii300": "‏", + "afii301": "‍", + "afii57381": "٪", + "afii57388": "،", + "afii57392": "٠", + "afii57393": "١", + "afii57394": "٢", + "afii57395": "٣", + "afii57396": "٤", + "afii57397": "٥", + "afii57398": "٦", + "afii57399": "٧", + "afii57400": "٨", + "afii57401": "٩", + "afii57403": "؛", + "afii57407": "؟", + "afii57409": "ء", + "afii57410": "آ", + "afii57411": "أ", + "afii57412": "ؤ", + "afii57413": "إ", + "afii57414": "ئ", + "afii57415": "ا", + "afii57416": "ب", + "afii57417": "ة", + "afii57418": "ت", + "afii57419": "ث", + "afii57420": "ج", + "afii57421": "ح", + "afii57422": "خ", + "afii57423": "د", + "afii57424": "ذ", + "afii57425": "ر", + "afii57426": "ز", + "afii57427": "س", + "afii57428": "ش", + "afii57429": "ص", + "afii57430": "ض", + "afii57431": "ط", + "afii57432": "ظ", + "afii57433": "ع", + "afii57434": "غ", + "afii57440": "ـ", + "afii57441": "ف", + "afii57442": "ق", + "afii57443": "ك", + "afii57444": "ل", + "afii57445": "م", + "afii57446": "ن", + "afii57448": "و", + "afii57449": "ى", + "afii57450": "ي", + "afii57451": "ً", + "afii57452": "ٌ", + "afii57453": "ٍ", + "afii57454": "َ", + "afii57455": "ُ", + "afii57456": "ِ", + "afii57457": "ّ", + "afii57458": "ْ", + "afii57470": "ه", + "afii57505": "ڤ", + "afii57506": "پ", + "afii57507": "چ", + "afii57508": "ژ", + "afii57509": "گ", + "afii57511": "ٹ", + "afii57512": "ڈ", + "afii57513": "ڑ", + "afii57514": "ں", + "afii57519": "ے", + "afii57534": "ە", + "afii57636": "₪", + "afii57645": "־", + "afii57658": "׃", + "afii57664": "א", + "afii57665": "ב", + "afii57666": "ג", + "afii57667": "ד", + "afii57668": "ה", + "afii57669": "ו", + "afii57670": "ז", + "afii57671": "ח", + "afii57672": "ט", + "afii57673": "י", + "afii57674": "ך", + "afii57675": "כ", + "afii57676": "ל", + "afii57677": "ם", + "afii57678": "מ", + "afii57679": "ן", + "afii57680": "נ", + "afii57681": "ס", + "afii57682": "ע", + "afii57683": "ף", + "afii57684": "פ", + "afii57685": "ץ", + "afii57686": "צ", + "afii57687": "ק", + "afii57688": "ר", + "afii57689": "ש", + "afii57690": "ת", + "afii57694": "שׁ", + "afii57695": "שׂ", + "afii57700": "וֹ", + "afii57705": "ײַ", + "afii57716": "װ", + "afii57717": "ױ", + "afii57718": "ײ", + "afii57723": "וּ", + "afii57793": "ִ", + "afii57794": "ֵ", + "afii57795": "ֶ", + "afii57796": "ֻ", + "afii57797": "ָ", + "afii57798": "ַ", + "afii57799": "ְ", + "afii57800": "ֲ", + "afii57801": "ֱ", + "afii57802": "ֳ", + "afii57803": "ׂ", + "afii57804": "ׁ", + "afii57806": "ֹ", + "afii57807": "ּ", + "afii57839": "ֽ", + "afii57841": "ֿ", + "afii57842": "׀", + "afii57929": "ʼ", + "afii61248": "℅", + "afii61289": "ℓ", + "afii61352": "№", + "afii61573": "‬", + "afii61574": "‭", + "afii61575": "‮", + "afii61664": "‌", + "afii63167": "٭", + "afii64937": "ʽ", + "Agrave": "À", + "agrave": "à", + "Agravesmall": "", + "agudo": "´", + "aleph": "ℵ", + "Alpha": "Α", + "alpha": "α", + "Alphatonos": "Ά", + "alphatonos": "ά", + "Amacron": "Ā", + "amacron": "ā", + "ampersand": "&", + "ampersandsmall": "", + "angle": "∠", + "angleleft": "〈", + "angleright": "〉", + "anoteleia": "·", + "Aogonek": "Ą", + "aogonek": "ą", + "apostrophe": "'", + "approxequal": "≈", + "Aring": "Å", + "aring": "å", + "Aringacute": "Ǻ", + "aringacute": "ǻ", + "Aringsmall": "", + "arrowboth": "↔", + "arrowdblboth": "⇔", + "arrowdbldown": "⇓", + "arrowdblleft": "⇐", + "arrowdblright": "⇒", + "arrowdblup": "⇑", + "arrowdown": "↓", + "arrowhorizex": "", + "arrowleft": "←", + "arrowright": "→", + "arrowup": "↑", + "arrowupdn": "↕", + "arrowupdnbse": "↨", + "arrowvertex": "", + "asciicircum": "^", + "asciitilde": "~", + "Asmall": "", + "asterisk": "*", + "asteriskmath": "∗", + "asuperior": "", + "at": "@", + "Atilde": "Ã", + "atilde": "ã", + "Atildesmall": "", + "backslash": "\\", + "bar": "|", + "Beta": "Β", + "beta": "β", + "block": "█", + "braceex": "", + "braceleft": "{", + "braceleftbt": "", + "braceleftmid": "", + "bracelefttp": "", + "braceright": "}", + "bracerightbt": "", + "bracerightmid": "", + "bracerighttp": "", + "bracketleft": "[", + "bracketleftbt": "", + "bracketleftex": "", + "bracketlefttp": "", + "bracketright": "]", + "bracketrightbt": "", + "bracketrightex": "", + "bracketrighttp": "", + "breve": "˘", + "Brevesmall": "", + "brokenbar": "¦", + "Bsmall": "", + "bsuperior": "", + "bullet": "•", + "Cacute": "Ć", + "cacute": "ć", + "caron": "ˇ", + "Caron": "", + "Caronsmall": "", + "carriagereturn": "↵", + "Ccaron": "Č", + "ccaron": "č", + "Ccedilla": "Ç", + "ccedilla": "ç", + "Ccedillasmall": "", + "Ccircumflex": "Ĉ", + "ccircumflex": "ĉ", + "Cdotaccent": "Ċ", + "cdotaccent": "ċ", + "cedilla": "¸", + "Cedillasmall": "", + "cent": "¢", + "centinferior": "", + "centoldstyle": "", + "centsuperior": "", + "Chi": "Χ", + "chi": "χ", + "circle": "○", + "circlemultiply": "⊗", + "circleplus": "⊕", + "circumflex": "^", + "circumflex": "ˆ", + "Circumflexsmall": "", + "club": "♣", + "colon": ":", + "colonmonetary": "₡", + "ColonSign": "₡", + "comma": ",", + "commaaccent": "", + "commainferior": "", + "commasuperior": "", + "congruent": "≅", + "copyright": "©", + "copyrightsans": "", + "copyrightserif": "", + "CruzeiroSign": "₢", + "Csmall": "", + "currency": "¤", + "cyrBreve": "", + "cyrbreve": "", + "cyrFlex": "", + "cyrflex": "", + "dagger": "†", + "daggerdbl": "‡", + "dblGrave": "", + "dblgrave": "", + "Dcaron": "Ď", + "dcaron": "ď", + "Dcroat": "Đ", + "dcroat": "đ", + "degree": "°", + "Delta": "Δ", + "delta": "δ", + "diaeresis": "¨", + "diamond": "♦", + "dieresis": "¨", + "Dieresis": "", + "DieresisAcute": "", + "dieresisacute": "", + "DieresisGrave": "", + "dieresisgrave": "", + "Dieresissmall": "", + "dieresistonos": "΅", + "divide": "/", + "divide": "÷", + "division": "÷", + "dkshade": "▓", + "dnblock": "▄", + "dollar": "$", + "dollarinferior": "", + "dollaroldstyle": "", + "dollarsuperior": "", + "dong": "₫", + "DongSign": "₫", + "dot": ".", + "dotaccent": "˙", + "Dotaccentsmall": "", + "dotbelowcomb": "̣", + "dotlessi": "ı", + "dotlessj": "", + "dotmath": "⋅", + "Dsmall": "", + "dstroke": "đ", + "Dstroke": "Đ", + "dsuperior": "", + "Eacute": "É", + "eacute": "é", + "Eacutesmall": "", + "Ebreve": "Ĕ", + "ebreve": "ĕ", + "Ecaron": "Ě", + "ecaron": "ě", + "Ecircumflex": "Ê", + "ecircumflex": "ê", + "Ecircumflexacute": "Ế", + "ecircumflexacute": "ế", + "Ecircumflexbelowdot": "Ệ", + "ecircumflexbelowdot": "ệ", + "Ecircumflexgrave": "Ề", + "ecircumflexgrave": "ề", + "Ecircumflexhook": "Ể", + "ecircumflexhook": "ể", + "Ecircumflexsmall": "", + "Ecircumflextilde": "Ễ", + "ecircumflextilde": "ễ", + "EcuSign": "₠", + "Ediaeresis": "Ë", + "ediaeresis": "ë", + "Edieresis": "Ë", + "edieresis": "ë", + "Edieresissmall": "", + "Edotaccent": "Ė", + "edotaccent": "ė", + "Egrave": "È", + "egrave": "è", + "Egravesmall": "", + "eight": "8", + "eightinferior": "₈", + "eightoldstyle": "", + "eightsubscript": "₈", + "eightsuperior": "⁸", + "element": "∈", + "ellipsis": "…", + "Emacron": "Ē", + "emacron": "ē", + "emdash": "—", + "emptyset": "∅", + "endash": "–", + "enfilledcircbullet": "•", + "Eng": "Ŋ", + "eng": "ŋ", + "Eogonek": "Ę", + "eogonek": "ę", + "Epsilon": "Ε", + "epsilon": "ε", + "Epsilontonos": "Έ", + "epsilontonos": "έ", + "equal": "=", + "equivalence": "≡", + "Esmall": "", + "estimated": "℮", + "esuperior": "", + "Eta": "Η", + "eta": "η", + "Etatonos": "Ή", + "etatonos": "ή", + "ETH": "Ð", + "eth": "ð", + "Eth": "Ð", + "Ethsmall": "", + "euro": "€", + "Euro": "€", + "EuroSign": "€", + "exclam": "!", + "exclamdbl": "‼", + "exclamdown": "¡", + "exclamdownsmall": "", + "exclamsmall": "", + "existential": "∃", + "female": "♀", + "ff": "ff", + "ffi": "ffi", + "ffl": "ffl", + "FFrancSign": "₣", + "fi": "fi", + "figuredash": "‒", + "filledbox": "■", + "filledrect": "▬", + "five": "5", + "fiveeighths": "⅝", + "fiveinferior": "₅", + "fiveoldstyle": "", + "fivesubscript": "₅", + "fivesuperior": "⁵", + "fl": "fl", + "florin": "ƒ", + "four": "4", + "fourinferior": "₄", + "fouroldstyle": "", + "foursubscript": "₄", + "foursuperior": "⁴", + "fraction": "∕", + "franc": "₣", + "Fsmall": "", + "function": "ƒ", + "Gamma": "Γ", + "gamma": "γ", + "Gbreve": "Ğ", + "gbreve": "ğ", + "Gcaron": "Ǧ", + "gcaron": "ǧ", + "Gcircumflex": "Ĝ", + "gcircumflex": "ĝ", + "Gcommaaccent": "Ģ", + "gcommaaccent": "ģ", + "Gdotaccent": "Ġ", + "gdotaccent": "ġ", + "germandbls": "ß", + "gradient": "∇", + "grave": "`", + "Grave": "", + "gravecomb": "̀", + "Gravesmall": "", + "greater": ">", + "greaterequal": "≥", + "Gsmall": "", + "guillemotleft": "«", + "guillemotright": "»", + "guilsinglleft": "‹", + "guilsinglright": "›", + "H18533": "●", + "H18543": "▪", + "H18551": "▫", + "H22073": "□", + "hash": "#", + "hashtag": "#", + "Hbar": "Ħ", + "hbar": "ħ", + "Hcircumflex": "Ĥ", + "hcircumflex": "ĥ", + "heart": "♥", + "hookabovecomb": "̉", + "house": "⌂", + "Hsmall": "", + "hungarumlaut": "˝", + "Hungarumlaut": "", + "Hungarumlautsmall": "", + "hyphen": "­", + "hypheninferior": "", + "hyphensuperior": "", + "Iacute": "Í", + "iacute": "í", + "Iacutesmall": "", + "Ibreve": "Ĭ", + "ibreve": "ĭ", + "Icircumflex": "Î", + "icircumflex": "î", + "Icircumflexsmall": "", + "Idiaeresis": "Ï", + "idiaeresis": "ï", + "Idieresis": "Ï", + "idieresis": "ï", + "Idieresissmall": "", + "Idotaccent": "İ", + "Ifraktur": "ℑ", + "Igrave": "Ì", + "igrave": "ì", + "Igravesmall": "", + "IJ": "IJ", + "ij": "ij", + "Imacron": "Ī", + "imacron": "ī", + "infinity": "∞", + "integral": "∫", + "integralbt": "⌡", + "integralex": "", + "integraltp": "⌠", + "intersection": "∩", + "invbullet": "◘", + "invcircle": "◙", + "invsmileface": "☻", + "Iogonek": "Į", + "iogonek": "į", + "Iota": "Ι", + "iota": "ι", + "Iotadieresis": "Ϊ", + "iotadieresis": "ϊ", + "iotadieresistonos": "ΐ", + "Iotatonos": "Ί", + "iotatonos": "ί", + "Ismall": "", + "isuperior": "", + "Itilde": "Ĩ", + "itilde": "ĩ", + "Jcircumflex": "Ĵ", + "jcircumflex": "ĵ", + "Jsmall": "", + "Kappa": "Κ", + "kappa": "κ", + "Kcommaaccent": "Ķ", + "kcommaaccent": "ķ", + "kgreenlandic": "ĸ", + "Ksmall": "", + "Lacute": "Ĺ", + "lacute": "ĺ", + "Lambda": "Λ", + "lambda": "λ", + "Lcaron": "Ľ", + "lcaron": "ľ", + "Lcommaaccent": "Ļ", + "lcommaaccent": "ļ", + "Ldot": "Ŀ", + "ldot": "ŀ", + "less": "<", + "lessequal": "≤", + "lfblock": "▌", + "lira": "₤", + "LiraSign": "₤", + "LL": "", + "ll": "", + "logicaland": "∧", + "logicalnot": "¬", + "logicalor": "∨", + "longs": "ſ", + "lozenge": "◊", + "Lslash": "Ł", + "lslash": "ł", + "Lslashsmall": "", + "Lsmall": "", + "lsuperior": "", + "ltshade": "░", + "macron": "¯", + "macron": "ˉ", + "Macron": "", + "Macronsmall": "", + "male": "♂", + "masculine": "º", + "MillSign": "₥", + "minplus": "+", + "minus": "-", + "minus": "−", + "minute": "′", + "Msmall": "", + "msuperior": "", + "mu": "µ", + "Mu": "Μ", + "mu": "μ", + "multiply": "*", + "multiply": "×", + "musicalnote": "♪", + "musicalnotedbl": "♫", + "Nacute": "Ń", + "nacute": "ń", + "NairaSign": "₦", + "napostrophe": "ʼn", + "Ncaron": "Ň", + "ncaron": "ň", + "Ncommaaccent": "Ņ", + "ncommaaccent": "ņ", + "NewSheqelSign": "₪", + "nine": "9", + "nineinferior": "₉", + "nineoldstyle": "", + "ninesubscript": "₉", + "ninesuperior": "⁹", + "nobreakspace": " ", + "notelement": "∉", + "notequal": "≠", + "notsign": "¬", + "notsubset": "⊄", + "Nsmall": "", + "nsuperior": "ⁿ", + "Ntilde": "Ñ", + "ntilde": "ñ", + "Ntildesmall": "", + "Nu": "Ν", + "nu": "ν", + "numbersign": "#", + "numerosign": "№", + "Oacute": "Ó", + "oacute": "ó", + "Oacutesmall": "", + "Obreve": "Ŏ", + "obreve": "ŏ", + "Ocircumflex": "Ô", + "ocircumflex": "ô", + "Ocircumflexacute": "Ố", + "ocircumflexacute": "ố", + "Ocircumflexbelowdot": "Ộ", + "ocircumflexbelowdot": "ộ", + "Ocircumflexgrave": "Ồ", + "ocircumflexgrave": "ồ", + "Ocircumflexhook": "Ổ", + "ocircumflexhook": "ổ", + "Ocircumflexsmall": "", + "Ocircumflextilde": "Ỗ", + "ocircumflextilde": "ỗ", + "Odiaeresis": "Ö", + "odiaeresis": "ö", + "Odieresis": "Ö", + "odieresis": "ö", + "Odieresissmall": "", + "oe": "œ", + "OE": "Œ", + "OEsmall": "", + "ogonek": "˛", + "Ogoneksmall": "", + "Ograve": "Ò", + "ograve": "ò", + "Ogravesmall": "", + "Ohorn": "Ơ", + "ohorn": "ơ", + "Ohornacute": "Ớ", + "ohornacute": "ớ", + "Ohornbelowdot": "Ợ", + "ohornbelowdot": "ợ", + "Ohorngrave": "Ờ", + "ohorngrave": "ờ", + "Ohornhook": "Ở", + "ohornhook": "ở", + "Ohorntilde": "Ỡ", + "ohorntilde": "ỡ", + "Ohungarumlaut": "Ő", + "ohungarumlaut": "ő", + "Omacron": "Ō", + "omacron": "ō", + "Omega": "Ω", + "omega": "ω", + "omega1": "ϖ", + "Omegatonos": "Ώ", + "omegatonos": "ώ", + "Omicron": "Ο", + "omicron": "ο", + "Omicrontonos": "Ό", + "omicrontonos": "ό", + "one": "1", + "onedotenleader": "․", + "oneeighth": "⅛", + "onefitted": "", + "onehalf": "½", + "oneinferior": "₁", + "oneoldstyle": "", + "onequarter": "¼", + "onesubscript": "₁", + "onesuperior": "¹", + "onethird": "⅓", + "openbullet": "◦", + "ordfeminine": "ª", + "ordmasculine": "º", + "orthogonal": "∟", + "Oslash": "Ø", + "oslash": "ø", + "Oslashacute": "Ǿ", + "oslashacute": "ǿ", + "Oslashsmall": "", + "Osmall": "", + "osuperior": "", + "Otilde": "Õ", + "otilde": "õ", + "Otildesmall": "", + "paragraph": "¶", + "parenleft": "(", + "parenleftbt": "", + "parenleftex": "", + "parenleftinferior": "₍", + "parenleftsuperior": "⁽", + "parenlefttp": "", + "parenright": ")", + "parenrightbt": "", + "parenrightex": "", + "parenrightinferior": "₎", + "parenrightsuperior": "⁾", + "parenrighttp": "", + "partialdiff": "∂", + "percent": "%", + "period": ".", + "periodcentered": "·", + "periodcentered": "∙", + "periodinferior": "", + "periodsuperior": "", + "perpendicular": "⊥", + "perthousand": "‰", + "peseta": "₧", + "PesetaSign": "₧", + "Phi": "Φ", + "phi": "φ", + "phi1": "ϕ", + "Pi": "Π", + "pi": "π", + "plus": "+", + "plusminus": "±", + "pound": "£", + "prescription": "℞", + "product": "∏", + "propersubset": "⊂", + "propersuperset": "⊃", + "proportional": "∝", + "Psi": "Ψ", + "psi": "ψ", + "Psmall": "", + "Qsmall": "", + "question": "?", + "questiondown": "¿", + "questiondownsmall": "", + "questionsmall": "", + "quotedbl": "\"", + "quotedblbase": "„", + "quotedblleft": "“", + "quotedblright": "”", + "quoteleft": "‘", + "quotereversed": "‛", + "quoteright": "’", + "quotesinglbase": "‚", + "quotesingle": "'", + "Racute": "Ŕ", + "racute": "ŕ", + "radical": "√", + "radicalex": "", + "Rcaron": "Ř", + "rcaron": "ř", + "Rcommaaccent": "Ŗ", + "rcommaaccent": "ŗ", + "reflexsubset": "⊆", + "reflexsuperset": "⊇", + "registered": "®", + "registersans": "", + "registerserif": "", + "revlogicalnot": "⌐", + "Rfraktur": "ℜ", + "Rho": "Ρ", + "rho": "ρ", + "ring": "˚", + "Ringsmall": "", + "Rsmall": "", + "rsuperior": "", + "rtblock": "▐", + "RupeeSign": "₨", + "rupiah": "", + "Sacute": "Ś", + "sacute": "ś", + "Scaron": "Š", + "scaron": "š", + "Scaronsmall": "", + "Scedilla": "", + "scedilla": "", + "Scircumflex": "Ŝ", + "scircumflex": "ŝ", + "Scommaaccent": "Ș", + "scommaaccent": "ș", + "second": "″", + "section": "§", + "semicolon": ";", + "seven": "7", + "seveneighths": "⅞", + "seveninferior": "₇", + "sevenoldstyle": "", + "sevensubscript": "₇", + "sevensuperior": "⁷", + "SF010000": "┌", + "SF020000": "└", + "SF030000": "┐", + "SF040000": "┘", + "SF050000": "┼", + "SF060000": "┬", + "SF070000": "┴", + "SF080000": "├", + "SF090000": "┤", + "SF100000": "─", + "SF110000": "│", + "SF190000": "╡", + "SF200000": "╢", + "SF210000": "╖", + "SF220000": "╕", + "SF230000": "╣", + "SF240000": "║", + "SF250000": "╗", + "SF260000": "╝", + "SF270000": "╜", + "SF280000": "╛", + "SF360000": "╞", + "SF370000": "╟", + "SF380000": "╚", + "SF390000": "╔", + "SF400000": "╩", + "SF410000": "╦", + "SF420000": "╠", + "SF430000": "═", + "SF440000": "╬", + "SF450000": "╧", + "SF460000": "╨", + "SF470000": "╤", + "SF480000": "╥", + "SF490000": "╙", + "SF500000": "╘", + "SF510000": "╒", + "SF520000": "╓", + "SF530000": "╫", + "SF540000": "╪", + "shade": "▒", + "Sigma": "Σ", + "sigma": "σ", + "sigma1": "ς", + "similar": "∼", + "similarequal": "≃", + "six": "6", + "sixinferior": "₆", + "sixoldstyle": "", + "sixsubscript": "₆", + "sixsuperior": "⁶", + "slash": "/", + "smileface": "☺", + "spade": "♠", + "ssharp": "§", + "ssharp": "ß", + "Ssharp": "ẞ", + "Ssmall": "", + "ssuperior": "", + "sterling": "£", + "subtract": "-", + "suchthat": "∋", + "summation": "∑", + "sun": "☼", + "Tau": "Τ", + "tau": "τ", + "Tbar": "Ŧ", + "tbar": "ŧ", + "Tcaron": "Ť", + "tcaron": "ť", + "Tcommaaccent": "Ț", + "tcommaaccent": "ț", + "Thai_baht": "฿", + "therefore": "∴", + "Theta": "Θ", + "theta": "θ", + "theta1": "ϑ", + "THORN": "Þ", + "thorn": "þ", + "Thorn": "Þ", + "Thornsmall": "", + "three": "3", + "threeeighths": "⅜", + "threeinferior": "₃", + "threeoldstyle": "", + "threequarters": "¾", + "threequartersemdash": "", + "threesubscript": "₃", + "threesuperior": "³", + "til": "~", + "tilde": "~", + "tilde": "˜", + "tildecomb": "̃", + "Tildesmall": "", + "tonos": "΄", + "trademark": "™", + "trademarksans": "", + "trademarkserif": "", + "triagdn": "▼", + "triaglf": "◄", + "triagrt": "►", + "triagup": "▲", + "Tsmall": "", + "tsuperior": "", + "two": "2", + "twodotenleader": "‥", + "twoinferior": "₂", + "twooldstyle": "", + "twosubscript": "₂", + "twosuperior": "²", + "twothirds": "⅔", + "Uacute": "Ú", + "uacute": "ú", + "Uacutesmall": "", + "Ubreve": "Ŭ", + "ubreve": "ŭ", + "Ucircumflex": "Û", + "ucircumflex": "û", + "Ucircumflexsmall": "", + "Udiaeresis": "Ü", + "udiaeresis": "ü", + "Udieresis": "Ü", + "udieresis": "ü", + "Udieresissmall": "", + "Ugrave": "Ù", + "ugrave": "ù", + "Ugravesmall": "", + "Uhorn": "Ư", + "uhorn": "ư", + "Uhornacute": "Ứ", + "uhornacute": "ứ", + "Uhornbelowdot": "Ự", + "uhornbelowdot": "ự", + "Uhorngrave": "Ừ", + "uhorngrave": "ừ", + "Uhornhook": "Ử", + "uhornhook": "ử", + "Uhorntilde": "Ữ", + "uhorntilde": "ữ", + "Uhungarumlaut": "Ű", + "uhungarumlaut": "ű", + "Umacron": "Ū", + "umacron": "ū", + "underscore": "_", + "underscoredbl": "‗", + "union": "∪", + "universal": "∀", + "Uogonek": "Ų", + "uogonek": "ų", + "upblock": "▀", + "Upsilon": "Υ", + "upsilon": "υ", + "Upsilon1": "ϒ", + "Upsilondieresis": "Ϋ", + "upsilondieresis": "ϋ", + "upsilondieresistonos": "ΰ", + "Upsilontonos": "Ύ", + "upsilontonos": "ύ", + "Uring": "Ů", + "uring": "ů", + "Usmall": "", + "Utilde": "Ũ", + "utilde": "ũ", + "Vsmall": "", + "Wacute": "Ẃ", + "wacute": "ẃ", + "Wcircumflex": "Ŵ", + "wcircumflex": "ŵ", + "Wdieresis": "Ẅ", + "wdieresis": "ẅ", + "weierstrass": "℘", + "Wgrave": "Ẁ", + "wgrave": "ẁ", + "WonSign": "₩", + "Wsmall": "", + "Xi": "Ξ", + "xi": "ξ", + "Xsmall": "", + "Yacute": "Ý", + "yacute": "ý", + "Yacutesmall": "", + "Ycircumflex": "Ŷ", + "ycircumflex": "ŷ", + "ydiaeresis": "ÿ", + "Ydieresis": "Ÿ", + "ydieresis": "ÿ", + "Ydieresissmall": "", + "yen": "¥", + "Ygrave": "Ỳ", + "ygrave": "ỳ", + "Ysmall": "", + "Zacute": "Ź", + "zacute": "ź", + "Zcaron": "Ž", + "zcaron": "ž", + "Zcaronsmall": "", + "Zdotaccent": "Ż", + "zdotaccent": "ż", + "zero": "0", + "zeroinferior": "₀", + "zerooldstyle": "", + "zerosubscript": "₀", + "zerosuperior": "⁰", + "zeta": "ζ", + "Zeta": "Ζ", + "Zsmall": "", +} +sided_modifiers = {'ctrl', 'alt', 'shift', 'windows'} +all_modifiers = {'alt', 'alt gr', 'ctrl', 'shift', 'windows'} | set('left ' + n for n in sided_modifiers) | set('right ' + n for n in sided_modifiers) + +# Platform-specific canonical overrides + +if platform.system() == 'Darwin': + canonical_names.update({ + "command": "command", + "windows": "command", + "cmd": "command", + "win": "command", + "backspace": "delete", + 'alt gr': 'alt' # Issue #117 + }) + all_modifiers = {'alt', 'ctrl', 'shift', 'windows'} +if platform.system() == 'Linux': + canonical_names.update({ + "select": "end", + "find": "home", + 'next': 'page down', + 'prior': 'page up', + }) + +def normalize_name(name): + """ + Given a key name (e.g. "LEFT CONTROL"), clean up the string and convert to + the canonical representation (e.g. "left ctrl") if one is known. + """ + if not name or not isinstance(name, basestring): + raise ValueError('Can only normalize non-empty string names. Unexpected '+ repr(name)) + + if len(name) > 1: + name = name.lower() + if name != '_' and '_' in name: + name = name.replace('_', ' ') + + return canonical_names.get(name, name) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinkeyboard.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinkeyboard.py new file mode 100644 index 0000000..85670ee --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinkeyboard.py @@ -0,0 +1,442 @@ +import ctypes +import ctypes.util +import Quartz +import time +import os +import threading +from AppKit import NSEvent +from ._keyboard_event import KeyboardEvent, KEY_DOWN, KEY_UP +from ._canonical_names import normalize_name + +try: # Python 2/3 compatibility + unichr +except NameError: + unichr = chr + +Carbon = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Carbon')) + +class KeyMap(object): + non_layout_keys = dict((vk, normalize_name(name)) for vk, name in { + # Layout specific keys from https://stackoverflow.com/a/16125341/252218 + # Unfortunately no source for layout-independent keys was found. + 0x24: 'return', + 0x30: 'tab', + 0x31: 'space', + 0x33: 'delete', + 0x35: 'escape', + 0x37: 'command', + 0x38: 'shift', + 0x39: 'capslock', + 0x3a: 'option', + 0x3b: 'control', + 0x3c: 'right shift', + 0x3d: 'right option', + 0x3e: 'right control', + 0x3f: 'function', + 0x40: 'f17', + 0x48: 'volume up', + 0x49: 'volume down', + 0x4a: 'mute', + 0x4f: 'f18', + 0x50: 'f19', + 0x5a: 'f20', + 0x60: 'f5', + 0x61: 'f6', + 0x62: 'f7', + 0x63: 'f3', + 0x64: 'f8', + 0x65: 'f9', + 0x67: 'f11', + 0x69: 'f13', + 0x6a: 'f16', + 0x6b: 'f14', + 0x6d: 'f10', + 0x6f: 'f12', + 0x71: 'f15', + 0x72: 'help', + 0x73: 'home', + 0x74: 'page up', + 0x75: 'forward delete', + 0x76: 'f4', + 0x77: 'end', + 0x78: 'f2', + 0x79: 'page down', + 0x7a: 'f1', + 0x7b: 'left', + 0x7c: 'right', + 0x7d: 'down', + 0x7e: 'up', + }.items()) + layout_specific_keys = {} + def __init__(self): + # Virtual key codes are usually the same for any given key, unless you have a different + # keyboard layout. The only way I've found to determine the layout relies on (supposedly + # deprecated) Carbon APIs. If there's a more modern way to do this, please update this + # section. + + # Set up data types and exported values: + + CFTypeRef = ctypes.c_void_p + CFDataRef = ctypes.c_void_p + CFIndex = ctypes.c_uint64 + OptionBits = ctypes.c_uint32 + UniCharCount = ctypes.c_uint8 + UniChar = ctypes.c_uint16 + UniChar4 = UniChar * 4 + + class CFRange(ctypes.Structure): + _fields_ = [('loc', CFIndex), + ('len', CFIndex)] + + kTISPropertyUnicodeKeyLayoutData = ctypes.c_void_p.in_dll(Carbon, 'kTISPropertyUnicodeKeyLayoutData') + shiftKey = 0x0200 + alphaKey = 0x0400 + optionKey = 0x0800 + controlKey = 0x1000 + kUCKeyActionDisplay = 3 + kUCKeyTranslateNoDeadKeysBit = 0 + + # Set up function calls: + Carbon.CFDataGetBytes.argtypes = [CFDataRef] #, CFRange, UInt8 + Carbon.CFDataGetBytes.restype = None + Carbon.CFDataGetLength.argtypes = [CFDataRef] + Carbon.CFDataGetLength.restype = CFIndex + Carbon.CFRelease.argtypes = [CFTypeRef] + Carbon.CFRelease.restype = None + Carbon.LMGetKbdType.argtypes = [] + Carbon.LMGetKbdType.restype = ctypes.c_uint32 + Carbon.TISCopyCurrentKeyboardInputSource.argtypes = [] + Carbon.TISCopyCurrentKeyboardInputSource.restype = ctypes.c_void_p + Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource.argtypes = [] + Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource.restype = ctypes.c_void_p + Carbon.TISGetInputSourceProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + Carbon.TISGetInputSourceProperty.restype = ctypes.c_void_p + Carbon.UCKeyTranslate.argtypes = [ctypes.c_void_p, + ctypes.c_uint16, + ctypes.c_uint16, + ctypes.c_uint32, + ctypes.c_uint32, + OptionBits, # keyTranslateOptions + ctypes.POINTER(ctypes.c_uint32), # deadKeyState + UniCharCount, # maxStringLength + ctypes.POINTER(UniCharCount), # actualStringLength + UniChar4] + Carbon.UCKeyTranslate.restype = ctypes.c_uint32 + + # Get keyboard layout + klis = Carbon.TISCopyCurrentKeyboardInputSource() + k_layout = Carbon.TISGetInputSourceProperty(klis, kTISPropertyUnicodeKeyLayoutData) + if k_layout is None: + klis = Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource() + k_layout = Carbon.TISGetInputSourceProperty(klis, kTISPropertyUnicodeKeyLayoutData) + k_layout_size = Carbon.CFDataGetLength(k_layout) + k_layout_buffer = ctypes.create_string_buffer(k_layout_size) # TODO - Verify this works instead of initializing with empty string + Carbon.CFDataGetBytes(k_layout, CFRange(0, k_layout_size), ctypes.byref(k_layout_buffer)) + + # Generate character representations of key codes + for key_code in range(0, 128): + # TODO - Possibly add alt modifier to key map + non_shifted_char = UniChar4() + shifted_char = UniChar4() + keys_down = ctypes.c_uint32() + char_count = UniCharCount() + + retval = Carbon.UCKeyTranslate(k_layout_buffer, + key_code, + kUCKeyActionDisplay, + 0, # No modifier + Carbon.LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + ctypes.byref(keys_down), + 4, + ctypes.byref(char_count), + non_shifted_char) + + non_shifted_key = u''.join(unichr(non_shifted_char[i]) for i in range(char_count.value)) + + retval = Carbon.UCKeyTranslate(k_layout_buffer, + key_code, + kUCKeyActionDisplay, + shiftKey >> 8, # Shift + Carbon.LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + ctypes.byref(keys_down), + 4, + ctypes.byref(char_count), + shifted_char) + + shifted_key = u''.join(unichr(shifted_char[i]) for i in range(char_count.value)) + + self.layout_specific_keys[key_code] = (non_shifted_key, shifted_key) + # Cleanup + Carbon.CFRelease(klis) + + def character_to_vk(self, character): + """ Returns a tuple of (scan_code, modifiers) where ``scan_code`` is a numeric scan code + and ``modifiers`` is an array of string modifier names (like 'shift') """ + for vk in self.non_layout_keys: + if self.non_layout_keys[vk] == character.lower(): + return (vk, []) + for vk in self.layout_specific_keys: + if self.layout_specific_keys[vk][0] == character: + return (vk, []) + elif self.layout_specific_keys[vk][1] == character: + return (vk, ['shift']) + raise ValueError("Unrecognized character: {}".format(character)) + + def vk_to_character(self, vk, modifiers=[]): + """ Returns a character corresponding to the specified scan code (with given + modifiers applied) """ + if vk in self.non_layout_keys: + # Not a character + return self.non_layout_keys[vk] + elif vk in self.layout_specific_keys: + if 'shift' in modifiers: + return self.layout_specific_keys[vk][1] + return self.layout_specific_keys[vk][0] + else: + # Invalid vk + raise ValueError("Invalid scan code: {}".format(vk)) + + +class KeyController(object): + def __init__(self): + self.key_map = KeyMap() + self.current_modifiers = { + "shift": False, + "caps": False, + "alt": False, + "ctrl": False, + "cmd": False, + } + self.media_keys = { + 'KEYTYPE_SOUND_UP': 0, + 'KEYTYPE_SOUND_DOWN': 1, + 'KEYTYPE_BRIGHTNESS_UP': 2, + 'KEYTYPE_BRIGHTNESS_DOWN': 3, + 'KEYTYPE_CAPS_LOCK': 4, + 'KEYTYPE_HELP': 5, + 'POWER_KEY': 6, + 'KEYTYPE_MUTE': 7, + 'UP_ARROW_KEY': 8, + 'DOWN_ARROW_KEY': 9, + 'KEYTYPE_NUM_LOCK': 10, + 'KEYTYPE_CONTRAST_UP': 11, + 'KEYTYPE_CONTRAST_DOWN': 12, + 'KEYTYPE_LAUNCH_PANEL': 13, + 'KEYTYPE_EJECT': 14, + 'KEYTYPE_VIDMIRROR': 15, + 'KEYTYPE_PLAY': 16, + 'KEYTYPE_NEXT': 17, + 'KEYTYPE_PREVIOUS': 18, + 'KEYTYPE_FAST': 19, + 'KEYTYPE_REWIND': 20, + 'KEYTYPE_ILLUMINATION_UP': 21, + 'KEYTYPE_ILLUMINATION_DOWN': 22, + 'KEYTYPE_ILLUMINATION_TOGGLE': 23 + } + + def press(self, key_code): + """ Sends a 'down' event for the specified scan code """ + if key_code >= 128: + # Media key + ev = NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_( + 14, # type + (0, 0), # location + 0xa00, # flags + 0, # timestamp + 0, # window + 0, # ctx + 8, # subtype + ((key_code-128) << 16) | (0xa << 8), # data1 + -1 # data2 + ) + Quartz.CGEventPost(0, ev.CGEvent()) + else: + # Regular key + # Apply modifiers if necessary + event_flags = 0 + if self.current_modifiers["shift"]: + event_flags += Quartz.kCGEventFlagMaskShift + if self.current_modifiers["caps"]: + event_flags += Quartz.kCGEventFlagMaskAlphaShift + if self.current_modifiers["alt"]: + event_flags += Quartz.kCGEventFlagMaskAlternate + if self.current_modifiers["ctrl"]: + event_flags += Quartz.kCGEventFlagMaskControl + if self.current_modifiers["cmd"]: + event_flags += Quartz.kCGEventFlagMaskCommand + + # Update modifiers if necessary + if key_code == 0x37: # cmd + self.current_modifiers["cmd"] = True + elif key_code == 0x38 or key_code == 0x3C: # shift or right shift + self.current_modifiers["shift"] = True + elif key_code == 0x39: # caps lock + self.current_modifiers["caps"] = True + elif key_code == 0x3A: # alt + self.current_modifiers["alt"] = True + elif key_code == 0x3B: # ctrl + self.current_modifiers["ctrl"] = True + event = Quartz.CGEventCreateKeyboardEvent(None, key_code, True) + Quartz.CGEventSetFlags(event, event_flags) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, event) + time.sleep(0.01) + + def release(self, key_code): + """ Sends an 'up' event for the specified scan code """ + if key_code >= 128: + # Media key + ev = NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_( + 14, # type + (0, 0), # location + 0xb00, # flags + 0, # timestamp + 0, # window + 0, # ctx + 8, # subtype + ((key_code-128) << 16) | (0xb << 8), # data1 + -1 # data2 + ) + Quartz.CGEventPost(0, ev.CGEvent()) + else: + # Regular key + # Update modifiers if necessary + if key_code == 0x37: # cmd + self.current_modifiers["cmd"] = False + elif key_code == 0x38 or key_code == 0x3C: # shift or right shift + self.current_modifiers["shift"] = False + elif key_code == 0x39: # caps lock + self.current_modifiers["caps"] = False + elif key_code == 0x3A: # alt + self.current_modifiers["alt"] = False + elif key_code == 0x3B: # ctrl + self.current_modifiers["ctrl"] = False + + # Apply modifiers if necessary + event_flags = 0 + if self.current_modifiers["shift"]: + event_flags += Quartz.kCGEventFlagMaskShift + if self.current_modifiers["caps"]: + event_flags += Quartz.kCGEventFlagMaskAlphaShift + if self.current_modifiers["alt"]: + event_flags += Quartz.kCGEventFlagMaskAlternate + if self.current_modifiers["ctrl"]: + event_flags += Quartz.kCGEventFlagMaskControl + if self.current_modifiers["cmd"]: + event_flags += Quartz.kCGEventFlagMaskCommand + event = Quartz.CGEventCreateKeyboardEvent(None, key_code, False) + Quartz.CGEventSetFlags(event, event_flags) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, event) + time.sleep(0.01) + + def map_char(self, character): + if character in self.media_keys: + return (128+self.media_keys[character],[]) + else: + return self.key_map.character_to_vk(character) + def map_scan_code(self, scan_code): + if scan_code >= 128: + character = [k for k, v in enumerate(self.media_keys) if v == scan_code-128] + if len(character): + return character[0] + return None + else: + return self.key_map.vk_to_character(scan_code) + +class KeyEventListener(object): + def __init__(self, callback, blocking=False): + self.blocking = blocking + self.callback = callback + self.listening = True + self.tap = None + + def run(self): + """ Creates a listener and loops while waiting for an event. Intended to run as + a background thread. """ + self.tap = Quartz.CGEventTapCreate( + Quartz.kCGSessionEventTap, + Quartz.kCGHeadInsertEventTap, + Quartz.kCGEventTapOptionDefault, + Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventFlagsChanged), + self.handler, + None) + loopsource = Quartz.CFMachPortCreateRunLoopSource(None, self.tap, 0) + loop = Quartz.CFRunLoopGetCurrent() + Quartz.CFRunLoopAddSource(loop, loopsource, Quartz.kCFRunLoopDefaultMode) + Quartz.CGEventTapEnable(self.tap, True) + + while self.listening: + Quartz.CFRunLoopRunInMode(Quartz.kCFRunLoopDefaultMode, 5, False) + + def handler(self, proxy, e_type, event, refcon): + scan_code = Quartz.CGEventGetIntegerValueField(event, Quartz.kCGKeyboardEventKeycode) + key_name = name_from_scancode(scan_code) + flags = Quartz.CGEventGetFlags(event) + event_type = "" + is_keypad = (flags & Quartz.kCGEventFlagMaskNumericPad) + if e_type == Quartz.kCGEventKeyDown: + event_type = "down" + elif e_type == Quartz.kCGEventKeyUp: + event_type = "up" + elif e_type == Quartz.kCGEventFlagsChanged: + if key_name.endswith("shift") and (flags & Quartz.kCGEventFlagMaskShift): + event_type = "down" + elif key_name == "caps lock" and (flags & Quartz.kCGEventFlagMaskAlphaShift): + event_type = "down" + elif (key_name.endswith("option") or key_name.endswith("alt")) and (flags & Quartz.kCGEventFlagMaskAlternate): + event_type = "down" + elif key_name == "ctrl" and (flags & Quartz.kCGEventFlagMaskControl): + event_type = "down" + elif key_name == "command" and (flags & Quartz.kCGEventFlagMaskCommand): + event_type = "down" + else: + event_type = "up" + + if self.blocking: + return None + + self.callback(KeyboardEvent(event_type, scan_code, name=key_name, is_keypad=is_keypad)) + return event + +key_controller = KeyController() + +""" Exported functions below """ + +def init(): + key_controller = KeyController() + +def press(scan_code): + """ Sends a 'down' event for the specified scan code """ + key_controller.press(scan_code) + +def release(scan_code): + """ Sends an 'up' event for the specified scan code """ + key_controller.release(scan_code) + +def map_name(name): + """ Returns a tuple of (scan_code, modifiers) where ``scan_code`` is a numeric scan code + and ``modifiers`` is an array of string modifier names (like 'shift') """ + yield key_controller.map_char(name) + +def name_from_scancode(scan_code): + """ Returns the name or character associated with the specified key code """ + return key_controller.map_scan_code(scan_code) + +def listen(callback): + if not os.geteuid() == 0: + raise OSError("Error 13 - Must be run as administrator") + KeyEventListener(callback).run() + +def type_unicode(character): + OUTPUT_SOURCE = Quartz.CGEventSourceCreate(Quartz.kCGEventSourceStateHIDSystemState) + # Key down + event = Quartz.CGEventCreateKeyboardEvent(OUTPUT_SOURCE, 0, True) + Quartz.CGEventKeyboardSetUnicodeString(event, len(character.encode('utf-16-le')) // 2, character) + Quartz.CGEventPost(Quartz.kCGSessionEventTap, event) + # Key up + event = Quartz.CGEventCreateKeyboardEvent(OUTPUT_SOURCE, 0, False) + Quartz.CGEventKeyboardSetUnicodeString(event, len(character.encode('utf-16-le')) // 2, character) + Quartz.CGEventPost(Quartz.kCGSessionEventTap, event) \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinmouse.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinmouse.py new file mode 100644 index 0000000..b112dc0 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_darwinmouse.py @@ -0,0 +1,173 @@ +import os +import datetime +import threading +import Quartz +from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN + +_button_mapping = { + LEFT: (Quartz.kCGMouseButtonLeft, Quartz.kCGEventLeftMouseDown, Quartz.kCGEventLeftMouseUp, Quartz.kCGEventLeftMouseDragged), + RIGHT: (Quartz.kCGMouseButtonRight, Quartz.kCGEventRightMouseDown, Quartz.kCGEventRightMouseUp, Quartz.kCGEventRightMouseDragged), + MIDDLE: (Quartz.kCGMouseButtonCenter, Quartz.kCGEventOtherMouseDown, Quartz.kCGEventOtherMouseUp, Quartz.kCGEventOtherMouseDragged) +} +_button_state = { + LEFT: False, + RIGHT: False, + MIDDLE: False +} +_last_click = { + "time": None, + "button": None, + "position": None, + "click_count": 0 +} + +class MouseEventListener(object): + def __init__(self, callback, blocking=False): + self.blocking = blocking + self.callback = callback + self.listening = True + + def run(self): + """ Creates a listener and loops while waiting for an event. Intended to run as + a background thread. """ + self.tap = Quartz.CGEventTapCreate( + Quartz.kCGSessionEventTap, + Quartz.kCGHeadInsertEventTap, + Quartz.kCGEventTapOptionDefault, + Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventMouseMoved) | + Quartz.CGEventMaskBit(Quartz.kCGEventScrollWheel), + self.handler, + None) + loopsource = Quartz.CFMachPortCreateRunLoopSource(None, self.tap, 0) + loop = Quartz.CFRunLoopGetCurrent() + Quartz.CFRunLoopAddSource(loop, loopsource, Quartz.kCFRunLoopDefaultMode) + Quartz.CGEventTapEnable(self.tap, True) + + while self.listening: + Quartz.CFRunLoopRunInMode(Quartz.kCFRunLoopDefaultMode, 5, False) + + def handler(self, proxy, e_type, event, refcon): + # TODO Separate event types by button/wheel/move + scan_code = Quartz.CGEventGetIntegerValueField(event, Quartz.kCGKeyboardEventKeycode) + key_name = name_from_scancode(scan_code) + flags = Quartz.CGEventGetFlags(event) + event_type = "" + is_keypad = (flags & Quartz.kCGEventFlagMaskNumericPad) + if e_type == Quartz.kCGEventKeyDown: + event_type = "down" + elif e_type == Quartz.kCGEventKeyUp: + event_type = "up" + + if self.blocking: + return None + + self.callback(KeyboardEvent(event_type, scan_code, name=key_name, is_keypad=is_keypad)) + return event + +# Exports + +def init(): + """ Initializes mouse state """ + pass + +def listen(queue): + """ Appends events to the queue (ButtonEvent, WheelEvent, and MoveEvent). """ + if not os.geteuid() == 0: + raise OSError("Error 13 - Must be run as administrator") + listener = MouseEventListener(lambda e: queue.put(e) or is_allowed(e.name, e.event_type == KEY_UP)) + t = threading.Thread(target=listener.run, args=()) + t.daemon = True + t.start() + +def press(button=LEFT): + """ Sends a down event for the specified button, using the provided constants """ + location = get_position() + button_code, button_down, _, _ = _button_mapping[button] + e = Quartz.CGEventCreateMouseEvent( + None, + button_down, + location, + button_code) + + # Check if this is a double-click (same location within the last 300ms) + if _last_click["time"] is not None and datetime.datetime.now() - _last_click["time"] < datetime.timedelta(seconds=0.3) and _last_click["button"] == button and _last_click["position"] == location: + # Repeated Click + _last_click["click_count"] = min(3, _last_click["click_count"]+1) + else: + # Not a double-click - Reset last click + _last_click["click_count"] = 1 + Quartz.CGEventSetIntegerValueField( + e, + Quartz.kCGMouseEventClickState, + _last_click["click_count"]) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, e) + _button_state[button] = True + _last_click["time"] = datetime.datetime.now() + _last_click["button"] = button + _last_click["position"] = location + +def release(button=LEFT): + """ Sends an up event for the specified button, using the provided constants """ + location = get_position() + button_code, _, button_up, _ = _button_mapping[button] + e = Quartz.CGEventCreateMouseEvent( + None, + button_up, + location, + button_code) + + if _last_click["time"] is not None and _last_click["time"] > datetime.datetime.now() - datetime.timedelta(microseconds=300000) and _last_click["button"] == button and _last_click["position"] == location: + # Repeated Click + Quartz.CGEventSetIntegerValueField( + e, + Quartz.kCGMouseEventClickState, + _last_click["click_count"]) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, e) + _button_state[button] = False + +def wheel(delta=1): + """ Sends a wheel event for the provided number of clicks. May be negative to reverse + direction. """ + location = get_position() + e = Quartz.CGEventCreateMouseEvent( + None, + Quartz.kCGEventScrollWheel, + location, + Quartz.kCGMouseButtonLeft) + e2 = Quartz.CGEventCreateScrollWheelEvent( + None, + Quartz.kCGScrollEventUnitLine, + 1, + delta) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, e) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, e2) + +def move_to(x, y): + """ Sets the mouse's location to the specified coordinates. """ + for b in _button_state: + if _button_state[b]: + e = Quartz.CGEventCreateMouseEvent( + None, + _button_mapping[b][3], # Drag Event + (x, y), + _button_mapping[b][0]) + break + else: + e = Quartz.CGEventCreateMouseEvent( + None, + Quartz.kCGEventMouseMoved, + (x, y), + Quartz.kCGMouseButtonLeft) + Quartz.CGEventPost(Quartz.kCGHIDEventTap, e) + +def get_position(): + """ Returns the mouse's location as a tuple of (x, y). """ + e = Quartz.CGEventCreate(None) + point = Quartz.CGEventGetLocation(e) + return (point.x, point.y) \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_generic.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_generic.py new file mode 100644 index 0000000..bac559f --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_generic.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +from threading import Thread, Lock +import traceback +import functools + +try: + from queue import Queue +except ImportError: + from Queue import Queue + +class GenericListener(object): + lock = Lock() + + def __init__(self): + self.handlers = [] + self.listening = False + self.queue = Queue() + + def invoke_handlers(self, event): + for handler in self.handlers: + try: + if handler(event): + # Stop processing this hotkey. + return 1 + except Exception as e: + traceback.print_exc() + + def start_if_necessary(self): + """ + Starts the listening thread if it wasn't already. + """ + self.lock.acquire() + try: + if not self.listening: + self.init() + + self.listening = True + self.listening_thread = Thread(target=self.listen) + self.listening_thread.daemon = True + self.listening_thread.start() + + self.processing_thread = Thread(target=self.process) + self.processing_thread.daemon = True + self.processing_thread.start() + finally: + self.lock.release() + + def pre_process_event(self, event): + raise NotImplementedError('This method should be implemented in the child class.') + + def process(self): + """ + Loops over the underlying queue of events and processes them in order. + """ + assert self.queue is not None + while True: + event = self.queue.get() + if self.pre_process_event(event): + self.invoke_handlers(event) + self.queue.task_done() + + def add_handler(self, handler): + """ + Adds a function to receive each event captured, starting the capturing + process if necessary. + """ + self.start_if_necessary() + self.handlers.append(handler) + + def remove_handler(self, handler): + """ Removes a previously added event handler. """ + while handler in self.handlers: + self.handlers.remove(handler) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_event.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_event.py new file mode 100644 index 0000000..6d9f279 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_event.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +from time import time as now +import json +from ._canonical_names import canonical_names, normalize_name + +try: + basestring +except NameError: + basestring = str + +KEY_DOWN = 'down' +KEY_UP = 'up' + +class KeyboardEvent(object): + event_type = None + scan_code = None + name = None + time = None + device = None + modifiers = None + is_keypad = None + + def __init__(self, event_type, scan_code, name=None, time=None, device=None, modifiers=None, is_keypad=None): + self.event_type = event_type + self.scan_code = scan_code + self.time = now() if time is None else time + self.device = device + self.is_keypad = is_keypad + self.modifiers = modifiers + if name: + self.name = normalize_name(name) + + def to_json(self, ensure_ascii=False): + attrs = dict( + (attr, getattr(self, attr)) for attr in ['event_type', 'scan_code', 'name', 'time', 'device', 'is_keypad'] + if not attr.startswith('_') and getattr(self, attr) is not None + ) + return json.dumps(attrs, ensure_ascii=ensure_ascii) + + def __repr__(self): + return 'KeyboardEvent({} {})'.format(self.name or 'Unknown {}'.format(self.scan_code), self.event_type) + + def __eq__(self, other): + return ( + isinstance(other, KeyboardEvent) + and self.event_type == other.event_type + and ( + not self.scan_code or not other.scan_code or self.scan_code == other.scan_code + ) and ( + not self.name or not other.name or self.name == other.name + ) + ) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_tests.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_tests.py new file mode 100644 index 0000000..f0e1432 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_keyboard_tests.py @@ -0,0 +1,827 @@ +# -*- coding: utf-8 -*- +""" +Side effects are avoided using two techniques: + +- Low level OS requests (keyboard._os_keyboard) are mocked out by rewriting +the functions at that namespace. This includes a list of dummy keys. +- Events are pumped manually by the main test class, and accepted events +are tested against expected values. + +Fake user events are appended to `input_events`, passed through +keyboard,_listener.direct_callback, then, if accepted, appended to +`output_events`. Fake OS events (keyboard.press) are processed +and added to `output_events` immediately, mimicking real functionality. +""" +from __future__ import print_function + +import unittest +import time + +import keyboard +from ._keyboard_event import KeyboardEvent, KEY_DOWN, KEY_UP + +dummy_keys = { + 'space': [(0, [])], + + 'a': [(1, [])], + 'b': [(2, [])], + 'c': [(3, [])], + 'A': [(1, ['shift']), (-1, [])], + 'B': [(2, ['shift']), (-2, [])], + 'C': [(3, ['shift']), (-3, [])], + + 'alt': [(4, [])], + 'left alt': [(4, [])], + + 'left shift': [(5, [])], + 'right shift': [(6, [])], + + 'left ctrl': [(7, [])], + + 'backspace': [(8, [])], + 'caps lock': [(9, [])], + + '+': [(10, [])], + ',': [(11, [])], + '_': [(12, [])], + + 'none': [], + 'duplicated': [(20, []), (20, [])], +} + +def make_event(event_type, name, scan_code=None, time=0): + return KeyboardEvent(event_type=event_type, scan_code=scan_code or dummy_keys[name][0][0], name=name, time=time) + +# Used when manually pumping events. +input_events = [] +output_events = [] + +def send_instant_event(event): + if keyboard._listener.direct_callback(event): + output_events.append(event) + +# Mock out side effects. +keyboard._os_keyboard.init = lambda: None +keyboard._os_keyboard.listen = lambda callback: None +keyboard._os_keyboard.map_name = dummy_keys.__getitem__ +keyboard._os_keyboard.press = lambda scan_code: send_instant_event(make_event(KEY_DOWN, None, scan_code)) +keyboard._os_keyboard.release = lambda scan_code: send_instant_event(make_event(KEY_UP, None, scan_code)) +keyboard._os_keyboard.type_unicode = lambda char: output_events.append(KeyboardEvent(event_type=KEY_DOWN, scan_code=999, name=char)) + +# Shortcuts for defining test inputs and expected outputs. +# Usage: d_shift + d_a + u_a + u_shift +d_a = [make_event(KEY_DOWN, 'a')] +u_a = [make_event(KEY_UP, 'a')] +du_a = d_a+u_a +d_b = [make_event(KEY_DOWN, 'b')] +u_b = [make_event(KEY_UP, 'b')] +du_b = d_b+u_b +d_c = [make_event(KEY_DOWN, 'c')] +u_c = [make_event(KEY_UP, 'c')] +du_c = d_c+u_c +d_ctrl = [make_event(KEY_DOWN, 'left ctrl')] +u_ctrl = [make_event(KEY_UP, 'left ctrl')] +du_ctrl = d_ctrl+u_ctrl +d_shift = [make_event(KEY_DOWN, 'left shift')] +u_shift = [make_event(KEY_UP, 'left shift')] +du_shift = d_shift+u_shift +d_alt = [make_event(KEY_DOWN, 'alt')] +u_alt = [make_event(KEY_UP, 'alt')] +du_alt = d_alt+u_alt +du_backspace = [make_event(KEY_DOWN, 'backspace'), make_event(KEY_UP, 'backspace')] +du_capslock = [make_event(KEY_DOWN, 'caps lock'), make_event(KEY_UP, 'caps lock')] +d_space = [make_event(KEY_DOWN, 'space')] +u_space = [make_event(KEY_UP, 'space')] +du_space = [make_event(KEY_DOWN, 'space'), make_event(KEY_UP, 'space')] + +trigger = lambda e=None: keyboard.press(999) +triggered_event = [KeyboardEvent(KEY_DOWN, scan_code=999)] + +class TestKeyboard(unittest.TestCase): + def tearDown(self): + keyboard.unhook_all() + #self.assertEquals(keyboard._hooks, {}) + #self.assertEquals(keyboard._hotkeys, {}) + + def setUp(self): + #keyboard._hooks.clear() + #keyboard._hotkeys.clear() + del input_events[:] + del output_events[:] + keyboard._recording = None + keyboard._pressed_events.clear() + keyboard._physically_pressed_keys.clear() + keyboard._logically_pressed_keys.clear() + keyboard._hotkeys.clear() + keyboard._listener.init() + keyboard._word_listeners = {} + + def do(self, manual_events, expected=None): + input_events.extend(manual_events) + while input_events: + event = input_events.pop(0) + if keyboard._listener.direct_callback(event): + output_events.append(event) + if expected is not None: + to_names = lambda es: '+'.join(('d' if e.event_type == KEY_DOWN else 'u') + '_' + str(e.scan_code) for e in es) + self.assertEqual(to_names(output_events), to_names(expected)) + del output_events[:] + + keyboard._listener.queue.join() + + def test_event_json(self): + event = make_event(KEY_DOWN, u'á \'"', 999) + import json + self.assertEqual(event, KeyboardEvent(**json.loads(event.to_json()))) + + def test_is_modifier_name(self): + for name in keyboard.all_modifiers: + self.assertTrue(keyboard.is_modifier(name)) + def test_is_modifier_scan_code(self): + for i in range(10): + self.assertEqual(keyboard.is_modifier(i), i in [4, 5, 6, 7]) + + def test_key_to_scan_codes_brute(self): + for name, entries in dummy_keys.items(): + if name in ['none', 'duplicated']: continue + expected = tuple(scan_code for scan_code, modifiers in entries) + self.assertEqual(keyboard.key_to_scan_codes(name), expected) + def test_key_to_scan_code_from_scan_code(self): + for i in range(10): + self.assertEqual(keyboard.key_to_scan_codes(i), (i,)) + def test_key_to_scan_code_from_letter(self): + self.assertEqual(keyboard.key_to_scan_codes('a'), (1,)) + self.assertEqual(keyboard.key_to_scan_codes('A'), (1,-1)) + def test_key_to_scan_code_from_normalized(self): + self.assertEqual(keyboard.key_to_scan_codes('shift'), (5,6)) + self.assertEqual(keyboard.key_to_scan_codes('SHIFT'), (5,6)) + self.assertEqual(keyboard.key_to_scan_codes('ctrl'), keyboard.key_to_scan_codes('CONTROL')) + def test_key_to_scan_code_from_sided_modifier(self): + self.assertEqual(keyboard.key_to_scan_codes('left shift'), (5,)) + self.assertEqual(keyboard.key_to_scan_codes('right shift'), (6,)) + def test_key_to_scan_code_underscores(self): + self.assertEqual(keyboard.key_to_scan_codes('_'), (12,)) + self.assertEqual(keyboard.key_to_scan_codes('right_shift'), (6,)) + def test_key_to_scan_code_error_none(self): + with self.assertRaises(ValueError): + keyboard.key_to_scan_codes(None) + def test_key_to_scan_code_error_empty(self): + with self.assertRaises(ValueError): + keyboard.key_to_scan_codes('') + def test_key_to_scan_code_error_other(self): + with self.assertRaises(ValueError): + keyboard.key_to_scan_codes({}) + def test_key_to_scan_code_list(self): + self.assertEqual(keyboard.key_to_scan_codes([10, 5, 'a']), (10, 5, 1)) + def test_key_to_scan_code_empty(self): + with self.assertRaises(ValueError): + keyboard.key_to_scan_codes('none') + def test_key_to_scan_code_duplicated(self): + self.assertEqual(keyboard.key_to_scan_codes('duplicated'), (20,)) + + def test_parse_hotkey_simple(self): + self.assertEqual(keyboard.parse_hotkey('a'), (((1,),),)) + self.assertEqual(keyboard.parse_hotkey('A'), (((1,-1),),)) + def test_parse_hotkey_separators(self): + self.assertEqual(keyboard.parse_hotkey('+'), keyboard.parse_hotkey('plus')) + self.assertEqual(keyboard.parse_hotkey(','), keyboard.parse_hotkey('comma')) + def test_parse_hotkey_keys(self): + self.assertEqual(keyboard.parse_hotkey('left shift + a'), (((5,), (1,),),)) + self.assertEqual(keyboard.parse_hotkey('left shift+a'), (((5,), (1,),),)) + def test_parse_hotkey_simple_steps(self): + self.assertEqual(keyboard.parse_hotkey('a,b'), (((1,),),((2,),))) + self.assertEqual(keyboard.parse_hotkey('a, b'), (((1,),),((2,),))) + def test_parse_hotkey_steps(self): + self.assertEqual(keyboard.parse_hotkey('a+b, b+c'), (((1,),(2,)),((2,),(3,)))) + def test_parse_hotkey_example(self): + alt_codes = keyboard.key_to_scan_codes('alt') + shift_codes = keyboard.key_to_scan_codes('shift') + a_codes = keyboard.key_to_scan_codes('a') + b_codes = keyboard.key_to_scan_codes('b') + c_codes = keyboard.key_to_scan_codes('c') + self.assertEqual(keyboard.parse_hotkey("alt+shift+a, alt+b, c"), ((alt_codes, shift_codes, a_codes), (alt_codes, b_codes), (c_codes,))) + def test_parse_hotkey_list_scan_codes(self): + self.assertEqual(keyboard.parse_hotkey([1, 2, 3]), (((1,), (2,), (3,)),)) + def test_parse_hotkey_deep_list_scan_codes(self): + result = keyboard.parse_hotkey('a') + self.assertEqual(keyboard.parse_hotkey(result), (((1,),),)) + def test_parse_hotkey_list_names(self): + self.assertEqual(keyboard.parse_hotkey(['a', 'b', 'c']), (((1,), (2,), (3,)),)) + + def test_is_pressed_none(self): + self.assertFalse(keyboard.is_pressed('a')) + def test_is_pressed_true(self): + self.do(d_a) + self.assertTrue(keyboard.is_pressed('a')) + def test_is_pressed_true_scan_code_true(self): + self.do(d_a) + self.assertTrue(keyboard.is_pressed(1)) + def test_is_pressed_true_scan_code_false(self): + self.do(d_a) + self.assertFalse(keyboard.is_pressed(2)) + def test_is_pressed_true_scan_code_invalid(self): + self.do(d_a) + self.assertFalse(keyboard.is_pressed(-1)) + def test_is_pressed_false(self): + self.do(d_a+u_a+d_b) + self.assertFalse(keyboard.is_pressed('a')) + self.assertTrue(keyboard.is_pressed('b')) + def test_is_pressed_hotkey_true(self): + self.do(d_shift+d_a) + self.assertTrue(keyboard.is_pressed('shift+a')) + def test_is_pressed_hotkey_false(self): + self.do(d_shift+d_a+u_a) + self.assertFalse(keyboard.is_pressed('shift+a')) + def test_is_pressed_multi_step_fail(self): + self.do(u_a+d_a) + with self.assertRaises(ValueError): + keyboard.is_pressed('a, b') + + def test_send_single_press_release(self): + keyboard.send('a', do_press=True, do_release=True) + self.do([], d_a+u_a) + def test_send_single_press(self): + keyboard.send('a', do_press=True, do_release=False) + self.do([], d_a) + def test_send_single_release(self): + keyboard.send('a', do_press=False, do_release=True) + self.do([], u_a) + def test_send_single_none(self): + keyboard.send('a', do_press=False, do_release=False) + self.do([], []) + def test_press(self): + keyboard.press('a') + self.do([], d_a) + def test_release(self): + keyboard.release('a') + self.do([], u_a) + def test_press_and_release(self): + keyboard.press_and_release('a') + self.do([], d_a+u_a) + + def test_send_modifier_press_release(self): + keyboard.send('ctrl+a', do_press=True, do_release=True) + self.do([], d_ctrl+d_a+u_a+u_ctrl) + def test_send_modifiers_release(self): + keyboard.send('ctrl+shift+a', do_press=False, do_release=True) + self.do([], u_a+u_shift+u_ctrl) + + def test_call_later(self): + triggered = [] + def fn(arg1, arg2): + assert arg1 == 1 and arg2 == 2 + triggered.append(True) + keyboard.call_later(fn, (1, 2), 0.01) + self.assertFalse(triggered) + time.sleep(0.05) + self.assertTrue(triggered) + + def test_hook_nonblocking(self): + self.i = 0 + def count(e): + self.assertEqual(e.name, 'a') + self.i += 1 + hook = keyboard.hook(count, suppress=False) + self.do(d_a+u_a, d_a+u_a) + self.assertEqual(self.i, 2) + keyboard.unhook(hook) + self.do(d_a+u_a, d_a+u_a) + self.assertEqual(self.i, 2) + keyboard.hook(count, suppress=False) + self.do(d_a+u_a, d_a+u_a) + self.assertEqual(self.i, 4) + keyboard.unhook_all() + self.do(d_a+u_a, d_a+u_a) + self.assertEqual(self.i, 4) + def test_hook_blocking(self): + self.i = 0 + def count(e): + self.assertIn(e.name, ['a', 'b']) + self.i += 1 + return e.name == 'b' + hook = keyboard.hook(count, suppress=True) + self.do(d_a+d_b, d_b) + self.assertEqual(self.i, 2) + keyboard.unhook(hook) + self.do(d_a+d_b, d_a+d_b) + self.assertEqual(self.i, 2) + keyboard.hook(count, suppress=True) + self.do(d_a+d_b, d_b) + self.assertEqual(self.i, 4) + keyboard.unhook_all() + self.do(d_a+d_b, d_a+d_b) + self.assertEqual(self.i, 4) + def test_on_press_nonblocking(self): + keyboard.on_press(lambda e: self.assertEqual(e.name, 'a') and self.assertEqual(e.event_type, KEY_DOWN)) + self.do(d_a+u_a) + def test_on_press_blocking(self): + keyboard.on_press(lambda e: e.scan_code == 1, suppress=True) + self.do([make_event(KEY_DOWN, 'A', -1)] + d_a, d_a) + def test_on_release(self): + keyboard.on_release(lambda e: self.assertEqual(e.name, 'a') and self.assertEqual(e.event_type, KEY_UP)) + self.do(d_a+u_a) + + def test_hook_key_invalid(self): + with self.assertRaises(ValueError): + keyboard.hook_key('invalid', lambda e: None) + def test_hook_key_nonblocking(self): + self.i = 0 + def count(event): + self.i += 1 + hook = keyboard.hook_key('A', count) + self.do(d_a) + self.assertEqual(self.i, 1) + self.do(u_a+d_b) + self.assertEqual(self.i, 2) + self.do([make_event(KEY_DOWN, 'A', -1)]) + self.assertEqual(self.i, 3) + keyboard.unhook_key(hook) + self.do(d_a) + self.assertEqual(self.i, 3) + def test_hook_key_blocking(self): + self.i = 0 + def count(event): + self.i += 1 + return event.scan_code == 1 + hook = keyboard.hook_key('A', count, suppress=True) + self.do(d_a, d_a) + self.assertEqual(self.i, 1) + self.do(u_a+d_b, u_a+d_b) + self.assertEqual(self.i, 2) + self.do([make_event(KEY_DOWN, 'A', -1)], []) + self.assertEqual(self.i, 3) + keyboard.unhook_key(hook) + self.do([make_event(KEY_DOWN, 'A', -1)], [make_event(KEY_DOWN, 'A', -1)]) + self.assertEqual(self.i, 3) + def test_on_press_key_nonblocking(self): + keyboard.on_press_key('A', lambda e: self.assertEqual(e.name, 'a') and self.assertEqual(e.event_type, KEY_DOWN)) + self.do(d_a+u_a+d_b+u_b) + def test_on_press_key_blocking(self): + keyboard.on_press_key('A', lambda e: e.scan_code == 1, suppress=True) + self.do([make_event(KEY_DOWN, 'A', -1)] + d_a, d_a) + def test_on_release_key(self): + keyboard.on_release_key('a', lambda e: self.assertEqual(e.name, 'a') and self.assertEqual(e.event_type, KEY_UP)) + self.do(d_a+u_a) + + def test_block_key(self): + blocked = keyboard.block_key('a') + self.do(d_a+d_b, d_b) + self.do([make_event(KEY_DOWN, 'A', -1)], [make_event(KEY_DOWN, 'A', -1)]) + keyboard.unblock_key(blocked) + self.do(d_a+d_b, d_a+d_b) + def test_block_key_ambiguous(self): + keyboard.block_key('A') + self.do(d_a+d_b, d_b) + self.do([make_event(KEY_DOWN, 'A', -1)], []) + + def test_remap_key_simple(self): + mapped = keyboard.remap_key('a', 'b') + self.do(d_a+d_c+u_a, d_b+d_c+u_b) + keyboard.unremap_key(mapped) + self.do(d_a+d_c+u_a, d_a+d_c+u_a) + def test_remap_key_ambiguous(self): + keyboard.remap_key('A', 'b') + self.do(d_a+d_b, d_b+d_b) + self.do([make_event(KEY_DOWN, 'A', -1)], d_b) + def test_remap_key_multiple(self): + mapped = keyboard.remap_key('a', 'shift+b') + self.do(d_a+d_c+u_a, d_shift+d_b+d_c+u_b+u_shift) + keyboard.unremap_key(mapped) + self.do(d_a+d_c+u_a, d_a+d_c+u_a) + + def test_stash_state(self): + self.do(d_a+d_shift) + self.assertEqual(sorted(keyboard.stash_state()), [1, 5]) + self.do([], u_a+u_shift) + def test_restore_state(self): + self.do(d_b) + keyboard.restore_state([1, 5]) + self.do([], u_b+d_a+d_shift) + def test_restore_modifieres(self): + self.do(d_b) + keyboard.restore_modifiers([1, 5]) + self.do([], u_b+d_shift) + + def test_write_simple(self): + keyboard.write('a', exact=False) + self.do([], d_a+u_a) + def test_write_multiple(self): + keyboard.write('ab', exact=False) + self.do([], d_a+u_a+d_b+u_b) + def test_write_modifiers(self): + keyboard.write('Ab', exact=False) + self.do([], d_shift+d_a+u_a+u_shift+d_b+u_b) + # restore_state_after has been removed after the introduction of `restore_modifiers`. + #def test_write_stash_not_restore(self): + # self.do(d_shift) + # keyboard.write('a', restore_state_after=False, exact=False) + # self.do([], u_shift+d_a+u_a) + def test_write_stash_restore(self): + self.do(d_shift) + keyboard.write('a', exact=False) + self.do([], u_shift+d_a+u_a+d_shift) + def test_write_multiple(self): + last_time = time.time() + keyboard.write('ab', delay=0.01, exact=False) + self.do([], d_a+u_a+d_b+u_b) + self.assertGreater(time.time() - last_time, 0.015) + def test_write_unicode_explicit(self): + keyboard.write('ab', exact=True) + self.do([], [KeyboardEvent(event_type=KEY_DOWN, scan_code=999, name='a'), KeyboardEvent(event_type=KEY_DOWN, scan_code=999, name='b')]) + def test_write_unicode_fallback(self): + keyboard.write(u'áb', exact=False) + self.do([], [KeyboardEvent(event_type=KEY_DOWN, scan_code=999, name=u'á')]+d_b+u_b) + + def test_start_stop_recording(self): + keyboard.start_recording() + self.do(d_a+u_a) + self.assertEqual(keyboard.stop_recording(), d_a+u_a) + def test_stop_recording_error(self): + with self.assertRaises(ValueError): + keyboard.stop_recording() + + def test_record(self): + queue = keyboard._queue.Queue() + def process(): + queue.put(keyboard.record('space', suppress=True)) + from threading import Thread + t = Thread(target=process) + t.daemon = True + t.start() + # 0.01s sleep failed once already. Better solutions? + time.sleep(0.01) + self.do(du_a+du_b+du_space, du_a+du_b) + self.assertEqual(queue.get(timeout=0.5), du_a+du_b+du_space) + + def test_play_nodelay(self): + keyboard.play(d_a+u_a, 0) + self.do([], d_a+u_a) + def test_play_stash(self): + self.do(d_ctrl) + keyboard.play(d_a+u_a, 0) + self.do([], u_ctrl+d_a+u_a+d_ctrl) + def test_play_delay(self): + last_time = time.time() + events = [make_event(KEY_DOWN, 'a', 1, 100), make_event(KEY_UP, 'a', 1, 100.01)] + keyboard.play(events, 1) + self.do([], d_a+u_a) + self.assertGreater(time.time() - last_time, 0.005) + + def test_get_typed_strings_simple(self): + events = du_a+du_b+du_backspace+d_shift+du_a+u_shift+du_space+du_ctrl+du_a + self.assertEqual(list(keyboard.get_typed_strings(events)), ['aA ', 'a']) + def test_get_typed_strings_backspace(self): + events = du_a+du_b+du_backspace + self.assertEqual(list(keyboard.get_typed_strings(events)), ['a']) + events = du_backspace+du_a+du_b + self.assertEqual(list(keyboard.get_typed_strings(events)), ['ab']) + def test_get_typed_strings_shift(self): + events = d_shift+du_a+du_b+u_shift+du_space+du_ctrl+du_a + self.assertEqual(list(keyboard.get_typed_strings(events)), ['AB ', 'a']) + def test_get_typed_strings_all(self): + events = du_a+du_b+du_backspace+d_shift+du_a+du_capslock+du_b+u_shift+du_space+du_ctrl+du_a + self.assertEqual(list(keyboard.get_typed_strings(events)), ['aAb ', 'A']) + + def test_get_hotkey_name_simple(self): + self.assertEqual(keyboard.get_hotkey_name(['a']), 'a') + def test_get_hotkey_name_modifiers(self): + self.assertEqual(keyboard.get_hotkey_name(['a', 'shift', 'ctrl']), 'ctrl+shift+a') + def test_get_hotkey_name_normalize(self): + self.assertEqual(keyboard.get_hotkey_name(['SHIFT', 'left ctrl']), 'ctrl+shift') + def test_get_hotkey_name_plus(self): + self.assertEqual(keyboard.get_hotkey_name(['+']), 'plus') + def test_get_hotkey_name_duplicated(self): + self.assertEqual(keyboard.get_hotkey_name(['+', 'plus']), 'plus') + def test_get_hotkey_name_full(self): + self.assertEqual(keyboard.get_hotkey_name(['+', 'left ctrl', 'shift', 'WIN', 'right alt']), 'ctrl+alt+shift+windows+plus') + def test_get_hotkey_name_multiple(self): + self.assertEqual(keyboard.get_hotkey_name(['ctrl', 'b', '!', 'a']), 'ctrl+!+a+b') + def test_get_hotkey_name_from_pressed(self): + self.do(du_c+d_ctrl+d_a+d_b) + self.assertEqual(keyboard.get_hotkey_name(), 'ctrl+a+b') + + def test_read_hotkey(self): + queue = keyboard._queue.Queue() + def process(): + queue.put(keyboard.read_hotkey()) + from threading import Thread + t = Thread(target=process) + t.daemon = True + t.start() + time.sleep(0.01) + self.do(d_ctrl+d_a+d_b+u_ctrl) + self.assertEqual(queue.get(timeout=0.5), 'ctrl+a+b') + + def test_read_event(self): + queue = keyboard._queue.Queue() + def process(): + queue.put(keyboard.read_event(suppress=True)) + from threading import Thread + t = Thread(target=process) + t.daemon = True + t.start() + time.sleep(0.01) + self.do(d_a, []) + self.assertEqual(queue.get(timeout=0.5), d_a[0]) + + def test_read_key(self): + queue = keyboard._queue.Queue() + def process(): + queue.put(keyboard.read_key(suppress=True)) + from threading import Thread + t = Thread(target=process) + t.daemon = True + t.start() + time.sleep(0.01) + self.do(d_a, []) + self.assertEqual(queue.get(timeout=0.5), 'a') + + def test_wait_infinite(self): + self.triggered = False + def process(): + keyboard.wait() + self.triggered = True + from threading import Thread + t = Thread(target=process) + t.daemon = True # Yep, we are letting this thread loose. + t.start() + time.sleep(0.01) + self.assertFalse(self.triggered) + + def test_wait_until_success(self): + queue = keyboard._queue.Queue() + def process(): + queue.put(keyboard.wait(queue.get(timeout=0.5), suppress=True) or True) + from threading import Thread + t = Thread(target=process) + t.daemon = True + t.start() + queue.put('a') + time.sleep(0.01) + self.do(d_a, []) + self.assertTrue(queue.get(timeout=0.5)) + def test_wait_until_fail(self): + def process(): + keyboard.wait('a', suppress=True) + self.fail() + from threading import Thread + t = Thread(target=process) + t.daemon = True # Yep, we are letting this thread loose. + t.start() + time.sleep(0.01) + self.do(d_b) + + def test_add_hotkey_single_step_suppress_allow(self): + keyboard.add_hotkey('a', lambda: trigger() or True, suppress=True) + self.do(d_a, triggered_event+d_a) + def test_add_hotkey_single_step_suppress_args_allow(self): + arg = object() + keyboard.add_hotkey('a', lambda a: self.assertIs(a, arg) or trigger() or True, args=(arg,), suppress=True) + self.do(d_a, triggered_event+d_a) + def test_add_hotkey_single_step_suppress_single(self): + keyboard.add_hotkey('a', trigger, suppress=True) + self.do(d_a, triggered_event) + def test_add_hotkey_single_step_suppress_removed(self): + keyboard.remove_hotkey(keyboard.add_hotkey('a', trigger, suppress=True)) + self.do(d_a, d_a) + def test_add_hotkey_single_step_suppress_removed(self): + keyboard.remove_hotkey(keyboard.add_hotkey('ctrl+a', trigger, suppress=True)) + self.do(d_ctrl+d_a, d_ctrl+d_a) + self.assertEqual(keyboard._listener.filtered_modifiers[dummy_keys['left ctrl'][0][0]], 0) + def test_remove_hotkey_internal(self): + remove = keyboard.add_hotkey('shift+a', trigger, suppress=True) + self.assertTrue(all(keyboard._listener.blocking_hotkeys.values())) + self.assertTrue(all(keyboard._listener.filtered_modifiers.values())) + self.assertNotEqual(keyboard._hotkeys, {}) + remove() + self.assertTrue(not any(keyboard._listener.filtered_modifiers.values())) + self.assertTrue(not any(keyboard._listener.blocking_hotkeys.values())) + self.assertEqual(keyboard._hotkeys, {}) + def test_remove_hotkey_internal_multistep_start(self): + remove = keyboard.add_hotkey('shift+a, b', trigger, suppress=True) + self.assertTrue(all(keyboard._listener.blocking_hotkeys.values())) + self.assertTrue(all(keyboard._listener.filtered_modifiers.values())) + self.assertNotEqual(keyboard._hotkeys, {}) + remove() + self.assertTrue(not any(keyboard._listener.filtered_modifiers.values())) + self.assertTrue(not any(keyboard._listener.blocking_hotkeys.values())) + self.assertEqual(keyboard._hotkeys, {}) + def test_remove_hotkey_internal_multistep_end(self): + remove = keyboard.add_hotkey('shift+a, b', trigger, suppress=True) + self.do(d_shift+du_a+u_shift) + self.assertTrue(any(keyboard._listener.blocking_hotkeys.values())) + self.assertTrue(not any(keyboard._listener.filtered_modifiers.values())) + self.assertNotEqual(keyboard._hotkeys, {}) + remove() + self.assertTrue(not any(keyboard._listener.filtered_modifiers.values())) + self.assertTrue(not any(keyboard._listener.blocking_hotkeys.values())) + self.assertEqual(keyboard._hotkeys, {}) + def test_add_hotkey_single_step_suppress_with_modifiers(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+d_a, triggered_event) + def test_add_hotkey_single_step_suppress_with_modifiers_fail_unrelated_modifier(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+u_shift+d_a, d_shift+u_shift+d_ctrl+d_a) + def test_add_hotkey_single_step_suppress_with_modifiers_fail_unrelated_key(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+du_b, d_shift+d_ctrl+du_b) + def test_add_hotkey_single_step_suppress_with_modifiers_unrelated_key(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+du_b+d_a, d_shift+d_ctrl+du_b+triggered_event) + def test_add_hotkey_single_step_suppress_with_modifiers_release(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+du_b+d_a+u_ctrl+u_shift, d_shift+d_ctrl+du_b+triggered_event+u_ctrl+u_shift) + def test_add_hotkey_single_step_suppress_with_modifiers_out_of_order(self): + keyboard.add_hotkey('ctrl+shift+a', trigger, suppress=True) + self.do(d_shift+d_ctrl+d_a, triggered_event) + def test_add_hotkey_single_step_suppress_with_modifiers_repeated(self): + keyboard.add_hotkey('ctrl+a', trigger, suppress=True) + self.do(d_ctrl+du_a+du_b+du_a, triggered_event+d_ctrl+du_b+triggered_event) + def test_add_hotkey_single_step_suppress_with_modifiers_release(self): + keyboard.add_hotkey('ctrl+a', trigger, suppress=True, trigger_on_release=True) + self.do(d_ctrl+du_a+du_b+du_a, triggered_event+d_ctrl+du_b+triggered_event) + def test_add_hotkey_single_step_suppress_with_modifier_superset_release(self): + keyboard.add_hotkey('ctrl+a', trigger, suppress=True, trigger_on_release=True) + self.do(d_ctrl+d_shift+du_a+u_shift+u_ctrl, d_ctrl+d_shift+du_a+u_shift+u_ctrl) + def test_add_hotkey_single_step_suppress_with_modifier_superset(self): + keyboard.add_hotkey('ctrl+a', trigger, suppress=True) + self.do(d_ctrl+d_shift+du_a+u_shift+u_ctrl, d_ctrl+d_shift+du_a+u_shift+u_ctrl) + def test_add_hotkey_single_step_timeout(self): + keyboard.add_hotkey('a', trigger, timeout=1, suppress=True) + self.do(du_a, triggered_event) + def test_add_hotkey_multi_step_first_timeout(self): + keyboard.add_hotkey('a, b', trigger, timeout=0.01, suppress=True) + time.sleep(0.03) + self.do(du_a+du_b, triggered_event) + def test_add_hotkey_multi_step_last_timeout(self): + keyboard.add_hotkey('a, b', trigger, timeout=0.01, suppress=True) + self.do(du_a, []) + time.sleep(0.05) + self.do(du_b, du_a+du_b) + def test_add_hotkey_multi_step_success_timeout(self): + keyboard.add_hotkey('a, b', trigger, timeout=0.05, suppress=True) + self.do(du_a, []) + time.sleep(0.01) + self.do(du_b, triggered_event) + def test_add_hotkey_multi_step_suffix_timeout(self): + keyboard.add_hotkey('a, b, a', trigger, timeout=0.01, suppress=True) + self.do(du_a+du_b, []) + time.sleep(0.05) + self.do(du_a, du_a+du_b) + self.do(du_b+du_a, triggered_event) + def test_add_hotkey_multi_step_allow(self): + keyboard.add_hotkey('a, b', lambda: trigger() or True, suppress=True) + self.do(du_a+du_b, triggered_event+du_a+du_b) + + def test_add_hotkey_single_step_nonsuppress(self): + queue = keyboard._queue.Queue() + keyboard.add_hotkey('ctrl+shift+a+b', lambda: queue.put(True), suppress=False) + self.do(d_shift+d_ctrl+d_a+d_b) + self.assertTrue(queue.get(timeout=0.5)) + def test_add_hotkey_single_step_nonsuppress_repeated(self): + queue = keyboard._queue.Queue() + keyboard.add_hotkey('ctrl+shift+a+b', lambda: queue.put(True), suppress=False) + self.do(d_shift+d_ctrl+d_a+d_b) + self.do(d_shift+d_ctrl+d_a+d_b) + self.assertTrue(queue.get(timeout=0.5)) + self.assertTrue(queue.get(timeout=0.5)) + def test_add_hotkey_single_step_nosuppress_with_modifiers_out_of_order(self): + queue = keyboard._queue.Queue() + keyboard.add_hotkey('ctrl+shift+a', lambda: queue.put(True), suppress=False) + self.do(d_shift+d_ctrl+d_a) + self.assertTrue(queue.get(timeout=0.5)) + def test_add_hotkey_single_step_suppress_regression_1(self): + keyboard.add_hotkey('a', trigger, suppress=True) + self.do(d_c+d_a+u_c+u_a, d_c+d_a+u_c+u_a) + + def test_remap_hotkey_single(self): + keyboard.remap_hotkey('a', 'b') + self.do(d_a+u_a, d_b+u_b) + def test_remap_hotkey_complex_dst(self): + keyboard.remap_hotkey('a', 'ctrl+b, c') + self.do(d_a+u_a, d_ctrl+du_b+u_ctrl+du_c) + def test_remap_hotkey_modifiers(self): + keyboard.remap_hotkey('ctrl+shift+a', 'b') + self.do(d_ctrl+d_shift+d_a+u_a, du_b) + def test_remap_hotkey_modifiers_repeat(self): + keyboard.remap_hotkey('ctrl+shift+a', 'b') + self.do(d_ctrl+d_shift+du_a+du_a, du_b+du_b) + def test_remap_hotkey_modifiers_state(self): + keyboard.remap_hotkey('ctrl+shift+a', 'b') + self.do(d_ctrl+d_shift+du_c+du_a+du_a, d_shift+d_ctrl+du_c+u_shift+u_ctrl+du_b+d_ctrl+d_shift+u_shift+u_ctrl+du_b+d_ctrl+d_shift) + def test_remap_hotkey_release_incomplete(self): + keyboard.remap_hotkey('a', 'b', trigger_on_release=True) + self.do(d_a, []) + def test_remap_hotkey_release_complete(self): + keyboard.remap_hotkey('a', 'b', trigger_on_release=True) + self.do(du_a, du_b) + + def test_parse_hotkey_combinations_scan_code(self): + self.assertEqual(keyboard.parse_hotkey_combinations(30), (((30,),),)) + def test_parse_hotkey_combinations_single(self): + self.assertEqual(keyboard.parse_hotkey_combinations('a'), (((1,),),)) + def test_parse_hotkey_combinations_single_modifier(self): + self.assertEqual(keyboard.parse_hotkey_combinations('shift+a'), (((1, 5), (1, 6)),)) + def test_parse_hotkey_combinations_single_modifiers(self): + self.assertEqual(keyboard.parse_hotkey_combinations('shift+ctrl+a'), (((1, 5, 7), (1, 6, 7)),)) + def test_parse_hotkey_combinations_multi(self): + self.assertEqual(keyboard.parse_hotkey_combinations('a, b'), (((1,),), ((2,),))) + def test_parse_hotkey_combinations_multi_modifier(self): + self.assertEqual(keyboard.parse_hotkey_combinations('shift+a, b'), (((1, 5), (1, 6)), ((2,),))) + def test_parse_hotkey_combinations_list_list(self): + self.assertEqual(keyboard.parse_hotkey_combinations(keyboard.parse_hotkey_combinations('a, b')), keyboard.parse_hotkey_combinations('a, b')) + def test_parse_hotkey_combinations_fail_empty(self): + with self.assertRaises(ValueError): + keyboard.parse_hotkey_combinations('') + + + def test_add_hotkey_multistep_suppress_incomplete(self): + keyboard.add_hotkey('a, b', trigger, suppress=True) + self.do(du_a, []) + self.assertEqual(keyboard._listener.blocking_hotkeys[(1,)], []) + self.assertEqual(len(keyboard._listener.blocking_hotkeys[(2,)]), 1) + def test_add_hotkey_multistep_suppress_incomplete(self): + keyboard.add_hotkey('a, b', trigger, suppress=True) + self.do(du_a+du_b, triggered_event) + def test_add_hotkey_multistep_suppress_modifier(self): + keyboard.add_hotkey('shift+a, b', trigger, suppress=True) + self.do(d_shift+du_a+u_shift+du_b, triggered_event) + def test_add_hotkey_multistep_suppress_fail(self): + keyboard.add_hotkey('a, b', trigger, suppress=True) + self.do(du_a+du_c, du_a+du_c) + def test_add_hotkey_multistep_suppress_three_steps(self): + keyboard.add_hotkey('a, b, c', trigger, suppress=True) + self.do(du_a+du_b+du_c, triggered_event) + def test_add_hotkey_multistep_suppress_repeated_prefix(self): + keyboard.add_hotkey('a, a, c', trigger, suppress=True, trigger_on_release=True) + self.do(du_a+du_a+du_c, triggered_event) + def test_add_hotkey_multistep_suppress_repeated_key(self): + keyboard.add_hotkey('a, b', trigger, suppress=True) + self.do(du_a+du_a+du_b, du_a+triggered_event) + self.assertEqual(keyboard._listener.blocking_hotkeys[(2,)], []) + self.assertEqual(len(keyboard._listener.blocking_hotkeys[(1,)]), 1) + def test_add_hotkey_multi_step_suppress_regression_1(self): + keyboard.add_hotkey('a, b', trigger, suppress=True) + self.do(d_c+d_a+u_c+u_a+du_c, d_c+d_a+u_c+u_a+du_c) + def test_add_hotkey_multi_step_suppress_replays(self): + keyboard.add_hotkey('a, b, c', trigger, suppress=True) + self.do(du_a+du_b+du_a+du_b+du_space, du_a+du_b+du_a+du_b+du_space) + + def test_add_word_listener_success(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free) + self.do(du_a+du_b+du_c+du_space) + self.assertTrue(queue.get(timeout=0.5)) + def test_add_word_listener_no_trigger_fail(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free) + self.do(du_a+du_b+du_c) + with self.assertRaises(keyboard._queue.Empty): + queue.get(timeout=0.01) + def test_add_word_listener_timeout_fail(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free, timeout=1) + self.do(du_a+du_b+du_c+[make_event(KEY_DOWN, name='space', time=2)]) + with self.assertRaises(keyboard._queue.Empty): + queue.get(timeout=0.01) + def test_duplicated_word_listener(self): + keyboard.add_word_listener('abc', trigger) + keyboard.add_word_listener('abc', trigger) + def test_add_word_listener_remove(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free) + keyboard.remove_word_listener('abc') + self.do(du_a+du_b+du_c+du_space) + with self.assertRaises(keyboard._queue.Empty): + queue.get(timeout=0.01) + def test_add_word_listener_suffix_success(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free, match_suffix=True) + self.do(du_a+du_a+du_b+du_c+du_space) + self.assertTrue(queue.get(timeout=0.5)) + def test_add_word_listener_suffix_fail(self): + queue = keyboard._queue.Queue() + def free(): + queue.put(1) + keyboard.add_word_listener('abc', free) + self.do(du_a+du_a+du_b+du_c) + with self.assertRaises(keyboard._queue.Empty): + queue.get(timeout=0.01) + + #def test_add_abbreviation(self): + # keyboard.add_abbreviation('abc', 'aaa') + # self.do(du_a+du_b+du_c+du_space, []) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_event.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_event.py new file mode 100644 index 0000000..38b8961 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_event.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from collections import namedtuple + +LEFT = 'left' +RIGHT = 'right' +MIDDLE = 'middle' +WHEEL = 'wheel' +X = 'x' +X2 = 'x2' + +UP = 'up' +DOWN = 'down' +DOUBLE = 'double' +VERTICAL = 'vertical' +HORIZONTAL = 'horizontal' + + +ButtonEvent = namedtuple('ButtonEvent', ['event_type', 'button', 'time']) +WheelEvent = namedtuple('WheelEvent', ['delta', 'time']) +MoveEvent = namedtuple('MoveEvent', ['x', 'y', 'time']) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_tests.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_tests.py new file mode 100644 index 0000000..6a2b2e4 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_mouse_tests.py @@ -0,0 +1,271 @@ +# -*- coding: utf-8 -*- +import unittest +import time + +from ._mouse_event import MoveEvent, ButtonEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE +from keyboard import mouse + +class FakeOsMouse(object): + def __init__(self): + self.append = None + self.position = (0, 0) + self.queue = None + self.init = lambda: None + + def listen(self, queue): + self.listening = True + self.queue = queue + + def press(self, button): + self.append((DOWN, button)) + + def release(self, button): + self.append((UP, button)) + + def get_position(self): + return self.position + + def move_to(self, x, y): + self.append(('move', (x, y))) + self.position = (x, y) + + def wheel(self, delta): + self.append(('wheel', delta)) + + def move_relative(self, x, y): + self.position = (self.position[0] + x, self.position[1] + y) + +class TestMouse(unittest.TestCase): + @staticmethod + def setUpClass(): + mouse._os_mouse= FakeOsMouse() + mouse._listener.start_if_necessary() + assert mouse._os_mouse.listening + + def setUp(self): + self.events = [] + mouse._pressed_events.clear() + mouse._os_mouse.append = self.events.append + + def tearDown(self): + mouse.unhook_all() + # Make sure there's no spill over between tests. + self.wait_for_events_queue() + + def wait_for_events_queue(self): + mouse._listener.queue.join() + + def flush_events(self): + self.wait_for_events_queue() + events = list(self.events) + # Ugly, but requried to work in Python2. Python3 has list.clear + del self.events[:] + return events + + def press(self, button=LEFT): + mouse._os_mouse.queue.put(ButtonEvent(DOWN, button, time.time())) + self.wait_for_events_queue() + + def release(self, button=LEFT): + mouse._os_mouse.queue.put(ButtonEvent(UP, button, time.time())) + self.wait_for_events_queue() + + def double_click(self, button=LEFT): + mouse._os_mouse.queue.put(ButtonEvent(DOUBLE, button, time.time())) + self.wait_for_events_queue() + + def click(self, button=LEFT): + self.press(button) + self.release(button) + + def wheel(self, delta=1): + mouse._os_mouse.queue.put(WheelEvent(delta, time.time())) + self.wait_for_events_queue() + + def move(self, x=0, y=0): + mouse._os_mouse.queue.put(MoveEvent(x, y, time.time())) + self.wait_for_events_queue() + + def test_hook(self): + events = [] + self.press() + mouse.hook(events.append) + self.press() + mouse.unhook(events.append) + self.press() + self.assertEqual(len(events), 1) + + def test_is_pressed(self): + self.assertFalse(mouse.is_pressed()) + self.press() + self.assertTrue(mouse.is_pressed()) + self.release() + self.press(X2) + self.assertFalse(mouse.is_pressed()) + + self.assertTrue(mouse.is_pressed(X2)) + self.press(X2) + self.assertTrue(mouse.is_pressed(X2)) + self.release(X2) + self.release(X2) + self.assertFalse(mouse.is_pressed(X2)) + + def test_buttons(self): + mouse.press() + self.assertEqual(self.flush_events(), [(DOWN, LEFT)]) + mouse.release() + self.assertEqual(self.flush_events(), [(UP, LEFT)]) + mouse.click() + self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT)]) + mouse.double_click() + self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT), (DOWN, LEFT), (UP, LEFT)]) + mouse.right_click() + self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)]) + mouse.click(RIGHT) + self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)]) + mouse.press(X2) + self.assertEqual(self.flush_events(), [(DOWN, X2)]) + + def test_position(self): + self.assertEqual(mouse.get_position(), mouse._os_mouse.get_position()) + + def test_move(self): + mouse.move(0, 0) + self.assertEqual(mouse._os_mouse.get_position(), (0, 0)) + mouse.move(100, 500) + self.assertEqual(mouse._os_mouse.get_position(), (100, 500)) + mouse.move(1, 2, False) + self.assertEqual(mouse._os_mouse.get_position(), (101, 502)) + + mouse.move(0, 0) + mouse.move(100, 499, True, duration=0.01) + self.assertEqual(mouse._os_mouse.get_position(), (100, 499)) + mouse.move(100, 1, False, duration=0.01) + self.assertEqual(mouse._os_mouse.get_position(), (200, 500)) + mouse.move(0, 0, False, duration=0.01) + self.assertEqual(mouse._os_mouse.get_position(), (200, 500)) + + def triggers(self, fn, events, **kwargs): + self.triggered = False + def callback(): + self.triggered = True + handler = fn(callback, **kwargs) + + for event_type, arg in events: + if event_type == DOWN: + self.press(arg) + elif event_type == UP: + self.release(arg) + elif event_type == DOUBLE: + self.double_click(arg) + elif event_type == 'WHEEL': + self.wheel() + + mouse._listener.remove_handler(handler) + return self.triggered + + def test_on_button(self): + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)])) + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, RIGHT)])) + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, X)])) + + self.assertFalse(self.triggers(mouse.on_button, [('WHEEL', '')])) + + self.assertFalse(self.triggers(mouse.on_button, [(DOWN, X)], buttons=MIDDLE)) + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE)) + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE)) + self.assertFalse(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE, types=UP)) + self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=MIDDLE, types=UP)) + + self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=[MIDDLE, LEFT], types=[UP, DOWN])) + self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)], buttons=[MIDDLE, LEFT], types=[UP, DOWN])) + self.assertFalse(self.triggers(mouse.on_button, [(UP, X)], buttons=[MIDDLE, LEFT], types=[UP, DOWN])) + + def test_ons(self): + self.assertTrue(self.triggers(mouse.on_click, [(UP, LEFT)])) + self.assertFalse(self.triggers(mouse.on_click, [(UP, RIGHT)])) + self.assertFalse(self.triggers(mouse.on_click, [(DOWN, LEFT)])) + self.assertFalse(self.triggers(mouse.on_click, [(DOWN, RIGHT)])) + + self.assertTrue(self.triggers(mouse.on_double_click, [(DOUBLE, LEFT)])) + self.assertFalse(self.triggers(mouse.on_double_click, [(DOUBLE, RIGHT)])) + self.assertFalse(self.triggers(mouse.on_double_click, [(DOWN, RIGHT)])) + + self.assertTrue(self.triggers(mouse.on_right_click, [(UP, RIGHT)])) + self.assertTrue(self.triggers(mouse.on_middle_click, [(UP, MIDDLE)])) + + def test_wait(self): + # If this fails it blocks. Unfortunately, but I see no other way of testing. + from threading import Thread, Lock + lock = Lock() + lock.acquire() + def t(): + mouse.wait() + lock.release() + Thread(target=t).start() + self.press() + lock.acquire() + + def test_record_play(self): + from threading import Thread, Lock + lock = Lock() + lock.acquire() + def t(): + self.recorded = mouse.record(RIGHT) + lock.release() + Thread(target=t).start() + self.click() + self.wheel(5) + self.move(100, 50) + self.press(RIGHT) + lock.acquire() + + self.assertEqual(len(self.recorded), 5) + self.assertEqual(self.recorded[0]._replace(time=None), ButtonEvent(DOWN, LEFT, None)) + self.assertEqual(self.recorded[1]._replace(time=None), ButtonEvent(UP, LEFT, None)) + self.assertEqual(self.recorded[2]._replace(time=None), WheelEvent(5, None)) + self.assertEqual(self.recorded[3]._replace(time=None), MoveEvent(100, 50, None)) + self.assertEqual(self.recorded[4]._replace(time=None), ButtonEvent(DOWN, RIGHT, None)) + + mouse.play(self.recorded, speed_factor=0) + events = self.flush_events() + self.assertEqual(len(events), 5) + self.assertEqual(events[0], (DOWN, LEFT)) + self.assertEqual(events[1], (UP, LEFT)) + self.assertEqual(events[2], ('wheel', 5)) + self.assertEqual(events[3], ('move', (100, 50))) + self.assertEqual(events[4], (DOWN, RIGHT)) + + mouse.play(self.recorded) + events = self.flush_events() + self.assertEqual(len(events), 5) + self.assertEqual(events[0], (DOWN, LEFT)) + self.assertEqual(events[1], (UP, LEFT)) + self.assertEqual(events[2], ('wheel', 5)) + self.assertEqual(events[3], ('move', (100, 50))) + self.assertEqual(events[4], (DOWN, RIGHT)) + + mouse.play(self.recorded, include_clicks=False) + events = self.flush_events() + self.assertEqual(len(events), 2) + self.assertEqual(events[0], ('wheel', 5)) + self.assertEqual(events[1], ('move', (100, 50))) + + mouse.play(self.recorded, include_moves=False) + events = self.flush_events() + self.assertEqual(len(events), 4) + self.assertEqual(events[0], (DOWN, LEFT)) + self.assertEqual(events[1], (UP, LEFT)) + self.assertEqual(events[2], ('wheel', 5)) + self.assertEqual(events[3], (DOWN, RIGHT)) + + mouse.play(self.recorded, include_wheel=False) + events = self.flush_events() + self.assertEqual(len(events), 4) + self.assertEqual(events[0], (DOWN, LEFT)) + self.assertEqual(events[1], (UP, LEFT)) + self.assertEqual(events[2], ('move', (100, 50))) + self.assertEqual(events[3], (DOWN, RIGHT)) + +if __name__ == '__main__': + unittest.main() diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_nixcommon.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixcommon.py new file mode 100644 index 0000000..a4d0d06 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixcommon.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +import struct +import os +import atexit +from time import time as now +from threading import Thread +from glob import glob +try: + from queue import Queue +except ImportError: + from Queue import Queue + +event_bin_format = 'llHHI' + +# Taken from include/linux/input.h +# https://www.kernel.org/doc/Documentation/input/event-codes.txt +EV_SYN = 0x00 +EV_KEY = 0x01 +EV_REL = 0x02 +EV_ABS = 0x03 +EV_MSC = 0x04 + +def make_uinput(): + if not os.path.exists('/dev/uinput'): + raise IOError('No uinput module found.') + + import fcntl, struct + + # Requires uinput driver, but it's usually available. + uinput = open("/dev/uinput", 'wb') + UI_SET_EVBIT = 0x40045564 + fcntl.ioctl(uinput, UI_SET_EVBIT, EV_KEY) + + UI_SET_KEYBIT = 0x40045565 + for i in range(256): + fcntl.ioctl(uinput, UI_SET_KEYBIT, i) + + BUS_USB = 0x03 + uinput_user_dev = "80sHHHHi64i64i64i64i" + axis = [0] * 64 * 4 + uinput.write(struct.pack(uinput_user_dev, b"Virtual Keyboard", BUS_USB, 1, 1, 1, 0, *axis)) + uinput.flush() # Without this you may get Errno 22: Invalid argument. + + UI_DEV_CREATE = 0x5501 + fcntl.ioctl(uinput, UI_DEV_CREATE) + UI_DEV_DESTROY = 0x5502 + #fcntl.ioctl(uinput, UI_DEV_DESTROY) + + return uinput + +class EventDevice(object): + def __init__(self, path): + self.path = path + self._input_file = None + self._output_file = None + + @property + def input_file(self): + if self._input_file is None: + try: + self._input_file = open(self.path, 'rb') + except IOError as e: + if e.strerror == 'Permission denied': + print('Permission denied ({}). You must be sudo to access global events.'.format(self.path)) + exit() + + def try_close(): + try: + self._input_file.close + except: + pass + atexit.register(try_close) + return self._input_file + + @property + def output_file(self): + if self._output_file is None: + self._output_file = open(self.path, 'wb') + atexit.register(self._output_file.close) + return self._output_file + + def read_event(self): + data = self.input_file.read(struct.calcsize(event_bin_format)) + seconds, microseconds, type, code, value = struct.unpack(event_bin_format, data) + return seconds + microseconds / 1e6, type, code, value, self.path + + def write_event(self, type, code, value): + integer, fraction = divmod(now(), 1) + seconds = int(integer) + microseconds = int(fraction * 1e6) + data_event = struct.pack(event_bin_format, seconds, microseconds, type, code, value) + + # Send a sync event to ensure other programs update. + sync_event = struct.pack(event_bin_format, seconds, microseconds, EV_SYN, 0, 0) + + self.output_file.write(data_event + sync_event) + self.output_file.flush() + +class AggregatedEventDevice(object): + def __init__(self, devices, output=None): + self.event_queue = Queue() + self.devices = devices + self.output = output or self.devices[0] + def start_reading(device): + while True: + self.event_queue.put(device.read_event()) + for device in self.devices: + thread = Thread(target=start_reading, args=[device]) + thread.setDaemon(True) + thread.start() + + def read_event(self): + return self.event_queue.get(block=True) + + def write_event(self, type, code, value): + self.output.write_event(type, code, value) + +import re +from collections import namedtuple +DeviceDescription = namedtuple('DeviceDescription', 'event_file is_mouse is_keyboard') +device_pattern = r"""N: Name="([^"]+?)".+?H: Handlers=([^\n]+)""" +def list_devices_from_proc(type_name): + try: + with open('/proc/bus/input/devices') as f: + description = f.read() + except FileNotFoundError: + return + + devices = {} + for name, handlers in re.findall(device_pattern, description, re.DOTALL): + path = '/dev/input/event' + re.search(r'event(\d+)', handlers).group(1) + if type_name in handlers: + yield EventDevice(path) + +def list_devices_from_by_id(name_suffix, by_id=True): + for path in glob('/dev/input/{}/*-event-{}'.format('by-id' if by_id else 'by-path', name_suffix)): + yield EventDevice(path) + +def aggregate_devices(type_name): + # Some systems have multiple keyboards with different range of allowed keys + # on each one, like a notebook with a "keyboard" device exclusive for the + # power button. Instead of figuring out which keyboard allows which key to + # send events, we create a fake device and send all events through there. + try: + uinput = make_uinput() + fake_device = EventDevice('uinput Fake Device') + fake_device._input_file = uinput + fake_device._output_file = uinput + except IOError as e: + import warnings + warnings.warn('Failed to create a device file using `uinput` module. Sending of events may be limited or unavailable depending on plugged-in devices.', stacklevel=2) + fake_device = None + + # We don't aggregate devices from different sources to avoid + # duplicates. + + devices_from_proc = list(list_devices_from_proc(type_name)) + if devices_from_proc: + return AggregatedEventDevice(devices_from_proc, output=fake_device) + + # breaks on mouse for virtualbox + # was getting /dev/input/by-id/usb-VirtualBox_USB_Tablet-event-mouse + devices_from_by_id = list(list_devices_from_by_id(type_name)) or list(list_devices_from_by_id(type_name, by_id=False)) + if devices_from_by_id: + return AggregatedEventDevice(devices_from_by_id, output=fake_device) + + # If no keyboards were found we can only use the fake device to send keys. + assert fake_device + return fake_device + + +def ensure_root(): + if os.geteuid() != 0: + raise ImportError('You must be root to use this library on linux.') diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_nixkeyboard.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixkeyboard.py new file mode 100644 index 0000000..d3950a1 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixkeyboard.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +import struct +import traceback +from time import time as now +from collections import namedtuple +from ._keyboard_event import KeyboardEvent, KEY_DOWN, KEY_UP +from ._canonical_names import all_modifiers, normalize_name +from ._nixcommon import EV_KEY, aggregate_devices, ensure_root + +# TODO: start by reading current keyboard state, as to not missing any already pressed keys. +# See: http://stackoverflow.com/questions/3649874/how-to-get-keyboard-state-in-linux + +def cleanup_key(name): + """ Formats a dumpkeys format to our standard. """ + name = name.lstrip('+') + is_keypad = name.startswith('KP_') + for mod in ('Meta_', 'Control_', 'dead_', 'KP_'): + if name.startswith(mod): + name = name[len(mod):] + + # Dumpkeys is weird like that. + if name == 'Remove': + name = 'Delete' + elif name == 'Delete': + name = 'Backspace' + + if name.endswith('_r'): + name = 'right ' + name[:-2] + if name.endswith('_l'): + name = 'left ' + name[:-2] + + + return normalize_name(name), is_keypad + +def cleanup_modifier(modifier): + modifier = normalize_name(modifier) + if modifier in all_modifiers: + return modifier + if modifier[:-1] in all_modifiers: + return modifier[:-1] + raise ValueError('Unknown modifier {}'.format(modifier)) + +""" +Use `dumpkeys --keys-only` to list all scan codes and their names. We +then parse the output and built a table. For each scan code and modifiers we +have a list of names and vice-versa. +""" +from subprocess import check_output +from collections import defaultdict +import re + +to_name = defaultdict(list) +from_name = defaultdict(list) +keypad_scan_codes = set() + +def register_key(key_and_modifiers, name): + if name not in to_name[key_and_modifiers]: + to_name[key_and_modifiers].append(name) + if key_and_modifiers not in from_name[name]: + from_name[name].append(key_and_modifiers) + +def build_tables(): + if to_name and from_name: return + ensure_root() + + modifiers_bits = { + 'shift': 1, + 'alt gr': 2, + 'ctrl': 4, + 'alt': 8, + } + keycode_template = r'^keycode\s+(\d+)\s+=(.*?)$' + dump = check_output(['dumpkeys', '--keys-only'], universal_newlines=True) + for str_scan_code, str_names in re.findall(keycode_template, dump, re.MULTILINE): + scan_code = int(str_scan_code) + for i, str_name in enumerate(str_names.strip().split()): + modifiers = tuple(sorted(modifier for modifier, bit in modifiers_bits.items() if i & bit)) + name, is_keypad = cleanup_key(str_name) + register_key((scan_code, modifiers), name) + if is_keypad: + keypad_scan_codes.add(scan_code) + register_key((scan_code, modifiers), 'keypad ' + name) + + # dumpkeys consistently misreports the Windows key, sometimes + # skipping it completely or reporting as 'alt. 125 = left win, + # 126 = right win. + if (125, ()) not in to_name or to_name[(125, ())] == 'alt': + register_key((125, ()), 'windows') + if (126, ()) not in to_name or to_name[(126, ())] == 'alt': + register_key((126, ()), 'windows') + + # The menu key is usually skipped altogether, so we also add it manually. + if (127, ()) not in to_name: + register_key((127, ()), 'menu') + + synonyms_template = r'^(\S+)\s+for (.+)$' + dump = check_output(['dumpkeys', '--long-info'], universal_newlines=True) + for synonym_str, original_str in re.findall(synonyms_template, dump, re.MULTILINE): + synonym, _ = cleanup_key(synonym_str) + original, _ = cleanup_key(original_str) + if synonym != original: + from_name[original].extend(from_name[synonym]) + from_name[synonym].extend(from_name[original]) + +device = None +def build_device(): + global device + if device: return + ensure_root() + device = aggregate_devices('kbd') + +def init(): + build_device() + build_tables() + +pressed_modifiers = set() + +def listen(callback): + build_device() + build_tables() + + while True: + time, type, code, value, device_id = device.read_event() + if type != EV_KEY: + continue + + scan_code = code + event_type = KEY_DOWN if value else KEY_UP # 0 = UP, 1 = DOWN, 2 = HOLD + + pressed_modifiers_tuple = tuple(sorted(pressed_modifiers)) + names = to_name[(scan_code, pressed_modifiers_tuple)] or to_name[(scan_code, ())] or ['unknown'] + name = names[0] + + if name in all_modifiers: + if event_type == KEY_DOWN: + pressed_modifiers.add(name) + else: + pressed_modifiers.discard(name) + + is_keypad = scan_code in keypad_scan_codes + callback(KeyboardEvent(event_type=event_type, scan_code=scan_code, name=name, time=time, device=device_id, is_keypad=is_keypad, modifiers=pressed_modifiers_tuple)) + +def write_event(scan_code, is_down): + build_device() + device.write_event(EV_KEY, scan_code, int(is_down)) + +def map_name(name): + build_tables() + for entry in from_name[name]: + yield entry + + parts = name.split(' ', 1) + if len(parts) > 1 and parts[0] in ('left', 'right'): + for entry in from_name[parts[1]]: + yield entry + +def press(scan_code): + write_event(scan_code, True) + +def release(scan_code): + write_event(scan_code, False) + +def type_unicode(character): + codepoint = ord(character) + hexadecimal = hex(codepoint)[len('0x'):] + + for key in ['ctrl', 'shift', 'u']: + scan_code, _ = next(map_name(key)) + press(scan_code) + + for key in hexadecimal: + scan_code, _ = next(map_name(key)) + press(scan_code) + release(scan_code) + + for key in ['ctrl', 'shift', 'u']: + scan_code, _ = next(map_name(key)) + release(scan_code) + +if __name__ == '__main__': + def p(e): + print(e) + listen(p) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_nixmouse.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixmouse.py new file mode 100644 index 0000000..6b02c57 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_nixmouse.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +import struct +from subprocess import check_output +import re +from ._nixcommon import EV_KEY, EV_REL, EV_MSC, EV_SYN, EV_ABS, aggregate_devices, ensure_root +from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN + +import ctypes +import ctypes.util +from ctypes import c_uint32, c_uint, c_int, byref + +display = None +window = None +x11 = None +def build_display(): + global display, window, x11 + if display and window and x11: return + x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library('X11')) + # Required because we will have multiple threads calling x11, + # such as the listener thread and then main using "move_to". + x11.XInitThreads() + display = x11.XOpenDisplay(None) + # Known to cause segfault in Fedora 23 64bits, no known workarounds. + # http://stackoverflow.com/questions/35137007/get-mouse-position-on-linux-pure-python + window = x11.XDefaultRootWindow(display) + +def get_position(): + build_display() + root_id, child_id = c_uint32(), c_uint32() + root_x, root_y, win_x, win_y = c_int(), c_int(), c_int(), c_int() + mask = c_uint() + ret = x11.XQueryPointer(display, c_uint32(window), byref(root_id), byref(child_id), + byref(root_x), byref(root_y), + byref(win_x), byref(win_y), byref(mask)) + return root_x.value, root_y.value + +def move_to(x, y): + build_display() + x11.XWarpPointer(display, None, window, 0, 0, 0, 0, x, y) + x11.XFlush(display) + +REL_X = 0x00 +REL_Y = 0x01 +REL_Z = 0x02 +REL_HWHEEL = 0x06 +REL_WHEEL = 0x08 + +ABS_X = 0x00 +ABS_Y = 0x01 + +BTN_MOUSE = 0x110 +BTN_LEFT = 0x110 +BTN_RIGHT = 0x111 +BTN_MIDDLE = 0x112 +BTN_SIDE = 0x113 +BTN_EXTRA = 0x114 + +button_by_code = { + BTN_LEFT: LEFT, + BTN_RIGHT: RIGHT, + BTN_MIDDLE: MIDDLE, + BTN_SIDE: X, + BTN_EXTRA: X2, +} +code_by_button = {button: code for code, button in button_by_code.items()} + +device = None +def build_device(): + global device + if device: return + ensure_root() + device = aggregate_devices('mouse') +init = build_device + +def listen(queue): + build_device() + + while True: + time, type, code, value, device_id = device.read_event() + if type == EV_SYN or type == EV_MSC: + continue + + event = None + arg = None + + if type == EV_KEY: + event = ButtonEvent(DOWN if value else UP, button_by_code.get(code, '?'), time) + elif type == EV_REL: + value, = struct.unpack('i', struct.pack('I', value)) + + if code == REL_WHEEL: + event = WheelEvent(value, time) + elif code in (REL_X, REL_Y): + x, y = get_position() + event = MoveEvent(x, y, time) + + if event is None: + # Unknown event type. + continue + + queue.put(event) + +def press(button=LEFT): + build_device() + device.write_event(EV_KEY, code_by_button[button], 0x01) + +def release(button=LEFT): + build_device() + device.write_event(EV_KEY, code_by_button[button], 0x00) + +def move_relative(x, y): + build_device() + # Note relative events are not in terms of pixels, but millimeters. + if x < 0: + x += 2**32 + if y < 0: + y += 2**32 + device.write_event(EV_REL, REL_X, x) + device.write_event(EV_REL, REL_Y, y) + +def wheel(delta=1): + build_device() + if delta < 0: + delta += 2**32 + device.write_event(EV_REL, REL_WHEEL, delta) + + +if __name__ == '__main__': + #listen(print) + move_to(100, 200) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_winkeyboard.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_winkeyboard.py new file mode 100644 index 0000000..8e310a4 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_winkeyboard.py @@ -0,0 +1,620 @@ +# -*- coding: utf-8 -*- +""" +This is the Windows backend for keyboard events, and is implemented by +invoking the Win32 API through the ctypes module. This is error prone +and can introduce very unpythonic failure modes, such as segfaults and +low level memory leaks. But it is also dependency-free, very performant +well documented on Microsoft's website and scattered examples. + +# TODO: +- Keypad numbers still print as numbers even when numlock is off. +- No way to specify if user wants a keypad key or not in `map_char`. +""" +from __future__ import unicode_literals +import re +import atexit +import traceback +from threading import Lock +from collections import defaultdict + +from ._keyboard_event import KeyboardEvent, KEY_DOWN, KEY_UP +from ._canonical_names import normalize_name +try: + # Force Python2 to convert to unicode and not to str. + chr = unichr +except NameError: + pass + +# This part is just declaring Win32 API structures using ctypes. In C +# this would be simply #include "windows.h". + +import ctypes +from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, Structure, CFUNCTYPE, POINTER +from ctypes.wintypes import WORD, DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM, LONG, HMODULE, LPCWSTR, HINSTANCE, HWND +LPMSG = POINTER(MSG) +ULONG_PTR = POINTER(DWORD) + +kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) +GetModuleHandleW = kernel32.GetModuleHandleW +GetModuleHandleW.restype = HMODULE +GetModuleHandleW.argtypes = [LPCWSTR] + +#https://github.com/boppreh/mouse/issues/1 +#user32 = ctypes.windll.user32 +user32 = ctypes.WinDLL('user32', use_last_error = True) + +VK_PACKET = 0xE7 + +INPUT_MOUSE = 0 +INPUT_KEYBOARD = 1 +INPUT_HARDWARE = 2 + +KEYEVENTF_KEYUP = 0x02 +KEYEVENTF_UNICODE = 0x04 + +class KBDLLHOOKSTRUCT(Structure): + _fields_ = [("vk_code", DWORD), + ("scan_code", DWORD), + ("flags", DWORD), + ("time", c_int), + ("dwExtraInfo", ULONG_PTR)] + +# Included for completeness. +class MOUSEINPUT(ctypes.Structure): + _fields_ = (('dx', LONG), + ('dy', LONG), + ('mouseData', DWORD), + ('dwFlags', DWORD), + ('time', DWORD), + ('dwExtraInfo', ULONG_PTR)) + +class KEYBDINPUT(ctypes.Structure): + _fields_ = (('wVk', WORD), + ('wScan', WORD), + ('dwFlags', DWORD), + ('time', DWORD), + ('dwExtraInfo', ULONG_PTR)) + +class HARDWAREINPUT(ctypes.Structure): + _fields_ = (('uMsg', DWORD), + ('wParamL', WORD), + ('wParamH', WORD)) + +class _INPUTunion(ctypes.Union): + _fields_ = (('mi', MOUSEINPUT), + ('ki', KEYBDINPUT), + ('hi', HARDWAREINPUT)) + +class INPUT(ctypes.Structure): + _fields_ = (('type', DWORD), + ('union', _INPUTunion)) + +LowLevelKeyboardProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(KBDLLHOOKSTRUCT)) + +SetWindowsHookEx = user32.SetWindowsHookExW +SetWindowsHookEx.argtypes = [c_int, LowLevelKeyboardProc, HINSTANCE , DWORD] +SetWindowsHookEx.restype = HHOOK + +CallNextHookEx = user32.CallNextHookEx +#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(KBDLLHOOKSTRUCT)] +CallNextHookEx.restype = c_int + +UnhookWindowsHookEx = user32.UnhookWindowsHookEx +UnhookWindowsHookEx.argtypes = [HHOOK] +UnhookWindowsHookEx.restype = BOOL + +GetMessage = user32.GetMessageW +GetMessage.argtypes = [LPMSG, HWND, c_uint, c_uint] +GetMessage.restype = BOOL + +TranslateMessage = user32.TranslateMessage +TranslateMessage.argtypes = [LPMSG] +TranslateMessage.restype = BOOL + +DispatchMessage = user32.DispatchMessageA +DispatchMessage.argtypes = [LPMSG] + + +keyboard_state_type = c_uint8 * 256 + +GetKeyboardState = user32.GetKeyboardState +GetKeyboardState.argtypes = [keyboard_state_type] +GetKeyboardState.restype = BOOL + +GetKeyNameText = user32.GetKeyNameTextW +GetKeyNameText.argtypes = [c_long, LPWSTR, c_int] +GetKeyNameText.restype = c_int + +MapVirtualKey = user32.MapVirtualKeyW +MapVirtualKey.argtypes = [c_uint, c_uint] +MapVirtualKey.restype = c_uint + +ToUnicode = user32.ToUnicode +ToUnicode.argtypes = [c_uint, c_uint, keyboard_state_type, LPWSTR, c_int, c_uint] +ToUnicode.restype = c_int + +SendInput = user32.SendInput +SendInput.argtypes = [c_uint, POINTER(INPUT), c_int] +SendInput.restype = c_uint + +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms646307(v=vs.85).aspx +MAPVK_VK_TO_CHAR = 2 +MAPVK_VK_TO_VSC = 0 +MAPVK_VSC_TO_VK = 1 +MAPVK_VK_TO_VSC_EX = 4 +MAPVK_VSC_TO_VK_EX = 3 + +VkKeyScan = user32.VkKeyScanW +VkKeyScan.argtypes = [WCHAR] +VkKeyScan.restype = c_short + +LLKHF_INJECTED = 0x00000010 + +WM_KEYDOWN = 0x0100 +WM_KEYUP = 0x0101 +WM_SYSKEYDOWN = 0x104 # Used for ALT key +WM_SYSKEYUP = 0x105 + + +# This marks the end of Win32 API declarations. The rest is ours. + +keyboard_event_types = { + WM_KEYDOWN: KEY_DOWN, + WM_KEYUP: KEY_UP, + WM_SYSKEYDOWN: KEY_DOWN, + WM_SYSKEYUP: KEY_UP, +} + +# List taken from the official documentation, but stripped of the OEM-specific keys. +# Keys are virtual key codes, values are pairs (name, is_keypad). +official_virtual_keys = { + 0x03: ('control-break processing', False), + 0x08: ('backspace', False), + 0x09: ('tab', False), + 0x0c: ('clear', False), + 0x0d: ('enter', False), + 0x10: ('shift', False), + 0x11: ('ctrl', False), + 0x12: ('alt', False), + 0x13: ('pause', False), + 0x14: ('caps lock', False), + 0x15: ('ime kana mode', False), + 0x15: ('ime hanguel mode', False), + 0x15: ('ime hangul mode', False), + 0x17: ('ime junja mode', False), + 0x18: ('ime final mode', False), + 0x19: ('ime hanja mode', False), + 0x19: ('ime kanji mode', False), + 0x1b: ('esc', False), + 0x1c: ('ime convert', False), + 0x1d: ('ime nonconvert', False), + 0x1e: ('ime accept', False), + 0x1f: ('ime mode change request', False), + 0x20: ('spacebar', False), + 0x21: ('page up', False), + 0x22: ('page down', False), + 0x23: ('end', False), + 0x24: ('home', False), + 0x25: ('left', False), + 0x26: ('up', False), + 0x27: ('right', False), + 0x28: ('down', False), + 0x29: ('select', False), + 0x2a: ('print', False), + 0x2b: ('execute', False), + 0x2c: ('print screen', False), + 0x2d: ('insert', False), + 0x2e: ('delete', False), + 0x2f: ('help', False), + 0x30: ('0', False), + 0x31: ('1', False), + 0x32: ('2', False), + 0x33: ('3', False), + 0x34: ('4', False), + 0x35: ('5', False), + 0x36: ('6', False), + 0x37: ('7', False), + 0x38: ('8', False), + 0x39: ('9', False), + 0x41: ('a', False), + 0x42: ('b', False), + 0x43: ('c', False), + 0x44: ('d', False), + 0x45: ('e', False), + 0x46: ('f', False), + 0x47: ('g', False), + 0x48: ('h', False), + 0x49: ('i', False), + 0x4a: ('j', False), + 0x4b: ('k', False), + 0x4c: ('l', False), + 0x4d: ('m', False), + 0x4e: ('n', False), + 0x4f: ('o', False), + 0x50: ('p', False), + 0x51: ('q', False), + 0x52: ('r', False), + 0x53: ('s', False), + 0x54: ('t', False), + 0x55: ('u', False), + 0x56: ('v', False), + 0x57: ('w', False), + 0x58: ('x', False), + 0x59: ('y', False), + 0x5a: ('z', False), + 0x5b: ('left windows', False), + 0x5c: ('right windows', False), + 0x5d: ('applications', False), + 0x5f: ('sleep', False), + 0x60: ('0', True), + 0x61: ('1', True), + 0x62: ('2', True), + 0x63: ('3', True), + 0x64: ('4', True), + 0x65: ('5', True), + 0x66: ('6', True), + 0x67: ('7', True), + 0x68: ('8', True), + 0x69: ('9', True), + 0x6a: ('*', True), + 0x6b: ('+', True), + 0x6c: ('separator', True), + 0x6d: ('-', True), + 0x6e: ('decimal', True), + 0x6f: ('/', True), + 0x70: ('f1', False), + 0x71: ('f2', False), + 0x72: ('f3', False), + 0x73: ('f4', False), + 0x74: ('f5', False), + 0x75: ('f6', False), + 0x76: ('f7', False), + 0x77: ('f8', False), + 0x78: ('f9', False), + 0x79: ('f10', False), + 0x7a: ('f11', False), + 0x7b: ('f12', False), + 0x7c: ('f13', False), + 0x7d: ('f14', False), + 0x7e: ('f15', False), + 0x7f: ('f16', False), + 0x80: ('f17', False), + 0x81: ('f18', False), + 0x82: ('f19', False), + 0x83: ('f20', False), + 0x84: ('f21', False), + 0x85: ('f22', False), + 0x86: ('f23', False), + 0x87: ('f24', False), + 0x90: ('num lock', False), + 0x91: ('scroll lock', False), + 0xa0: ('left shift', False), + 0xa1: ('right shift', False), + 0xa2: ('left ctrl', False), + 0xa3: ('right ctrl', False), + 0xa4: ('left menu', False), + 0xa5: ('right menu', False), + 0xa6: ('browser back', False), + 0xa7: ('browser forward', False), + 0xa8: ('browser refresh', False), + 0xa9: ('browser stop', False), + 0xaa: ('browser search key', False), + 0xab: ('browser favorites', False), + 0xac: ('browser start and home', False), + 0xad: ('volume mute', False), + 0xae: ('volume down', False), + 0xaf: ('volume up', False), + 0xb0: ('next track', False), + 0xb1: ('previous track', False), + 0xb2: ('stop media', False), + 0xb3: ('play/pause media', False), + 0xb4: ('start mail', False), + 0xb5: ('select media', False), + 0xb6: ('start application 1', False), + 0xb7: ('start application 2', False), + 0xbb: ('+', False), + 0xbc: (',', False), + 0xbd: ('-', False), + 0xbe: ('.', False), + #0xbe:('/', False), # Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?. + 0xe5: ('ime process', False), + 0xf6: ('attn', False), + 0xf7: ('crsel', False), + 0xf8: ('exsel', False), + 0xf9: ('erase eof', False), + 0xfa: ('play', False), + 0xfb: ('zoom', False), + 0xfc: ('reserved ', False), + 0xfd: ('pa1', False), + 0xfe: ('clear', False), +} + +tables_lock = Lock() +to_name = defaultdict(list) +from_name = defaultdict(list) +scan_code_to_vk = {} + +distinct_modifiers = [ + (), + ('shift',), + ('alt gr',), + ('num lock',), + ('shift', 'num lock'), + ('caps lock',), + ('shift', 'caps lock'), + ('alt gr', 'num lock'), +] + +name_buffer = ctypes.create_unicode_buffer(32) +unicode_buffer = ctypes.create_unicode_buffer(32) +keyboard_state = keyboard_state_type() +def get_event_names(scan_code, vk, is_extended, modifiers): + is_keypad = (scan_code, vk, is_extended) in keypad_keys + is_official = vk in official_virtual_keys + if is_keypad and is_official: + yield official_virtual_keys[vk][0] + + keyboard_state[0x10] = 0x80 * ('shift' in modifiers) + keyboard_state[0x11] = 0x80 * ('alt gr' in modifiers) + keyboard_state[0x12] = 0x80 * ('alt gr' in modifiers) + keyboard_state[0x14] = 0x01 * ('caps lock' in modifiers) + keyboard_state[0x90] = 0x01 * ('num lock' in modifiers) + keyboard_state[0x91] = 0x01 * ('scroll lock' in modifiers) + unicode_ret = ToUnicode(vk, scan_code, keyboard_state, unicode_buffer, len(unicode_buffer), 0) + if unicode_ret and unicode_buffer.value: + yield unicode_buffer.value + # unicode_ret == -1 -> is dead key + # ToUnicode has the side effect of setting global flags for dead keys. + # Therefore we need to call it twice to clear those flags. + # If your 6 and 7 keys are named "^6" and "^7", this is the reason. + ToUnicode(vk, scan_code, keyboard_state, unicode_buffer, len(unicode_buffer), 0) + + name_ret = GetKeyNameText(scan_code << 16 | is_extended << 24, name_buffer, 1024) + if name_ret and name_buffer.value: + yield name_buffer.value + + char = user32.MapVirtualKeyW(vk, MAPVK_VK_TO_CHAR) & 0xFF + if char != 0: + yield chr(char) + + if not is_keypad and is_official: + yield official_virtual_keys[vk][0] + +def _setup_name_tables(): + """ + Ensures the scan code/virtual key code/name translation tables are + filled. + """ + with tables_lock: + if to_name: return + + # Go through every possible scan code, and map them to virtual key codes. + # Then vice-versa. + all_scan_codes = [(sc, user32.MapVirtualKeyExW(sc, MAPVK_VSC_TO_VK_EX, 0)) for sc in range(0x100)] + all_vks = [(user32.MapVirtualKeyExW(vk, MAPVK_VK_TO_VSC_EX, 0), vk) for vk in range(0x100)] + for scan_code, vk in all_scan_codes + all_vks: + # `to_name` and `from_name` entries will be a tuple (scan_code, vk, extended, shift_state). + if (scan_code, vk, 0, 0, 0) in to_name: + continue + + if scan_code not in scan_code_to_vk: + scan_code_to_vk[scan_code] = vk + + # Brute force all combinations to find all possible names. + for extended in [0, 1]: + for modifiers in distinct_modifiers: + entry = (scan_code, vk, extended, modifiers) + # Get key names from ToUnicode, GetKeyNameText, MapVirtualKeyW and official virtual keys. + names = list(get_event_names(*entry)) + if names: + # Also map lowercased key names, but only after the properly cased ones. + lowercase_names = [name.lower() for name in names] + to_name[entry] = names + lowercase_names + # Remember the "id" of the name, as the first techniques + # have better results and therefore priority. + for i, name in enumerate(map(normalize_name, names + lowercase_names)): + from_name[name].append((i, entry)) + + # TODO: single quotes on US INTL is returning the dead key (?), and therefore + # not typing properly. + + # Alt gr is way outside the usual range of keys (0..127) and on my + # computer is named as 'ctrl'. Therefore we add it manually and hope + # Windows is consistent in its inconsistency. + for extended in [0, 1]: + for modifiers in distinct_modifiers: + to_name[(541, 162, extended, modifiers)] = ['alt gr'] + from_name['alt gr'].append((1, (541, 162, extended, modifiers))) + + modifiers_preference = defaultdict(lambda: 10) + modifiers_preference.update({(): 0, ('shift',): 1, ('alt gr',): 2, ('ctrl',): 3, ('alt',): 4}) + def order_key(line): + i, entry = line + scan_code, vk, extended, modifiers = entry + return modifiers_preference[modifiers], i, extended, vk, scan_code + for name, entries in list(from_name.items()): + from_name[name] = sorted(set(entries), key=order_key) + +# Called by keyboard/__init__.py +init = _setup_name_tables + +# List created manually. +keypad_keys = [ + # (scan_code, virtual_key_code, is_extended) + (126, 194, 0), + (126, 194, 0), + (28, 13, 1), + (28, 13, 1), + (53, 111, 1), + (53, 111, 1), + (55, 106, 0), + (55, 106, 0), + (69, 144, 1), + (69, 144, 1), + (71, 103, 0), + (71, 36, 0), + (72, 104, 0), + (72, 38, 0), + (73, 105, 0), + (73, 33, 0), + (74, 109, 0), + (74, 109, 0), + (75, 100, 0), + (75, 37, 0), + (76, 101, 0), + (76, 12, 0), + (77, 102, 0), + (77, 39, 0), + (78, 107, 0), + (78, 107, 0), + (79, 35, 0), + (79, 97, 0), + (80, 40, 0), + (80, 98, 0), + (81, 34, 0), + (81, 99, 0), + (82, 45, 0), + (82, 96, 0), + (83, 110, 0), + (83, 46, 0), +] + +shift_is_pressed = False +altgr_is_pressed = False +ignore_next_right_alt = False +shift_vks = set([0x10, 0xa0, 0xa1]) +def prepare_intercept(callback): + """ + Registers a Windows low level keyboard hook. The provided callback will + be invoked for each high-level keyboard event, and is expected to return + True if the key event should be passed to the next program, or False if + the event is to be blocked. + + No event is processed until the Windows messages are pumped (see + start_intercept). + """ + _setup_name_tables() + + def process_key(event_type, vk, scan_code, is_extended): + global shift_is_pressed, altgr_is_pressed, ignore_next_right_alt + #print(event_type, vk, scan_code, is_extended) + + # Pressing alt-gr also generates an extra "right alt" event + if vk == 0xA5 and ignore_next_right_alt: + ignore_next_right_alt = False + return True + + modifiers = ( + ('shift',) * shift_is_pressed + + ('alt gr',) * altgr_is_pressed + + ('num lock',) * (user32.GetKeyState(0x90) & 1) + + ('caps lock',) * (user32.GetKeyState(0x14) & 1) + + ('scroll lock',) * (user32.GetKeyState(0x91) & 1) + ) + entry = (scan_code, vk, is_extended, modifiers) + if entry not in to_name: + to_name[entry] = list(get_event_names(*entry)) + + names = to_name[entry] + name = names[0] if names else None + + # TODO: inaccurate when holding multiple different shifts. + if vk in shift_vks: + shift_is_pressed = event_type == KEY_DOWN + if scan_code == 541 and vk == 162: + ignore_next_right_alt = True + altgr_is_pressed = event_type == KEY_DOWN + + is_keypad = (scan_code, vk, is_extended) in keypad_keys + return callback(KeyboardEvent(event_type=event_type, scan_code=scan_code or -vk, name=name, is_keypad=is_keypad)) + + def low_level_keyboard_handler(nCode, wParam, lParam): + try: + vk = lParam.contents.vk_code + # Ignore the second `alt` DOWN observed in some cases. + fake_alt = (LLKHF_INJECTED | 0x20) + # Ignore events generated by SendInput with Unicode. + if vk != VK_PACKET and lParam.contents.flags & fake_alt != fake_alt: + event_type = keyboard_event_types[wParam] + is_extended = lParam.contents.flags & 1 + scan_code = lParam.contents.scan_code + should_continue = process_key(event_type, vk, scan_code, is_extended) + if not should_continue: + return -1 + except Exception as e: + print('Error in keyboard hook:') + traceback.print_exc() + + return CallNextHookEx(None, nCode, wParam, lParam) + + WH_KEYBOARD_LL = c_int(13) + keyboard_callback = LowLevelKeyboardProc(low_level_keyboard_handler) + handle = GetModuleHandleW(None) + thread_id = DWORD(0) + keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_callback, handle, thread_id) + + # Register to remove the hook when the interpreter exits. Unfortunately a + # try/finally block doesn't seem to work here. + atexit.register(UnhookWindowsHookEx, keyboard_callback) + +def listen(callback): + prepare_intercept(callback) + msg = LPMSG() + while not GetMessage(msg, 0, 0, 0): + TranslateMessage(msg) + DispatchMessage(msg) + +def map_name(name): + _setup_name_tables() + + entries = from_name.get(name) + if not entries: + raise ValueError('Key name {} is not mapped to any known key.'.format(repr(name))) + for i, entry in entries: + scan_code, vk, is_extended, modifiers = entry + yield scan_code or -vk, modifiers + +def _send_event(code, event_type): + if code == 541: + # Alt-gr is made of ctrl+alt. Just sending even 541 doesn't do anything. + user32.keybd_event(0x11, code, event_type, 0) + user32.keybd_event(0x12, code, event_type, 0) + elif code > 0: + vk = scan_code_to_vk.get(code, 0) + user32.keybd_event(vk, code, event_type, 0) + else: + # Negative scan code is a way to indicate we don't have a scan code, + # and the value actually contains the Virtual key code. + user32.keybd_event(-code, 0, event_type, 0) + +def press(code): + _send_event(code, 0) + +def release(code): + _send_event(code, 2) + +def type_unicode(character): + # This code and related structures are based on + # http://stackoverflow.com/a/11910555/252218 + surrogates = bytearray(character.encode('utf-16le')) + presses = [] + releases = [] + for i in range(0, len(surrogates), 2): + higher, lower = surrogates[i:i+2] + structure = KEYBDINPUT(0, (lower << 8) + higher, KEYEVENTF_UNICODE, 0, None) + presses.append(INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))) + structure = KEYBDINPUT(0, (lower << 8) + higher, KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, None) + releases.append(INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))) + inputs = presses + releases + nInputs = len(inputs) + LPINPUT = INPUT * nInputs + pInputs = LPINPUT(*inputs) + cbSize = c_int(ctypes.sizeof(INPUT)) + SendInput(nInputs, pInputs, cbSize) + +if __name__ == '__main__': + _setup_name_tables() + import pprint + pprint.pprint(to_name) + pprint.pprint(from_name) + #listen(lambda e: print(e.to_json()) or True) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/_winmouse.py b/CLI/venv/lib/python3.12/site-packages/keyboard/_winmouse.py new file mode 100644 index 0000000..ef16dd4 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/_winmouse.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +import ctypes +import time +from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER +from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM +LPMSG = POINTER(MSG) + +import atexit + +from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE, WHEEL, HORIZONTAL, VERTICAL + +#https://github.com/boppreh/mouse/issues/1 +#user32 = ctypes.windll.user32 +user32 = ctypes.WinDLL('user32', use_last_error = True) + +class MSLLHOOKSTRUCT(Structure): + _fields_ = [("x", c_long), + ("y", c_long), + ('data', c_int32), + ('reserved', c_int32), + ("flags", DWORD), + ("time", c_int), + ] + +LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT)) + +SetWindowsHookEx = user32.SetWindowsHookExA +#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int] +SetWindowsHookEx.restype = HHOOK + +CallNextHookEx = user32.CallNextHookEx +#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)] +CallNextHookEx.restype = c_int + +UnhookWindowsHookEx = user32.UnhookWindowsHookEx +UnhookWindowsHookEx.argtypes = [HHOOK] +UnhookWindowsHookEx.restype = BOOL + +GetMessage = user32.GetMessageW +GetMessage.argtypes = [LPMSG, c_int, c_int, c_int] +GetMessage.restype = BOOL + +TranslateMessage = user32.TranslateMessage +TranslateMessage.argtypes = [LPMSG] +TranslateMessage.restype = BOOL + +DispatchMessage = user32.DispatchMessageA +DispatchMessage.argtypes = [LPMSG] + +# Beware, as of 2016-01-30 the official docs have a very incomplete list. +# This one was compiled from experience and may be incomplete. +WM_MOUSEMOVE = 0x200 +WM_LBUTTONDOWN = 0x201 +WM_LBUTTONUP = 0x202 +WM_LBUTTONDBLCLK = 0x203 +WM_RBUTTONDOWN = 0x204 +WM_RBUTTONUP = 0x205 +WM_RBUTTONDBLCLK = 0x206 +WM_MBUTTONDOWN = 0x207 +WM_MBUTTONUP = 0x208 +WM_MBUTTONDBLCLK = 0x209 +WM_MOUSEWHEEL = 0x20A +WM_XBUTTONDOWN = 0x20B +WM_XBUTTONUP = 0x20C +WM_XBUTTONDBLCLK = 0x20D +WM_NCXBUTTONDOWN = 0x00AB +WM_NCXBUTTONUP = 0x00AC +WM_NCXBUTTONDBLCLK = 0x00AD +WM_MOUSEHWHEEL = 0x20E +WM_LBUTTONDOWN = 0x0201 +WM_LBUTTONUP = 0x0202 +WM_MOUSEMOVE = 0x0200 +WM_MOUSEWHEEL = 0x020A +WM_MOUSEHWHEEL = 0x020E +WM_RBUTTONDOWN = 0x0204 +WM_RBUTTONUP = 0x0205 + +buttons_by_wm_code = { + WM_LBUTTONDOWN: (DOWN, LEFT), + WM_LBUTTONUP: (UP, LEFT), + WM_LBUTTONDBLCLK: (DOUBLE, LEFT), + + WM_RBUTTONDOWN: (DOWN, RIGHT), + WM_RBUTTONUP: (UP, RIGHT), + WM_RBUTTONDBLCLK: (DOUBLE, RIGHT), + + WM_MBUTTONDOWN: (DOWN, MIDDLE), + WM_MBUTTONUP: (UP, MIDDLE), + WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE), + + WM_XBUTTONDOWN: (DOWN, X), + WM_XBUTTONUP: (UP, X), + WM_XBUTTONDBLCLK: (DOUBLE, X), +} + +MOUSEEVENTF_ABSOLUTE = 0x8000 +MOUSEEVENTF_MOVE = 0x1 +MOUSEEVENTF_WHEEL = 0x800 +MOUSEEVENTF_HWHEEL = 0x1000 +MOUSEEVENTF_LEFTDOWN = 0x2 +MOUSEEVENTF_LEFTUP = 0x4 +MOUSEEVENTF_RIGHTDOWN = 0x8 +MOUSEEVENTF_RIGHTUP = 0x10 +MOUSEEVENTF_MIDDLEDOWN = 0x20 +MOUSEEVENTF_MIDDLEUP = 0x40 +MOUSEEVENTF_XDOWN = 0x0080 +MOUSEEVENTF_XUP = 0x0100 + +simulated_mouse_codes = { + (WHEEL, HORIZONTAL): MOUSEEVENTF_HWHEEL, + (WHEEL, VERTICAL): MOUSEEVENTF_WHEEL, + + (DOWN, LEFT): MOUSEEVENTF_LEFTDOWN, + (UP, LEFT): MOUSEEVENTF_LEFTUP, + + (DOWN, RIGHT): MOUSEEVENTF_RIGHTDOWN, + (UP, RIGHT): MOUSEEVENTF_RIGHTUP, + + (DOWN, MIDDLE): MOUSEEVENTF_MIDDLEDOWN, + (UP, MIDDLE): MOUSEEVENTF_MIDDLEUP, + + (DOWN, X): MOUSEEVENTF_XDOWN, + (UP, X): MOUSEEVENTF_XUP, +} + +NULL = c_int(0) + +WHEEL_DELTA = 120 + +init = lambda: None + +def listen(queue): + def low_level_mouse_handler(nCode, wParam, lParam): + struct = lParam.contents + # Can't use struct.time because it's usually zero. + t = time.time() + + if wParam == WM_MOUSEMOVE: + event = MoveEvent(struct.x, struct.y, t) + elif wParam == WM_MOUSEWHEEL: + event = WheelEvent(struct.data / (WHEEL_DELTA * (2<<15)), t) + elif wParam in buttons_by_wm_code: + type, button = buttons_by_wm_code.get(wParam, ('?', '?')) + if wParam >= WM_XBUTTONDOWN: + button = {0x10000: X, 0x20000: X2}[struct.data] + event = ButtonEvent(type, button, t) + + queue.put(event) + return CallNextHookEx(NULL, nCode, wParam, lParam) + + WH_MOUSE_LL = c_int(14) + mouse_callback = LowLevelMouseProc(low_level_mouse_handler) + mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, NULL, NULL) + + # Register to remove the hook when the interpreter exits. Unfortunately a + # try/finally block doesn't seem to work here. + atexit.register(UnhookWindowsHookEx, mouse_hook) + + msg = LPMSG() + while not GetMessage(msg, NULL, NULL, NULL): + TranslateMessage(msg) + DispatchMessage(msg) + +def _translate_button(button): + if button == X or button == X2: + return X, {X: 0x10000, X2: 0x20000}[button] + else: + return button, 0 + +def press(button=LEFT): + button, data = _translate_button(button) + code = simulated_mouse_codes[(DOWN, button)] + user32.mouse_event(code, 0, 0, data, 0) + +def release(button=LEFT): + button, data = _translate_button(button) + code = simulated_mouse_codes[(UP, button)] + user32.mouse_event(code, 0, 0, data, 0) + +def wheel(delta=1): + code = simulated_mouse_codes[(WHEEL, VERTICAL)] + user32.mouse_event(code, 0, 0, int(delta * WHEEL_DELTA), 0) + +def move_to(x, y): + user32.SetCursorPos(int(x), int(y)) + +def move_relative(x, y): + user32.mouse_event(MOUSEEVENTF_MOVE, int(x), int(y), 0, 0) + +class POINT(Structure): + _fields_ = [("x", c_long), ("y", c_long)] + +def get_position(): + point = POINT() + user32.GetCursorPos(byref(point)) + return (point.x, point.y) + +if __name__ == '__main__': + def p(e): + print(e) + listen(p) diff --git a/CLI/venv/lib/python3.12/site-packages/keyboard/mouse.py b/CLI/venv/lib/python3.12/site-packages/keyboard/mouse.py new file mode 100644 index 0000000..315199e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/keyboard/mouse.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +import warnings +warnings.simplefilter('always', DeprecationWarning) +warnings.warn('The mouse sub-library is deprecated and will be removed in future versions. Please use the standalone package `mouse`.', DeprecationWarning, stacklevel=2) + +import time as _time + +import platform as _platform +if _platform.system() == 'Windows': + from. import _winmouse as _os_mouse +elif _platform.system() == 'Linux': + from. import _nixmouse as _os_mouse +elif _platform.system() == 'Darwin': + from. import _darwinmouse as _os_mouse +else: + raise OSError("Unsupported platform '{}'".format(_platform.system())) + +from ._mouse_event import ButtonEvent, MoveEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE +from ._generic import GenericListener as _GenericListener + +_pressed_events = set() +class _MouseListener(_GenericListener): + def init(self): + _os_mouse.init() + def pre_process_event(self, event): + if isinstance(event, ButtonEvent): + if event.event_type in (UP, DOUBLE): + _pressed_events.discard(event.button) + else: + _pressed_events.add(event.button) + return True + + def listen(self): + _os_mouse.listen(self.queue) + +_listener = _MouseListener() + +def is_pressed(button=LEFT): + """ Returns True if the given button is currently pressed. """ + _listener.start_if_necessary() + return button in _pressed_events + +def press(button=LEFT): + """ Presses the given button (but doesn't release). """ + _os_mouse.press(button) + +def release(button=LEFT): + """ Releases the given button. """ + _os_mouse.release(button) + +def click(button=LEFT): + """ Sends a click with the given button. """ + _os_mouse.press(button) + _os_mouse.release(button) + +def double_click(button=LEFT): + """ Sends a double click with the given button. """ + click(button) + click(button) + +def right_click(): + """ Sends a right click with the given button. """ + click(RIGHT) + +def wheel(delta=1): + """ Scrolls the wheel `delta` clicks. Sign indicates direction. """ + _os_mouse.wheel(delta) + +def move(x, y, absolute=True, duration=0): + """ + Moves the mouse. If `absolute`, to position (x, y), otherwise move relative + to the current position. If `duration` is non-zero, animates the movement. + """ + x = int(x) + y = int(y) + + # Requires an extra system call on Linux, but `move_relative` is measured + # in millimiters so we would lose precision. + position_x, position_y = get_position() + + if not absolute: + x = position_x + x + y = position_y + y + + if duration: + start_x = position_x + start_y = position_y + dx = x - start_x + dy = y - start_y + + if dx == 0 and dy == 0: + _time.sleep(duration) + else: + # 120 movements per second. + # Round and keep float to ensure float division in Python 2 + steps = max(1.0, float(int(duration * 120.0))) + for i in range(int(steps)+1): + move(start_x + dx*i/steps, start_y + dy*i/steps) + _time.sleep(duration/steps) + else: + _os_mouse.move_to(x, y) + +def drag(start_x, start_y, end_x, end_y, absolute=True, duration=0): + """ + Holds the left mouse button, moving from start to end position, then + releases. `absolute` and `duration` are parameters regarding the mouse + movement. + """ + if is_pressed(): + release() + move(start_x, start_y, absolute, 0) + press() + move(end_x, end_y, absolute, duration) + release() + +def on_button(callback, args=(), buttons=(LEFT, MIDDLE, RIGHT, X, X2), types=(UP, DOWN, DOUBLE)): + """ Invokes `callback` with `args` when the specified event happens. """ + if not isinstance(buttons, (tuple, list)): + buttons = (buttons,) + if not isinstance(types, (tuple, list)): + types = (types,) + + def handler(event): + if isinstance(event, ButtonEvent): + if event.event_type in types and event.button in buttons: + callback(*args) + _listener.add_handler(handler) + return handler + +def on_click(callback, args=()): + """ Invokes `callback` with `args` when the left button is clicked. """ + return on_button(callback, args, [LEFT], [UP]) + +def on_double_click(callback, args=()): + """ + Invokes `callback` with `args` when the left button is double clicked. + """ + return on_button(callback, args, [LEFT], [DOUBLE]) + +def on_right_click(callback, args=()): + """ Invokes `callback` with `args` when the right button is clicked. """ + return on_button(callback, args, [RIGHT], [UP]) + +def on_middle_click(callback, args=()): + """ Invokes `callback` with `args` when the middle button is clicked. """ + return on_button(callback, args, [MIDDLE], [UP]) + +def wait(button=LEFT, target_types=(UP, DOWN, DOUBLE)): + """ + Blocks program execution until the given button performs an event. + """ + from threading import Lock + lock = Lock() + lock.acquire() + handler = on_button(lock.release, (), [button], target_types) + lock.acquire() + _listener.remove_handler(handler) + +def get_position(): + """ Returns the (x, y) mouse position. """ + return _os_mouse.get_position() + +def hook(callback): + """ + Installs a global listener on all available mouses, invoking `callback` + each time it is moved, a key status changes or the wheel is spun. A mouse + event is passed as argument, with type either `mouse.ButtonEvent`, + `mouse.WheelEvent` or `mouse.MoveEvent`. + + Returns the given callback for easier development. + """ + _listener.add_handler(callback) + return callback + +def unhook(callback): + """ + Removes a previously installed hook. + """ + _listener.remove_handler(callback) + +def unhook_all(): + """ + Removes all hooks registered by this application. Note this may include + hooks installed by high level functions, such as `record`. + """ + del _listener.handlers[:] + +def record(button=RIGHT, target_types=(DOWN,)): + """ + Records all mouse events until the user presses the given button. + Then returns the list of events recorded. Pairs well with `play(events)`. + + Note: this is a blocking function. + Note: for more details on the mouse hook and events see `hook`. + """ + recorded = [] + hook(recorded.append) + wait(button=button, target_types=target_types) + unhook(recorded.append) + return recorded + +def play(events, speed_factor=1.0, include_clicks=True, include_moves=True, include_wheel=True): + """ + Plays a sequence of recorded events, maintaining the relative time + intervals. If speed_factor is <= 0 then the actions are replayed as fast + as the OS allows. Pairs well with `record()`. + + The parameters `include_*` define if events of that type should be inluded + in the replay or ignored. + """ + last_time = None + for event in events: + if speed_factor > 0 and last_time is not None: + _time.sleep((event.time - last_time) / speed_factor) + last_time = event.time + + if isinstance(event, ButtonEvent) and include_clicks: + if event.event_type == UP: + _os_mouse.release(event.button) + else: + _os_mouse.press(event.button) + elif isinstance(event, MoveEvent) and include_moves: + _os_mouse.move_to(event.x, event.y) + elif isinstance(event, WheelEvent) and include_wheel: + _os_mouse.wheel(event.delta) + +replay = play +hold = press + +if __name__ == '__main__': + print('Recording... Double click to stop and replay.') + play(record()) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/COPYING.LGPL b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/COPYING.LGPL new file mode 100644 index 0000000..0df067b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/COPYING.LGPL @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007-2024 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/METADATA new file mode 100644 index 0000000..fecb69e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/METADATA @@ -0,0 +1,914 @@ +Metadata-Version: 2.1 +Name: pynput +Version: 1.8.1 +Summary: Monitor and control user input devices +Home-page: https://github.com/moses-palmer/pynput +Author: Moses Palmér +Author-email: moses.palmer@gmail.com +License: LGPLv3 +Keywords: control mouse,mouse input,control keyboard,keyboard input +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000 +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Monitoring +License-File: COPYING.LGPL +Requires-Dist: six +Requires-Dist: evdev>=1.3; "linux" in sys_platform +Requires-Dist: python-xlib>=0.17; "linux" in sys_platform +Requires-Dist: enum34; python_version == "2.7" +Requires-Dist: pyobjc-framework-ApplicationServices>=8.0; sys_platform == "darwin" +Requires-Dist: pyobjc-framework-Quartz>=8.0; sys_platform == "darwin" + +pynput +====== + +This library allows you to control and monitor input devices. + +Currently, mouse and keyboard input and monitoring are supported. + +See `here `_ for the full +documentation. + + +Controlling the mouse +--------------------- + +Use ``pynput.mouse.Controller`` like this:: + + from pynput.mouse import Button, Controller + + mouse = Controller() + + # Read pointer position + print('The current pointer position is {}'.format( + mouse.position)) + + # Set pointer position + mouse.position = (10, 20) + print('Now we have moved it to {}'.format( + mouse.position)) + + # Move pointer relative to current position + mouse.move(5, -5) + + # Press and release + mouse.press(Button.left) + mouse.release(Button.left) + + # Double click; this is different from pressing and releasing + # twice on macOS + mouse.click(Button.left, 2) + + # Scroll two steps down + mouse.scroll(0, 2) + + +Monitoring the mouse +-------------------- + +Use ``pynput.mouse.Listener`` like this:: + + from pynput import mouse + + def on_move(x, y, injected): + print('Pointer moved to {}; it was {}'.format( + (x, y, 'faked' if injected else 'not faked'))) + + def on_click(x, y, button, pressed, injected): + print('{} at {}; it was {}'.format( + 'Pressed' if pressed else 'Released', + (x, y, 'faked' if injected else 'not faked'))) + if not pressed: + # Stop listener + return False + + def on_scroll(x, y, dx, dy, injected): + print('Scrolled {} at {}; it was {}'.format( + 'down' if dy < 0 else 'up', + (x, y, 'faked' if injected else 'not faked'))) + + # Collect events until released + with mouse.Listener( + on_move=on_move, + on_click=on_click, + on_scroll=on_scroll) as listener: + listener.join() + + # ...or, in a non-blocking fashion: + listener = mouse.Listener( + on_move=on_move, + on_click=on_click, + on_scroll=on_scroll) + listener.start() + +A mouse listener is a ``threading.Thread``, and all callbacks will be invoked +from the thread. + +Call ``pynput.mouse.Listener.stop`` from anywhere, raise ``StopException`` or +return ``False`` from a callback to stop the listener. + +When using the non-blocking version above, the current thread will continue +executing. This might be necessary when integrating with other GUI frameworks +that incorporate a main-loop, but when run from a script, this will cause the +program to terminate immediately. + + +The mouse listener thread +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The listener callbacks are invoked directly from an operating thread on some +platforms, notably *Windows*. + +This means that long running procedures and blocking operations should not be +invoked from the callback, as this risks freezing input for all processes. + +A possible workaround is to just dispatch incoming messages to a queue, and let +a separate thread handle them. + + +Handling mouse listener errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a callback handler raises an exception, the listener will be stopped. Since +callbacks run in a dedicated thread, the exceptions will not automatically be +reraised. + +To be notified about callback errors, call ``Thread.join`` on the listener +instance:: + + from pynput import mouse + + class MyException(Exception): pass + + def on_click(x, y, button, pressed): + if button == mouse.Button.left: + raise MyException(button) + + # Collect events until released + with mouse.Listener( + on_click=on_click) as listener: + try: + listener.join() + except MyException as e: + print('{} was clicked'.format(e.args[0])) + + +Toggling event listening for the mouse listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once ``pynput.mouse.Listener.stop`` has been called, the listener cannot be +restarted, since listeners are instances of ``threading.Thread``. + +If your application requires toggling listening events, you must either add an +internal flag to ignore events when not required, or create a new listener when +resuming listening. + + +Synchronous event listening for the mouse listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To simplify scripting, synchronous event listening is supported through the +utility class ``pynput.mouse.Events``. This class supports reading single +events in a non-blocking fashion, as well as iterating over all events. + +To read a single event, use the following code:: + + from pynput import mouse + + # The event listener will be running in this block + with mouse.Events() as events: + # Block at most one second + event = events.get(1.0) + if event is None: + print('You did not interact with the mouse within one second') + else: + print('Received event {}'.format(event)) + +To iterate over mouse events, use the following code:: + + from pynput import mouse + + # The event listener will be running in this block + with mouse.Events() as events: + for event in events: + if event.button == mouse.Button.right: + break + else: + print('Received event {}'.format(event)) + +Please note that the iterator method does not support non-blocking operation, +so it will wait for at least one mouse event. + +The events will be instances of the inner classes found in +``pynput.mouse.Events``. + + +Ensuring consistent coordinates between listener and controller on Windows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Recent versions of _Windows_ support running legacy applications scaled when +the system scaling has been increased beyond 100%. This allows old applications +to scale, albeit with a blurry look, and avoids tiny, unusable user interfaces. + +This scaling is unfortunately inconsistently applied to a mouse listener and a +controller: the listener will receive physical coordinates, but the controller +has to work with scaled coordinates. + +This can be worked around by telling Windows that your application is DPI +aware. This is a process global setting, so _pynput_ cannot do it +automatically. Do enable DPI awareness, run the following code:: + + import ctypes + + + PROCESS_PER_MONITOR_DPI_AWARE = 2 + + ctypes.windll.shcore.SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) + + +Controlling the keyboard +------------------------ + +Use ``pynput.keyboard.Controller`` like this:: + + from pynput.keyboard import Key, Controller + + keyboard = Controller() + + # Press and release space + keyboard.press(Key.space) + keyboard.release(Key.space) + + # Type a lower case A; this will work even if no key on the + # physical keyboard is labelled 'A' + keyboard.press('a') + keyboard.release('a') + + # Type two upper case As + keyboard.press('A') + keyboard.release('A') + with keyboard.pressed(Key.shift): + keyboard.press('a') + keyboard.release('a') + + # Type 'Hello World' using the shortcut type method + keyboard.type('Hello World') + + +Monitoring the keyboard +----------------------- + +Use ``pynput.keyboard.Listener`` like this:: + + from pynput import keyboard + + def on_press(key, injected): + try: + print('alphanumeric key {} pressed; it was {}'.format( + key.char, 'faked' if injected else 'not faked')) + except AttributeError: + print('special key {} pressed'.format( + key)) + + def on_release(key, injected): + print('{} released; it was {}'.format( + key, 'faked' if injected else 'not faked')) + if key == keyboard.Key.esc: + # Stop listener + return False + + # Collect events until released + with keyboard.Listener( + on_press=on_press, + on_release=on_release) as listener: + listener.join() + + # ...or, in a non-blocking fashion: + listener = keyboard.Listener( + on_press=on_press, + on_release=on_release) + listener.start() + +A keyboard listener is a ``threading.Thread``, and all callbacks will be +invoked from the thread. + +Call ``pynput.keyboard.Listener.stop`` from anywhere, raise ``StopException`` +or return ``False`` from a callback to stop the listener. + +The ``key`` parameter passed to callbacks is a ``pynput.keyboard.Key``, for +special keys, a ``pynput.keyboard.KeyCode`` for normal alphanumeric keys, or +just ``None`` for unknown keys. + +When using the non-blocking version above, the current thread will continue +executing. This might be necessary when integrating with other GUI frameworks +that incorporate a main-loop, but when run from a script, this will cause the +program to terminate immediately. + + +The keyboard listener thread +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The listener callbacks are invoked directly from an operating thread on some +platforms, notably *Windows*. + +This means that long running procedures and blocking operations should not be +invoked from the callback, as this risks freezing input for all processes. + +A possible workaround is to just dispatch incoming messages to a queue, and let +a separate thread handle them. + + +Handling keyboard listener errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a callback handler raises an exception, the listener will be stopped. Since +callbacks run in a dedicated thread, the exceptions will not automatically be +reraised. + +To be notified about callback errors, call ``Thread.join`` on the listener +instance:: + + from pynput import keyboard + + class MyException(Exception): pass + + def on_press(key): + if key == keyboard.Key.esc: + raise MyException(key) + + # Collect events until released + with keyboard.Listener( + on_press=on_press) as listener: + try: + listener.join() + except MyException as e: + print('{} was pressed'.format(e.args[0])) + + +Toggling event listening for the keyboard listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once ``pynput.keyboard.Listener.stop`` has been called, the listener cannot be +restarted, since listeners are instances of ``threading.Thread``. + +If your application requires toggling listening events, you must either add an +internal flag to ignore events when not required, or create a new listener when +resuming listening. + + +Synchronous event listening for the keyboard listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To simplify scripting, synchronous event listening is supported through the +utility class ``pynput.keyboard.Events``. This class supports reading single +events in a non-blocking fashion, as well as iterating over all events. + +To read a single event, use the following code:: + + from pynput import keyboard + + # The event listener will be running in this block + with keyboard.Events() as events: + # Block at most one second + event = events.get(1.0) + if event is None: + print('You did not press a key within one second') + else: + print('Received event {}'.format(event)) + +To iterate over keyboard events, use the following code:: + + from pynput import keyboard + + # The event listener will be running in this block + with keyboard.Events() as events: + for event in events: + if event.key == keyboard.Key.esc: + break + else: + print('Received event {}'.format(event)) + +Please note that the iterator method does not support non-blocking operation, +so it will wait for at least one keyboard event. + +The events will be instances of the inner classes found in +``pynput.keyboard.Events``. + + +Global hotkeys +~~~~~~~~~~~~~~ + +A common use case for keyboard monitors is reacting to global hotkeys. Since a +listener does not maintain any state, hotkeys involving multiple keys must +store this state somewhere. + +*pynput* provides the class ``pynput.keyboard.HotKey`` for this purpose. It +contains two methods to update the state, designed to be easily interoperable +with a keyboard listener: ``pynput.keyboard.HotKey.press`` and +``pynput.keyboard.HotKey.release`` which can be directly passed as listener +callbacks. + +The intended usage is as follows:: + + from pynput import keyboard + + def on_activate(): + print('Global hotkey activated!') + + def for_canonical(f): + return lambda k: f(l.canonical(k)) + + hotkey = keyboard.HotKey( + keyboard.HotKey.parse('++h'), + on_activate) + with keyboard.Listener( + on_press=for_canonical(hotkey.press), + on_release=for_canonical(hotkey.release)) as l: + l.join() + +This will create a hotkey, and then use a listener to update its state. Once +all the specified keys are pressed simultaneously, ``on_activate`` will be +invoked. + +Note that keys are passed through ``pynput.keyboard.Listener.canonical`` before +being passed to the ``HotKey`` instance. This is to remove any modifier state +from the key events, and to normalise modifiers with more than one physical +button. + +The method ``pynput.keyboard.HotKey.parse`` is a convenience function to +transform shortcut strings to key collections. Please see its documentation for +more information. + +To register a number of global hotkeys, use the convenience class +``pynput.keyboard.GlobalHotKeys``:: + + from pynput import keyboard + + def on_activate_h(): + print('++h pressed') + + def on_activate_i(): + print('++i pressed') + + with keyboard.GlobalHotKeys({ + '++h': on_activate_h, + '++i': on_activate_i}) as h: + h.join() + + +Release Notes +============= + +v1.8.1 (2025-03-17) - Various fixes +----------------------------------- +* Remove incorrectly merged line for the *Xorg* backend. Thanks to *sphh*! +* Let events know about the new ``injected`` parameter. Thanks to + *phpjunkie420*! + + +v1.8.0 (2025-03-03) - Allow detecting injected events +----------------------------------------------------- +* Add a flag to callbacks to allow detecting injected input events. +* Add ``media_stop`` key for *macOS*. Thanks to *laura-3*! +* Add ``eject`` key for *macOS*. Thanks to *DiMNDev*! + + +v1.7.8 (2025-02-28) - Fixes for Python 3.12 +------------------------------------------- +* Rename method for listeners to not conflict with new ``threading.Thread`` + field. + + +v1.7.7 (2024-05-10) - Various fixes +----------------------------------- +* Small corrections to the documentation. +* Handle explicit timeout when calling ``join`` on listeners. +* Correct regression in hot key handling for special keys. +* Reverted changes to lazy loading of ``CoreFoundation`` and ``Quartz``, since + this still does not appear to work. Thanks to *Zach Zaiman*! +* Let the type of values in ``Key`` be ``KeyCode`` so that type checkers are + not confused. Thanks to *Amund Eggen Svandal*! +* Do not crash in ``__del__`` on *Xorg* if display creation fails. Thanks to + *Gabriele Pongelli*! +* Correct support for emojis on *Windows*. Thanks to *Yunus Emre*! + + +v1.7.6 (2022-01-01) - Various fixes +----------------------------------- +* Allow passing virtual key codes to the parser for global hot keys. +* Stop the recording context asynchronously on *Xorg*. +* Do not pass ``None`` to ``objc.objc_object``. Thanks to *yejunxi*! +* Do not crash when pressing the *alt* key on *uinput*. Thanks to *Caldas + Lopes*! +* Use the correct option prefix for listeners derived from the backend + implementations. Thanks to *Yu Wang*! + + +v1.7.5 (2021-11-19) - Various fixes +----------------------------------- +* Corrected crashes on *Xorg* when a listener was configured to suppress + system events. Thanks to *jpramosi*! +* Improved handling of keyboard controller on *Windows*. The controller now + has a greater change of working with applications using lower level events. + Thanks to *bhudax*! +* Updated *macOS* implementation to use new version of *pyobjc*. + + +v1.7.4 (2021-10-10) - Various fixes +----------------------------------- +* Detect whether permissions are lacking on *macOS*. Thanks to *Dane Finlay*! +* Eagerly import symbols from ``CoreFoundation`` and ``Quartz``. Thanks to + *Ronald Oussoren*! +* Improved handling of ``dumpkeys`` utility. Thanks to *Markus Niedermann*! +* Removed ambiguous license file. + + +v1.7.3 (2021-02-10) - Various fixes +----------------------------------- +* Corrected *keysym* handling on *Xorg*; not all groups were loaded, and the + fallback to our internal tables was never triggered. Thanks to *Philipp + Klaus*! +* Updated the version of *Quartz* used for the *macOS* backend to allow + *pynput* to be installed on *Big Sur*. Thanks to *Michael Madden*! +* Added missing function keys on *Windows*. Thanks to *Dave Atkinson*! +* Corrected scroll speed for mouse controller on *macOS*. Thanks to *Albert + Zeyer*! +* Corrected media keys for *Xorg*. Thanks to *Gabriele N. Tornetta*! +* Corrected parameter name in documentation. Thanks to *Jinesi Yelizati*! + + +v1.7.2 (2020-12-21) - Corrected uinput key mapping +-------------------------------------------------- +* Corrected mapping of virtual key codes to characters for the *uinput* + backend. +* Corrected spelling errors. Thanks to *Martin Michlmayr*! +* Corrected and improved documentation. + + +v1.7.1 (2020-08-30) - Corrected release notes +--------------------------------------------- +* Corrected thanks for arbitrary unicode character support for *Xorg*. + + +v1.7.0 (2020-08-30) - A new backend and many new features and bug fixes +----------------------------------------------------------------------- +* Added a new *uinput* based keyboard backend for *Linux*, when no *X* server + is available. +* Allow typing arbitrary unicode characters on *Xorg* backend. Thanks to + *gdiShun*! +* Allow overriding the automatically selected backend with an environment + variable, and added a dummy backend. +* Added support for mouse side button on *Windows*. Thanks to *danielkovarik*! +* Added convenience method to tap keys. +* Allow specifying raw virtual key codes in hotkeys. +* Improved error messages when a backend cannot be loaded. +* Include more information in stringification of events. +* Corrected return value of ``Events.get`` to that specified by the + documentation. +* Corrected keyboard listener not to type random characters on certain + keyboard layouts. +* Corrected errors when pressing certain keys on *Windows*, where the + operating system reports that they are dead but no combining version exists. +* Improved documentation. + + +v1.6.8 (2020-02-28) - Various fixes +----------------------------------- +* Updated documentation. +* Corrected lint warnings and tests. +* Do not use internal types in ``argtypes`` for ``win32`` functions; this + renders them uncallable for other code running in the same runtime. +* Include scan codes in events on *Windows*. Thanks to *bhudax*! +* Correctly apply transformation to scroll event values on *Windows*. Thanks + to *DOCCA0*! + + +v1.6.7 (2020-02-17) - Various fixes +----------------------------------- +* Corrected infinite scrolling on *macOS* when providing non-integer deltas. + Thanks to *Iván Munsuri Ibáñez*! +* Corrected controller and listener handling of media keys on *macOS*. Thanks + to *Iván Munsuri Ibáñez*! + + +v1.6.6 (2020-01-23) - Corrected hot key documentation +----------------------------------------------------- +* The code examples for the simple ``pynput.keyboard.HotKey`` now work. Thanks + to *jfongattw*! + + +v1.6.5 (2020-01-08) - Corrected media key mappings +-------------------------------------------------- +* Corrected media key mappings on *macOS*. Thanks to *Luis Nachtigall*! + + +v1.6.4 (2020-01-03) - Corrected imports yet again +------------------------------------------------- +* Corrected imports for keyboard Controller. Thanks to *rhystedstone*! + + +v1.6.3 (2019-12-28) - Corrected imports again +--------------------------------------------- +* Corrected imports for keyboard Controller. Thanks to *Matt Iversen*! + + +v1.6.2 (2019-12-28) - Corrected imports +--------------------------------------- +* Corrected imports for keyboard Controller. Thanks to *Matt Iversen*! + + +v1.6.1 (2019-12-27) - Corrections for *Windows* +----------------------------------------------- +* Corrected global hotkeys on *Windows*. +* Corrected pressed / released state for keyboard listener on *Windows*. + Thanks to *segalion*! + +v1.6.0 (2019-12-11) - Global Hotkeys +------------------------------------ +* Added support for global hotkeys. +* Added support for streaming listener events synchronously. + + +v1.5.2 (2019-12-06) - Corrected media key names for *Xorg* +---------------------------------------------------------- +* Removed media flag from *Xorg* keys. + + +v1.5.1 (2019-12-06) - Corrected media key names for *macOS* +----------------------------------------------------------- +* Corrected attribute names for media keys on *macOS*. Thanks to *ah3243*! + + +v1.5.0 (2019-12-04) - Various improvements +------------------------------------------ +* Corrected keyboard listener on *Windows*. Thanks to *akiratakasaki*, + *segalion*, *SpecialCharacter*! +* Corrected handling of some special keys, including arrow keys, when combined + with modifiers on *Windows*. Thanks to *tuessetr*! +* Updated documentation to include information about DPI scaling on *Windows*. + Thanks to *david-szarka*! +* Added experimental support for media keys. Thanks to *ShivamJoker*, + *StormTersteeg*! + + +v1.4.5 (2019-11-05) - Corrected errors on *Python 3.8* +------------------------------------------------------ +* Corrected errors about using `in` operator for enums on *Python 3.8* on + *macOS*. + + +v1.4.4 (2019-09-24) - Actually corrected keyboard listener on macOS +------------------------------------------------------------------- +* Included commit to correctly fall back on + ``CGEventKeyboardGetUnicodeString``. +* Corrected deprecation warnings about ``Enum`` usage on *Python 3.8*. + + +v1.4.3 (2019-09-24) - Corrected keyboard listener on macOS again +---------------------------------------------------------------- +* Correctly fall back on ``CGEventKeyboardGetUnicodeString``. +* Updated documentation. + + +v1.4.2 (2019-03-22) - Corrected keyboard listener on macOS +---------------------------------------------------------- +* Use ``CGEventKeyboardGetUnicodeString`` in *macOS* keyboard listener to send + correct characters. +* Include keysym instead of key code in *Xorg* keyboard listener. +* Corrected logging to not include expected ``StopException``. +* Updated and corrected documentation. + + +v1.4.1 (2018-09-07) - Logging +----------------------------- +* Log unhandled exceptions raised by listener callbacks. + + +v1.4 (2018-07-03) - Event suppression +------------------------------------- +* Added possibility to fully suppress events when listening. +* Added support for typing some control characters. +* Added support for mouse drag events on *OSX*. Thanks to *jungledrum*! +* Include the key code in keyboard listener events. +* Correctly handle the numeric key pad on *Xorg* with *num lock* active. + Thanks to *TheoRet*! +* Corrected handling of current thread keyboard layout on *Windows*. Thanks to + *Schmettaling*! +* Corrected stopping of listeners on *Xorg*. +* Corrected import of ``Xlib.keysymdef.xkb`` on *Xorg*. Thanks to *Glandos*! + + +v1.3.10 (2018-02-05) - Do not crash under *Xephyr* +-------------------------------------------------- +* Do not crash when ``Xlib.display.Display.get_input_focus`` returns an + integer, as it may when running under *Xephyr*. Thanks to *Eli Skeggs*! + + +v1.3.9 (2018-01-12) - Correctly handle the letter *A* on *OSX* +-------------------------------------------------------------- +* Corrected check for virtual key code when generating keyboard events on + *OSX*. This fixes an issue where pressing *A* with *shift* explicitly pressed + would still type a minuscule letter. + + +v1.3.8 (2017-12-08) - Do not crash on some keyboard layouts on *OSX* +-------------------------------------------------------------------- +* Fall back on a different method to retrieve the keyboard layout on *OSX*. + This helps for some keyboard layouts, such as *Chinese*. Thanks to + *haoflynet*! + + +v1.3.7 (2017-08-23) - *Xorg* corrections +---------------------------------------- +* Include mouse buttons up to *30* for *Xorg*. + + +v1.3.6 (2017-08-13) - *win32* corrections +----------------------------------------- +* Corrected double delivery of fake keyboard events on *Windows*. +* Corrected handling of synthetic unicode keys on *Windows*. + + +v1.3.5 (2017-06-07) - Corrected dependencies again +-------------------------------------------------- +* Reverted changes in *1.3.3*. +* Corrected platform specifier for *Python 2* on *Linux*. + + +v1.3.4 (2017-06-05) - *Xorg* corrections +---------------------------------------- +* Corrected bounds check for values on *Xorg*. + + +v1.3.3 (2017-06-05) - Make dependencies non-optional +---------------------------------------------------- +* Made platform dependencies non-optional. + + +v1.3.2 (2017-05-15) - Fix for button click on Mac +------------------------------------------------- +* Corrected regression from previous release where button clicks would + crash the *Mac* mouse listener. + + +v1.3.1 (2017-05-12) - Fixes for unknown buttons on Linux +-------------------------------------------------------- +* Fall back on `Button.unknown` for unknown mouse buttons in *Xorg* mouse + listener. + + +v1.3 (2017-04-10) - Platform specific features +---------------------------------------------- +* Added ability to stop event propagation on *Windows*. This will prevent + events from reaching other applications. +* Added ability to ignore events on *Windows*. This is a workaround for systems + where the keyboard monitor interferes with normal keyboard events. +* Added ability to modify events on *OSX*. This allows intercepting and + altering input events before they reach other applications. +* Corrected crash on *OSX* when some types of third party input sources are + installed. + + +v1.2 (2017-01-06) - Improved error handling +------------------------------------------- +* Allow catching exceptions thrown from listener callbacks. This changes the + API, as joining a listener now potentially raises unhandled exceptions, + and unhandled exceptions will stop listeners. +* Added support for the numeric keypad on *Linux*. +* Improved documentation. +* Thanks to *jollysean* and *gilleswijnker* for their input! + + +v1.1.7 (2017-01-02) - Handle middle button on Windows +----------------------------------------------------- +* Listen for and dispatch middle button mouse clicks on *Windows*. + + +v1.1.6 (2016-11-24) - Corrected context manager for pressing keys +----------------------------------------------------------------- +* Corrected bug in ``pynput.keyboard.Controller.pressed`` which caused it to + never release the key. Many thanks to Toby Southwell! + + +v1.1.5 (2016-11-17) - Corrected modifier key combinations on Linux +------------------------------------------------------------------ +* Corrected handling of modifier keys to allow them to be composable on + *Linux*. + + +v1.1.4 (2016-10-30) - Small bugfixes +------------------------------------ +* Corrected error generation when ``GetKeyboardState`` fails. +* Make sure to apply shift state to borrowed keys on *X*. +* Use *pylint*. + + +v1.1.3 (2016-09-27) - Changed Xlib backend library +-------------------------------------------------- +* Changed *Xlib* library. + + +v1.1.2 (2016-09-26) - Added missing type for Python 2 +----------------------------------------------------- +* Added missing ``LPDWORD`` for *Python 2* on *Windows*. + + +v1.1.1 (2016-09-26) - Fixes for listeners and controllers on Windows +-------------------------------------------------------------------- +* Corrected keyboard listener on *Windows*. Modifier keys and other keys + changing the state of the keyboard are now handled correctly. +* Corrected mouse click and release on *Windows*. +* Corrected code samples. + + +v1.1 (2016-06-22) - Simplified usage on Linux +--------------------------------------------- +* Propagate import errors raised on Linux to help troubleshoot missing + ``Xlib`` module. +* Declare ``python3-xlib`` as dependency on *Linux* for *Python 3*. + + +v1.0.6 (2016-04-19) - Universal wheel +------------------------------------- +* Make sure to build a universal wheel for all python versions. + + +v1.0.5 (2016-04-11) - Fixes for dragging on OSX +----------------------------------------------- +* Corrected dragging on *OSX*. +* Added scroll speed constant for *OSX* to correct slow scroll speed. + + +v1.0.4 (2016-04-11) - Fixes for clicking and scrolling on Windows +----------------------------------------------------------------- +* Corrected name of mouse input field when sending click and scroll events. + + +v1.0.3 (2016-04-05) - Fixes for Python 3 on Windows +--------------------------------------------------- +* Corrected use of ``ctypes`` on Windows. + + +v1.0.2 (2016-04-03) - Fixes for thread identifiers +-------------------------------------------------- +* Use thread identifiers to identify threads, not Thread instances. + + +v1.0.1 (2016-04-03) - Fixes for Python 3 +---------------------------------------- +* Corrected bugs which prevented the library from being used on *Python 3*. + + +v1.0 (2016-02-28) - Stable Release +---------------------------------- +* Changed license to *LGPL*. +* Corrected minor bugs and inconsistencies. +* Corrected and extended documentation. + + +v0.6 (2016-02-08) - Keyboard Monitor +------------------------------------ +* Added support for monitoring the keyboard. +* Corrected wheel packaging. +* Corrected deadlock when stopping a listener in some cases on *X*. +* Corrected key code constants on *Mac OSX*. +* Do not intercept events on *Mac OSX*. + + +v0.5.1 (2016-01-26) - Do not die on dead keys +--------------------------------------------- +* Corrected handling of dead keys. +* Corrected documentation. + + +v0.5 (2016-01-18) - Keyboard Modifiers +-------------------------------------- +* Added support for modifiers. + + +v0.4 (2015-12-22) - Keyboard Controller +--------------------------------------- +* Added keyboard controller. + + +v0.3 (2015-12-22) - Cleanup +--------------------------- +* Moved ``pynput.mouse.Controller.Button`` to top-level. + + +v0.2 (2015-10-28) - Initial Release +----------------------------------- +* Support for controlling the mouse on *Linux*, *Mac OSX* and *Windows*. +* Support for monitoring the mouse on *Linux*, *Mac OSX* and *Windows*. diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/RECORD new file mode 100644 index 0000000..a71033b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/RECORD @@ -0,0 +1,55 @@ +pynput-1.8.1.dist-info/COPYING.LGPL,sha256=eInlwsfJhthC1m5_bBVCQ1Mmf5nTUtL8MpjKfZxi0LU,7656 +pynput-1.8.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pynput-1.8.1.dist-info/METADATA,sha256=YNPNdd5SDrz20GVbmn7XZ-viRHHlyyZu1rUhCoYTo0k,32018 +pynput-1.8.1.dist-info/RECORD,, +pynput-1.8.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pynput-1.8.1.dist-info/WHEEL,sha256=qUzzGenXXuJTzyjFah76kDVqDvnk-YDzY00svnrl84w,109 +pynput-1.8.1.dist-info/pbr.json,sha256=CAnWerrCQ6A-ekJTVVKkD9J-ia4q-xoZzQWKOlPcseQ,47 +pynput-1.8.1.dist-info/top_level.txt,sha256=DpJjYf-VkYaa_COk_yUczD0pHqsLndB9SjmwcQGkXJQ,7 +pynput-1.8.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +pynput/__init__.py,sha256=dJ7uVZs3BRQILOxuM9BqDNDS36Qav123Hpx-3HUklpo,1334 +pynput/__pycache__/__init__.cpython-312.pyc,, +pynput/__pycache__/_info.cpython-312.pyc,, +pynput/_info.py,sha256=2aajH_7soMpmZO_oMDHp7R2aXpMher6jdVa5Mnhjj6g,775 +pynput/_util/__init__.py,sha256=ZB2LiSbGsbeQlnlVUQP9TNze15Fv6cb9m1zXYuJmy5g,15482 +pynput/_util/__pycache__/__init__.cpython-312.pyc,, +pynput/_util/__pycache__/darwin.cpython-312.pyc,, +pynput/_util/__pycache__/darwin_vks.cpython-312.pyc,, +pynput/_util/__pycache__/uinput.cpython-312.pyc,, +pynput/_util/__pycache__/win32.cpython-312.pyc,, +pynput/_util/__pycache__/win32_vks.cpython-312.pyc,, +pynput/_util/__pycache__/xorg.cpython-312.pyc,, +pynput/_util/__pycache__/xorg_keysyms.cpython-312.pyc,, +pynput/_util/darwin.py,sha256=AxtbSopLkKzWI1WLdCIZWMQtUtTuCxbRvWB6-WKcsCM,9200 +pynput/_util/darwin_vks.py,sha256=x-SbG4VgJ6Qc5-ZyF8cniqN3qIqahuQtXzG8ei94uWI,1512 +pynput/_util/uinput.py,sha256=ZFYiTsjQ7lr4h43X2Axrj-_FvWxiVT6dik7Z7Ra_sQE,2837 +pynput/_util/win32.py,sha256=YzEct1u1pzQ8v69kRlF-PnMB9BxwqkxCroNFVy4Ychw,18135 +pynput/_util/win32_vks.py,sha256=lC4y8E85nCGHmr4avVs44SvuBvUHBxmDeikNZcPGt6o,2894 +pynput/_util/xorg.py,sha256=ETHqMURfpvnA4q1UFIFQpWCj0c_9YTgasH3e0M4PRrM,15251 +pynput/_util/xorg_keysyms.py,sha256=YGRUXj1P0HT0gEkci2HZHyI_wcOwt0imt6R-7wPQVJo,69338 +pynput/keyboard/__init__.py,sha256=-5KBcWTSFjv2z1tu6sMV40UwhcqcX5O-yIex9fAmC_o,7903 +pynput/keyboard/__pycache__/__init__.cpython-312.pyc,, +pynput/keyboard/__pycache__/_base.cpython-312.pyc,, +pynput/keyboard/__pycache__/_darwin.cpython-312.pyc,, +pynput/keyboard/__pycache__/_dummy.cpython-312.pyc,, +pynput/keyboard/__pycache__/_uinput.cpython-312.pyc,, +pynput/keyboard/__pycache__/_win32.cpython-312.pyc,, +pynput/keyboard/__pycache__/_xorg.cpython-312.pyc,, +pynput/keyboard/_base.py,sha256=CPkWx8uE-oEhYMiRUY3uxqZuAMgT7Phrv3k8WoYp-D0,24082 +pynput/keyboard/_darwin.py,sha256=apF_nOR5EECuo1q-tZ5bi66JM3uFa83ZJy7Cfpc6xSQ,11672 +pynput/keyboard/_dummy.py,sha256=hkBFRY7HWyl86B_HdFiTeLthJjg926kN2peF-HUUXB0,895 +pynput/keyboard/_uinput.py,sha256=EH9FJX45IlbmjGvE1x4O2Ixvgkynp7XOka-vbtjVEAI,14479 +pynput/keyboard/_win32.py,sha256=i3S975s2SlEL9wva9ZMTi0icrNMWHyoj2zPN6gLeqsQ,12645 +pynput/keyboard/_xorg.py,sha256=QEGbet8NreQElzaSGfyARLaVoZxEvcIOTtjU6EHPnRQ,22677 +pynput/mouse/__init__.py,sha256=RiwZMZiWJEikRr8amiMoqJDVTn9i0irEfFcy3IA-s4w,2864 +pynput/mouse/__pycache__/__init__.cpython-312.pyc,, +pynput/mouse/__pycache__/_base.cpython-312.pyc,, +pynput/mouse/__pycache__/_darwin.cpython-312.pyc,, +pynput/mouse/__pycache__/_dummy.cpython-312.pyc,, +pynput/mouse/__pycache__/_win32.cpython-312.pyc,, +pynput/mouse/__pycache__/_xorg.cpython-312.pyc,, +pynput/mouse/_base.py,sha256=FfxHWA126ts1vz05YdcOHJOWb3XaF6WTctM-_ix6FNU,9338 +pynput/mouse/_darwin.py,sha256=a6M_Od7yCzEdxxrYGWLlHuInOWk6Nibd6dKnm5HC79s,6793 +pynput/mouse/_dummy.py,sha256=p16GreQcJbLMhE51uf8H3F8iarHf7Tu2s0JGt3J2xeQ,874 +pynput/mouse/_win32.py,sha256=e1NYKhsKe_Z2W4SZOJK3xWqDjtAa7Dy-zmvT_WzKx7M,7117 +pynput/mouse/_xorg.py,sha256=0P-N-jvRw0VTXH5P1O4LVnTds8jeHlqBiiDRpoUxVzQ,5559 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/REQUESTED b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/WHEEL new file mode 100644 index 0000000..de294b9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (74.1.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/pbr.json b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/pbr.json new file mode 100644 index 0000000..ab50f33 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/pbr.json @@ -0,0 +1 @@ +{"is_release": false, "git_version": "2d6ab69"} \ No newline at end of file diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/top_level.txt new file mode 100644 index 0000000..91a67a9 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pynput diff --git a/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/zip-safe b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput-1.8.1.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/__init__.py b/CLI/venv/lib/python3.12/site-packages/pynput/__init__.py new file mode 100644 index 0000000..b6ab843 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/__init__.py @@ -0,0 +1,41 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The main *pynput* module. + +This module imports ``keyboard`` and ``mouse``. +""" + +def _logger(cls): + """Creates a logger with a name suitable for a specific class. + + This function takes into account that implementations for classes reside in + platform dependent modules, and thus removes the final part of the module + name. + + :param type cls: The class for which to create a logger. + + :return: a logger + """ + import logging + return logging.getLogger('{}.{}'.format( + '.'.join(cls.__module__.split('.', 2)[:2]), + cls.__name__)) + + +from . import keyboard +from . import mouse diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a86865602d711223b2e2b5610345514e4149bb0 GIT binary patch literal 1113 zcmZWo&r2IY6rN48Nt#4k4HzgQgJ2<2vuL3QDPHWQAX2DM@Ze^$JIPMmo!!n%l=uUB z=*3gplkKTJTKot4H?)_E2W1bv^yJMNdhygZo5X`Y*x5I4-}~l!-`n{)GEzWb(bW&{ zsfo}Zy%}0+;Pf7WbBJ8Dj$Gp%S~uL3oAy&ddOd9*@H60N)-wj`n$_&iN@2~TI3SGU z*{I8-j+(_m=yrTsE5Iiv2RqDyC=^QKdVQ028zB*Hy^aZYArOQeN$d4m!7+wp;H{aa z;pu&c1^56DAMG1^Mq5X3nVW7yKex@zv~#y(2<@SE{%*8gyc=^fu6aDr1v)n$qT>NW zz$o3#ALb6TUZHB1EJ4Y#phQuL3HHNQiweBWlm|Ob0*YmaDbnyMZiWJ4GNKM^G6y?8 zkrGtIV2P5=4tEp_IaXv7z!+B{CXN$!xWdXKN^9)XfO182noIx_6v!4-GM7S8f*1Kj z!Eph0X+*gTC4)K1$H`EX*U=?GxCNyOCfsD4_&6d$;jo!R`cqEObQ=Sri;zMBthy0} z2IL|z*A8@&u-W#Q<6+?KB#PV!GOQL0S|K32M}@V#^1|Ape9Q7#!-~4f3;C1U{DLK!qH_^(Hc5+0_@FO= zW!sE1W!tr=8|Uo))Wv-`rJ|2}3Cmm5n?Ppyyf}VVoIEK`etP|7OifMnP^wh9L@Be<159+G|Iexs z=ZBXJd^5RUt5p+-*ly_9c0wdZVjPl18J2HIJkb6qEZ6yGea)7H=Bfdub}rL~Vf>xW U7@4cms8RVhjf~1~R89*2101j;DgXcg literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/_info.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/__pycache__/_info.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a02037fcfe5b91f53eba3e908cbe27cd2b0fad90 GIT binary patch literal 255 zcmX@j%ge<81O=Z?Ww0|dFgylvV1N0(qt~>1q%7*7pE30 z1SIC<9$s0b$@~(e{v`*HC}IKjzOG`5Hi{j&NamUA(r4|)u=I6!7uVnZP zRKf5oP(L@XMBk+-vn3C$TgyIU}`5-`U4gzbrMcOg|?xNxz^HXiT25 zo}rO`ab`)XZb4#lc4B&JF;F6}ptM9kJ~J;ZU$3C@7l%!5eoARhs$CH$&<2o`iUonh Z2WCb_#t$kCd~yw3H~7RGxr^9=q5xaqMa%#I literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_info.py b/CLI/venv/lib/python3.12/site-packages/pynput/_info.py new file mode 100644 index 0000000..91bf033 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_info.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# pystray +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +__author__ = u'Moses Palmér' +__version__ = (1, 8, 1) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__init__.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__init__.py new file mode 100644 index 0000000..c7d98b4 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__init__.py @@ -0,0 +1,489 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +General utility functions and classes. +""" + +# pylint: disable=R0903 +# We implement minimal mixins + +# pylint: disable=W0212 +# We implement an internal API + +import contextlib +import functools +import importlib +import inspect +import os +import sys +import threading +import time + +import six + +from six.moves import queue + + +#: Possible resolutions for import related errors. +RESOLUTIONS = { + 'darwin': 'Please make sure that you have Python bindings for the ' + 'system frameworks installed', + 'uinput': 'Please make sure that you are running as root, and that ' + 'the utility dumpkeys is installed', + 'xorg': 'Please make sure that you have an X server running, and that ' + 'the DISPLAY environment variable is set correctly'} + + +def backend(package): + """Returns the backend module for a package. + + :param str package: The package for which to load a backend. + """ + backend_name = os.environ.get( + 'PYNPUT_BACKEND_{}'.format(package.rsplit('.')[-1].upper()), + os.environ.get('PYNPUT_BACKEND', None)) + if backend_name: + modules = [backend_name] + elif sys.platform == 'darwin': + modules = ['darwin'] + elif sys.platform == 'win32': + modules = ['win32'] + else: + modules = ['xorg'] + + errors = [] + resolutions = [] + for module in modules: + try: + return importlib.import_module('._' + module, package) + except ImportError as e: + errors.append(e) + if module in RESOLUTIONS: + resolutions.append(RESOLUTIONS[module]) + + raise ImportError('this platform is not supported: {}'.format( + '; '.join(str(e) for e in errors)) + ('\n\n' + 'Try one of the following resolutions:\n\n' + + '\n\n'.join( + ' * {}'.format(s) + for s in resolutions)) + if resolutions else '') + + +def prefix(base, cls): + """Calculates the prefix to use for platform specific options for a + specific class. + + The prefix if the name of the module containing the class that is an + immediate subclass of ``base`` among the super classes of ``cls``. + """ + for super_cls in filter( + lambda cls: issubclass(cls, base), + cls.__mro__[1:]): + if super_cls is base: + return cls.__module__.rsplit('.', 1)[-1][1:] + '_' + else: + result = prefix(base, super_cls) + if result is not None: + return result + + +class AbstractListener(threading.Thread): + """A class implementing the basic behaviour for event listeners. + + Instances of this class can be used as context managers. This is equivalent + to the following code:: + + listener.start() + listener.wait() + try: + with_statements() + finally: + listener.stop() + + Actual implementations of this class must set the attribute ``_log``, which + must be an instance of :class:`logging.Logger`. + + :param bool suppress: Whether to suppress events. Setting this to ``True`` + will prevent the input events from being passed to the rest of the + system. + + :param kwargs: A mapping from callback attribute to callback handler. All + handlers will be wrapped in a function reading the return value of the + callback, and if it ``is False``, raising :class:`StopException`. + + Any callback that is falsy will be ignored. + """ + class StopException(Exception): + """If an event listener callback raises this exception, the current + listener is stopped. + """ + pass + + #: Exceptions that are handled outside of the emitter and should thus not + #: be passed through the queue + _HANDLED_EXCEPTIONS = tuple() + + def __init__(self, suppress=False, **kwargs): + super(AbstractListener, self).__init__() + + def wrapper(f): + def inner(*args): + if f(*args) is False: + raise self.StopException() + return inner + + self._suppress = suppress + self._running = False + self._thread = threading.current_thread() + self._condition = threading.Condition() + self._ready = False + + # Allow multiple calls to stop + self._queue = queue.Queue(10) + + self.daemon = True + + for name, callback in kwargs.items(): + setattr(self, name, wrapper(callback)) + + @property + def suppress(self): + """Whether to suppress events. + """ + return self._suppress + + @property + def running(self): + """Whether the listener is currently running. + """ + return self._running + + def stop(self): + """Stops listening for events. + + When this method returns, no more events will be delivered. Once this + method has been called, the listener instance cannot be used any more, + since a listener is a :class:`threading.Thread`, and once stopped it + cannot be restarted. + + To resume listening for event, a new listener must be created. + """ + if self._running: + self._running = False + self._queue.put(None) + self._stop_platform() + + def __enter__(self): + self.start() + self.wait() + return self + + def __exit__(self, exc_type, value, traceback): + self.stop() + + def wait(self): + """Waits for this listener to become ready. + """ + self._condition.acquire() + while not self._ready: + self._condition.wait() + self._condition.release() + + def run(self): + """The thread runner method. + """ + self._running = True + self._thread = threading.current_thread() + self._run() + + # Make sure that the queue contains something + self._queue.put(None) + + @classmethod + def _emitter(cls, f): + """A decorator to mark a method as the one emitting the callbacks. + + This decorator will wrap the method and catch exception. If a + :class:`StopException` is caught, the listener will be stopped + gracefully. If any other exception is caught, it will be propagated to + the thread calling :meth:`join` and reraised there. + """ + @functools.wraps(f) + def inner(self, *args, **kwargs): + # pylint: disable=W0702; we want to catch all exception + try: + return f(self, *args, **kwargs) + except Exception as e: + if not isinstance(e, self._HANDLED_EXCEPTIONS): + if not isinstance(e, AbstractListener.StopException): + self._log.exception( + 'Unhandled exception in listener callback') + self._queue.put( + None if isinstance(e, cls.StopException) + else sys.exc_info()) + self.stop() + raise + # pylint: enable=W0702 + + return inner + + def _mark_ready(self): + """Marks this listener as ready to receive events. + + This method must be called from :meth:`_run`. :meth:`wait` will block + until this method is called. + """ + self._condition.acquire() + self._ready = True + self._condition.notify() + self._condition.release() + + def _run(self): + """The implementation of the :meth:`run` method. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _stop_platform(self): + """The implementation of the :meth:`stop` method. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _wrap(self, f, args): + """Wraps a callable to make it accept ``args`` number of arguments. + + :param f: The callable to wrap. If this is ``None`` a no-op wrapper is + returned. + + :param int args: The number of arguments to accept. + + :raises ValueError: if f requires more than ``args`` arguments + """ + if f is None: + return lambda *a: None + else: + argspec = inspect.getfullargspec(f) + actual = len(inspect.signature(f).parameters) + defaults = len(argspec.defaults) if argspec.defaults else 0 + if actual - defaults > args: + raise ValueError(f) + elif actual >= args or argspec.varargs is not None: + return f + else: + return lambda *a: f(*a[:actual]) + + def join(self, timeout=None, *args): + start = time.time() + super(AbstractListener, self).join(timeout, *args) + timeout = max(0.0, timeout - (time.time() - start)) \ + if timeout is not None \ + else None + + # Reraise any exceptions; make sure not to block if a timeout was + # provided + try: + exc_type, exc_value, exc_traceback = self._queue.get( + timeout=timeout) + six.reraise(exc_type, exc_value, exc_traceback) + except queue.Empty: + pass + except TypeError: + return + + +class Events(object): + """A base class to enable iterating over events. + """ + #: The listener class providing events. + _Listener = None + + class Event(object): + def __str__(self): + return '{}({})'.format( + self.__class__.__name__, + ', '.join( + '{}={}'.format(k, v) + for (k, v) in vars(self).items())) + + def __eq__(self, other): + return self.__class__ == other.__class__ \ + and dir(self) == dir(other) \ + and all( + getattr(self, k) == getattr(other, k) + for k in dir(self)) + + def __init__(self, *args, **kwargs): + super(Events, self).__init__() + self._event_queue = queue.Queue() + self._sentinel = object() + self._listener = self._Listener(*args, **{ + key: self._event_mapper(value) + for (key, value) in kwargs.items()}) + self.start = self._listener.start + + def __enter__(self): + self._listener.__enter__() + return self + + def __exit__(self, *args): + self._listener.__exit__(*args) + + # Drain the queue to ensure that the put does not block + while True: + try: + self._event_queue.get_nowait() + except queue.Empty: + break + + self._event_queue.put(self._sentinel) + + def __iter__(self): + return self + + def __next__(self): + event = self.get() + if event is not None: + return event + else: + raise StopIteration() + + def get(self, timeout=None): + """Attempts to read the next event. + + :param int timeout: An optional timeout. If this is not provided, this + method may block infinitely. + + :return: the next event, or ``None`` if the source has been stopped or + no events were received + """ + try: + event = self._event_queue.get(timeout=timeout) + return event if event is not self._sentinel else None + except queue.Empty: + return None + + def _event_mapper(self, event): + """Generates an event callback to transforms the callback arguments to + an event and then publishes it. + + :param callback event: A function generating an event object. + + :return: a callback + """ + @functools.wraps(event) + def inner(*args): + try: + self._event_queue.put(event(*args), block=False) + except queue.Full: + pass + + return inner + + +class NotifierMixin(object): + """A mixin for notifiers of fake events. + + This mixin can be used for controllers on platforms where sending fake + events does not cause a listener to receive a notification. + """ + def _emit(self, action, *args): + """Sends a notification to all registered listeners. + + This method will ensure that listeners that raise + :class:`StopException` are stopped. + + :param str action: The name of the notification. + + :param args: The arguments to pass. + """ + stopped = [] + for listener in self._listeners(): + try: + getattr(listener, action)(*args) + except listener.StopException: + stopped.append(listener) + for listener in stopped: + listener.stop() + + @classmethod + def _receiver(cls, listener_class): + """A decorator to make a class able to receive fake events from a + controller. + + This decorator will add the method ``_receive`` to the decorated class. + + This method is a context manager which ensures that all calls to + :meth:`_emit` will invoke the named method in the listener instance + while the block is active. + """ + @contextlib.contextmanager + def receive(self): + """Executes a code block with this listener instance registered as + a receiver of fake input events. + """ + self._controller_class._add_listener(self) + try: + yield + finally: + self._controller_class._remove_listener(self) + + listener_class._receive = receive + listener_class._controller_class = cls + + # Make sure this class has the necessary attributes + if not hasattr(cls, '_listener_cache'): + cls._listener_cache = set() + cls._listener_lock = threading.Lock() + + return listener_class + + @classmethod + def _listeners(cls): + """Iterates over the set of running listeners. + + This method will quit without acquiring the lock if the set is empty, + so there is potential for race conditions. This is an optimisation, + since :class:`Controller` will need to call this method for every + control event. + """ + if not cls._listener_cache: + return + with cls._listener_lock: + for listener in cls._listener_cache: + yield listener + + @classmethod + def _add_listener(cls, listener): + """Adds a listener to the set of running listeners. + + :param listener: The listener for fake events. + """ + with cls._listener_lock: + cls._listener_cache.add(listener) + + @classmethod + def _remove_listener(cls, listener): + """Removes this listener from the set of running listeners. + + :param listener: The listener for fake events. + """ + with cls._listener_lock: + cls._listener_cache.remove(listener) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83591ea334f35df2ec4cb40fe2db17bb2bff0e5f GIT binary patch literal 22694 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/darwin_vks.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/darwin_vks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b195c39d97e1da6f64f816a63570226ded3a1121 GIT binary patch literal 1654 zcmZ9MIa6C_6o&5y2nmGP_kA%40n$Yht66LVUa$q&h#g@NIxE&o%AR7C?2qV@{fO1F zajcQeV6E&m*2(6uUe=EdvH@(A4Puk*1UAb~VT?N9V?nA$9F9u{!aFZ6pj4gu4j@#@zj9tbaW1n%zh!EC2>dqeCUt8J; zh5s@hn|PrSm!SIG;;im=Mi;Os0+t=UHF+`oS@Oc?J24_+lnaH{+j5 z_D}ku6iby-#o;+;$>%cLFWF)#**{`7vSPVmE2mRCyF+^gd!=?KdzE$t5cd>VC?_uxN-pAfA{%wH$kv<<}AJXn- zAJ*<+AJIO_KBnEv?$d6vk8Ag{2eb#-C$vwpPidcKpV2(;dmskc_WliIZ28J60zu5C-v ze`|RxyHa~r?Moe4bto0F>PYInRmV~%Rz;;wt%^y3RdJ~gy1t!BC6rN7_1WS4-`{ literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/uinput.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/uinput.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1945f6a3f1341f178e3aed74c061d98a85ec53a GIT binary patch literal 3455 zcmbUkO>Y~=b!I=vB}GZJEjiYgyOx;1lpV=++Q3#7$8M!2P8Iba*{D?q>lJq-t-R#2 zvrE|`C_qgNluDG!J|uEZNr3=~;TGs$Xpim1vS5f^_~4?K_NK2Et`9}u8**it^{Efw z%%#fK4a-JY>2^o+uiR!0H7tCD=gNc^8IXfuM|l=0I;2 zosdCyN~pUDwM?c!v$wQ~h|p{lwK$PZqkW{F_Ml3jU%?_vmE2^+c)i8 zaruIt#f8w}p8gm-(bt_Crq>sb>i}bg$x!3oj9YLl-DAFP>T{-3V1mGa>HB=(nlXHN zcyxU1nlO@`%{wd$^aPE8Ec0goV+QQ!FeA%64>WeIPaI~bcye`!!qg1Eo&Uh_8C@m* z-l-odhm^>t;DRM;lall`{WYbqGmAIt0CrL7bubG~TMriX8^gWXrf~Iq4%L3YCd2)j zR3&2UaR6=ypWg^qyaV==;n(wdw)OcsT!maH_~$%HOQS);Vsmze8F|y6@zM=}>J{>g za}2;hGYmUt`-TxjjVc;!xp@&NfjrIpKxK1q5G2r~H54yUa204kD9^zTfilg_$+QwE z9&@Gw#pKgo5V?Ls%rV0dwl@q9;|9E8k)xhDs;GGQ1*hr@#W@LQ9(wiDMeH1CA#U0k}jGP*SSDABnolSErJg7#bln4+8_&_9R8Dmn(t z^)QPVbr33lhJH$uL_=qxWVufP!*ZmXR(T6d zL5wrgG91^<2Z}$RXJE`~90kpF;c`#nuiy=^D#VqCo~Y}>9AHyk$Q2LP*#q{z2S^^~ z;zd$vZCkx^=gLOw@wL|D>#e=pM2ej(4_BI7R*Fl-yW?M8{o?Aw=5!_5vXM-!B~xEr zdXzk|r2^9bDj9hTC7*%C|D$B|@TwZ5sv6Xc<9aMj#S=X=XzgiDhUdF^Bk!0#B>Zf# zv+j{EoSuby9tImcS4*tKmSQW-OU;k8nxE_?5WqkyiYIgeGt9IWy$a_G(t=!~-~$${ zmDs-YGrRvbTt+A^I=Ia~X!u=uZe0 z-uQt|h%hDvCDA4MWhr2e@J1gUKtM?fRq{DqrJ%HK4AkGrH)!akM*%O89hQSsDfOM= z$M9RtxEAxOK8vz|oYe&REH*d|<@RQtpDP}(^Vpi61|2tJI^MayJyhIxyyq@#>|_O*lpR&3uLd54OHlDvK~*trLa0eaIs&J_Uk@aLRB373CI@22%0ruq+}QTGL*M8)xz=&=+wt{|)3>$FIO$Anbevl2I0fJ3 zk;iSFJE*%SsZ$%NH`h{cuBXoIs;~jO?Y-sqHZ_uLzdQV}`B>%f(c5z6NcSD}N%F{Q z)19VANqw^iIBmX063yiwJU-a=p#9AH!Ltt%XP+E8Tz>EA?yIDwW1G;%w!b8gY|1b{ z^A3Q(pSE6jTl&M>u^%?5e~eQYGyBs8u0^sr42%6eO&F#hQn260?~3*ax?J6}bJGw5 zBGd1Sl<^tc)3KLwp$n@vW8g!M?&cT<7Iwp&O=APcnN_{5BLa5DVLyk4s70nAKcJ7p zwHhZpL`c)%(5UNQ47)gH2|wXF$iKhx@bADzv8&FQFSdDC@eZb_MY7vOn!DGVdLC#! zqNt=3*u~_`EQ2m4ZWvkDDnNf|1PR0VMZt7xCsD(&+zf21egWD_jrYQMIiEX>R#sdhwlIC8Bn1 zCuQ~IcATp1+mWN{EB`uAqiRaXEp9^vM}HMzC7Syn;!e)8j4w{bUyCX-c1+K-!Rq7A y@$>MB1Cpqpf=|R1WN@nw> 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/win32_vks.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/win32_vks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1606445a8834b16f0a12cadb9463e81ad3125ee9 GIT binary patch literal 3813 zcmb`{cW@Kg9S3k3tIHKrkKQ}7WiW8Z!L6k=mc7~)tCh8@Auli-F>@1sH_Zo=msD&t8siOZ>+z2s#d`Pff>4p4xD6yy+vI80%V zP=qU}f-9+#tEh^rsalpAS!%h4CUY&-@no7J%T%tTX*`9d^HiF_(`Y77r$=}O&ElCf zn;)S$Jd5V?Y?{Y&Xg<%S1w4-y@_bsv3urMfq$RwFmhxg+#!F~9FQpZ{j8^h;TE#19 zHLs*Kyo%QHYKrn2s^_)Tz)^~EJvDLzt>YN2=SFJcb+m!k(?)KhO}v2~<&E?hZ=%io zC_T=P(H7oJTlsN%g13;yTdA3!pg3!k;AYY}PA#0EZLCu(w@{L|Q5&~XJ15EDHcD|j znQV~7DN3_R+u0(U)0E-u3M#JUf^fxMShO1^7C|! zU!d#!BHiGtbd#^qExt~-`3BwLoAeUjqL=wLy~20sRep(H;yE0Y3un#ck0sFxL&R36U<8bUF>nkV2jk!bI0;UH)8Gs^3-aI`I1es>i{KKt46cBy;2O9NZh)KM z7Pt-G03QM$1|I<*1s?++2cH0+1aE>*flq_afX{-@fzN|4fG>hCfiHuvfUknDfv_5#_p>5Z+cRr3u0-tQa&FgLTDVeKBY%1{;dO#$vEZ1XEeVNv4f% zQLZHtB9zh7nyoqVVuP7%vtw)WG6M2;BvbNc`V+~HWI`8{S{h`D$(@?8Dr#vbNQp6_G-_VRdT{6B~)&aQB_xc8@`$ zxB-K9G4dJiUbNMrqS>}O<%7(rtz2EqS}eO$vlHTBg{`;PdZtx8?4NP0w5Tff&&bUm zZxyx0yhZDGiiw)Fu(69hntZq1 zpwV4!XD060M&W|wm&kC(YK~*N9po2B?m)LTZl${m?ODfiBi%GQ-5rPRg72PJ4fe%t z%;wX(+=H!KEy9ZjBD`c-DdCr2DNTNE%CS24hT?nqrUxHx&x0M&!viDH#8BT@Pb}*6 z4ILTm8!`5b4(#jg8H&b@WOS@&U@Y3-w>LUCKGJ(+pmA+OEIQmb(z9l8&%Q%@4)hGm zhJnG+k!Wsoq_01EtZ$$(mK!@XymoN>L2&coBRtyQvt>vt^LXUnGrYRoJ6RET`y_zagDVMA26s2LMsI*8m;$2kY^52h0 zm7Lihl544`&W9#csyc@% zNQGLsA{dd6QK5!So|>NRcVT~D2R zUX`nJs8gz;3N@y*g7=Non$=aR2~?`as##R3BGvkyhga&ST2-o|5^8;cF!t`lyP+ag Rr%>l8Jos~=p{??@`7e`$pm+cP literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/xorg.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/_util/__pycache__/xorg.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad837f248b33578192ef2e4ce8719c924671b30c GIT binary patch literal 18809 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin.py new file mode 100644 index 0000000..fdc284b --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin.py @@ -0,0 +1,302 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +Utility functions and classes for the *Darwin* backend. +""" + +# pylint: disable=C0103 +# pylint: disable=R0903 +# This module contains wrapper classes + +import contextlib +import ctypes +import ctypes.util +import six + +import objc +import HIServices + +from CoreFoundation import ( + CFRelease +) + +from Quartz import ( + CFMachPortCreateRunLoopSource, + CFRunLoopAddSource, + CFRunLoopGetCurrent, + CFRunLoopRunInMode, + CFRunLoopStop, + CGEventGetIntegerValueField, + CGEventTapCreate, + CGEventTapEnable, + kCFRunLoopDefaultMode, + kCFRunLoopRunTimedOut, + kCGEventSourceUnixProcessID, + kCGEventTapOptionDefault, + kCGEventTapOptionListenOnly, + kCGHeadInsertEventTap, + kCGSessionEventTap) + + +from . import AbstractListener + + +def _wrap_value(value): + """Converts a pointer to a *Python objc* value. + + :param value: The pointer to convert. + + :return: a wrapped value + """ + return objc.objc_object(c_void_p=value) if value is not None else None + + +@contextlib.contextmanager +def _wrapped(value): + """A context manager that converts a raw pointer to a *Python objc* value. + + When the block is exited, the value is released. + + :param value: The raw value to wrap. + """ + wrapped_value = _wrap_value(value) + + try: + yield value + finally: + CFRelease(wrapped_value) + + +class CarbonExtra(object): + """A class exposing some missing functionality from *Carbon* as class + attributes. + """ + _Carbon = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Carbon')) + + _Carbon.TISCopyCurrentKeyboardInputSource.argtypes = [] + _Carbon.TISCopyCurrentKeyboardInputSource.restype = ctypes.c_void_p + + _Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource.argtypes = [] + _Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource.restype = \ + ctypes.c_void_p + + _Carbon.TISGetInputSourceProperty.argtypes = [ + ctypes.c_void_p, ctypes.c_void_p] + _Carbon.TISGetInputSourceProperty.restype = ctypes.c_void_p + + _Carbon.LMGetKbdType.argtypes = [] + _Carbon.LMGetKbdType.restype = ctypes.c_uint32 + + _Carbon.UCKeyTranslate.argtypes = [ + ctypes.c_void_p, + ctypes.c_uint16, + ctypes.c_uint16, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(ctypes.c_uint32), + ctypes.c_uint8, + ctypes.POINTER(ctypes.c_uint8), + ctypes.c_uint16 * 4] + _Carbon.UCKeyTranslate.restype = ctypes.c_uint32 + + TISCopyCurrentKeyboardInputSource = \ + _Carbon.TISCopyCurrentKeyboardInputSource + + TISCopyCurrentASCIICapableKeyboardLayoutInputSource = \ + _Carbon.TISCopyCurrentASCIICapableKeyboardLayoutInputSource + + kTISPropertyUnicodeKeyLayoutData = ctypes.c_void_p.in_dll( + _Carbon, 'kTISPropertyUnicodeKeyLayoutData') + + TISGetInputSourceProperty = \ + _Carbon.TISGetInputSourceProperty + + LMGetKbdType = \ + _Carbon.LMGetKbdType + + kUCKeyActionDisplay = 3 + kUCKeyTranslateNoDeadKeysBit = 0 + + UCKeyTranslate = \ + _Carbon.UCKeyTranslate + + +@contextlib.contextmanager +def keycode_context(): + """Returns an opaque value representing a context for translating keycodes + to strings. + """ + keyboard_type, layout_data = None, None + for source in [ + CarbonExtra.TISCopyCurrentKeyboardInputSource, + CarbonExtra.TISCopyCurrentASCIICapableKeyboardLayoutInputSource]: + with _wrapped(source()) as keyboard: + keyboard_type = CarbonExtra.LMGetKbdType() + layout = _wrap_value(CarbonExtra.TISGetInputSourceProperty( + keyboard, + CarbonExtra.kTISPropertyUnicodeKeyLayoutData)) + layout_data = layout.bytes().tobytes() if layout else None + if keyboard is not None and layout_data is not None: + break + yield (keyboard_type, layout_data) + + +def keycode_to_string(context, keycode, modifier_state=0): + """Converts a keycode to a string. + """ + LENGTH = 4 + + keyboard_type, layout_data = context + + dead_key_state = ctypes.c_uint32() + length = ctypes.c_uint8() + unicode_string = (ctypes.c_uint16 * LENGTH)() + CarbonExtra.UCKeyTranslate( + layout_data, + keycode, + CarbonExtra.kUCKeyActionDisplay, + modifier_state, + keyboard_type, + CarbonExtra.kUCKeyTranslateNoDeadKeysBit, + ctypes.byref(dead_key_state), + LENGTH, + ctypes.byref(length), + unicode_string) + return u''.join( + six.unichr(unicode_string[i]) + for i in range(length.value)) + + +def get_unicode_to_keycode_map(): + """Returns a mapping from unicode strings to virtual key codes. + + :return: a dict mapping key codes to strings + """ + with keycode_context() as context: + return { + keycode_to_string(context, keycode): keycode + for keycode in range(128)} + + +class ListenerMixin(object): + """A mixin for *Quartz* event listeners. + + Subclasses should set a value for :attr:`_EVENTS` and implement + :meth:`_handle_message`. + """ + #: The events that we listen to + _EVENTS = tuple() + + #: Whether this process is trusted to monitor input events. + IS_TRUSTED = False + + def _run(self): + self.IS_TRUSTED = HIServices.AXIsProcessTrusted() + if not self.IS_TRUSTED: + self._log.warning( + 'This process is not trusted! Input event monitoring will not ' + 'be possible until it is added to accessibility clients.') + + self._loop = None + try: + tap = self._create_event_tap() + if tap is None: + self._mark_ready() + return + + loop_source = CFMachPortCreateRunLoopSource( + None, tap, 0) + self._loop = CFRunLoopGetCurrent() + + CFRunLoopAddSource( + self._loop, loop_source, kCFRunLoopDefaultMode) + CGEventTapEnable(tap, True) + + self._mark_ready() + + # pylint: disable=W0702; we want to silence errors + try: + while self.running: + result = CFRunLoopRunInMode( + kCFRunLoopDefaultMode, 1, False) + try: + if result != kCFRunLoopRunTimedOut: + break + except AttributeError: + # This happens during teardown of the virtual machine + break + + except: + # This exception will have been passed to the main thread + pass + # pylint: enable=W0702 + + finally: + self._loop = None + + def _stop_platform(self): + # The base class sets the running flag to False; this will cause the + # loop around run loop invocations to terminate and set this event + try: + if self._loop is not None: + CFRunLoopStop(self._loop) + except AttributeError: + # The loop may not have been created + pass + + def _create_event_tap(self): + """Creates the event tap used by the listener. + + :return: an event tap + """ + return CGEventTapCreate( + kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionListenOnly if ( + True + and not self.suppress + and self._intercept is None) + else kCGEventTapOptionDefault, + self._EVENTS, + self._handler, + None) + + @AbstractListener._emitter + def _handler(self, proxy, event_type, event, refcon): + """The callback registered with *macOS* for mouse events. + + This method will call the callbacks registered on initialisation. + """ + # An injected event will have a Unix process ID attached + is_injected = (CGEventGetIntegerValueField( + event, + kCGEventSourceUnixProcessID)) != 0 + + self._handle_message(proxy, event_type, event, refcon, is_injected) + if self._intercept is not None: + return self._intercept(event_type, event) + elif self.suppress: + return None + + def _handle_message(self, proxy, event_type, event, refcon): + """The device specific callback handler. + + This method calls the appropriate callback registered when this + listener was created based on the event. + """ + raise NotImplementedError() diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin_vks.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin_vks.py new file mode 100644 index 0000000..6499fb1 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/darwin_vks.py @@ -0,0 +1,79 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +# pylint: disable=C0111,C0302 + +SYMBOLS = { + 0: 'a', + 1: 's', + 2: 'd', + 3: 'f', + 4: 'h', + 5: 'g', + 6: 'z', + 7: 'x', + 8: 'c', + 9: 'v', + 11: 'b', + 12: 'q', + 13: 'w', + 14: 'e', + 15: 'r', + 16: 'y', + 17: 't', + 18: '1', + 19: '2', + 20: '3', + 21: '4', + 22: '6', + 23: '5', + 24: '=', + 25: '9', + 26: '7', + 27: '-', + 28: '8', + 29: '0', + 30: ']', + 31: 'o', + 32: 'u', + 33: '[', + 34: 'i', + 35: 'p', + 37: 'l', + 38: 'j', + 39: '\'', + 40: 'k', + 41: ';', + 42: '\\', + 43: ',', + 44: '/', + 45: 'n', + 46: 'm', + 47: '.', + 49: ' ', + 50: '`', + 82: '0', + 83: '1', + 84: '2', + 85: '3', + 86: '4', + 87: '5', + 88: '6', + 89: '7', + 91: '8', + 92: '9', +} diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/uinput.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/uinput.py new file mode 100644 index 0000000..b0a6a78 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/uinput.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +Utility functions and classes for the *uinput* backend. +""" + +# pylint: disable=R0903 +# We implement stubs + +import evdev + + +# Check that we have permissions to continue +def _check(): + # TODO: Implement! + pass +_check() +del _check + + +class ListenerMixin(object): + """A mixin for *uinput* event listeners. + + Subclasses should set a value for :attr:`_EVENTS` and implement + :meth:`_handle_message`. + """ + #: The events for which to listen + _EVENTS = tuple() + + def __init__(self, *args, **kwargs): + super(ListenerMixin, self).__init__(*args, **kwargs) + self._dev = self._device(self._options.get( + 'device_paths', + evdev.list_devices())) + if self.suppress: + self._dev.grab() + + def _run(self): + for event in self._dev.read_loop(): + if event.type in self._EVENTS: + self._handle_message(event) + + def _stop_platform(self): + self._dev.close() + + def _device(self, paths): + """Attempts to load a readable keyboard device. + + :param paths: A list of paths. + + :return: a compatible device + """ + dev, count = None, 0 + for path in paths: + # Open the device + try: + next_dev = evdev.InputDevice(path) + except OSError: + continue + + # Does this device provide more handled event codes? + capabilities = next_dev.capabilities() + next_count = sum( + len(codes) + for event, codes in capabilities.items() + if event in self._EVENTS) + if next_count > count: + dev = next_dev + count = next_count + else: + next_dev.close() + + if dev is None: + raise OSError('no keyboard device available') + else: + return dev + + def _handle_message(self, event): + """Handles a single event. + + This method should call one of the registered event callbacks. + + :param event: The event. + """ + raise NotImplementedError() diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32.py new file mode 100644 index 0000000..b945a59 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32.py @@ -0,0 +1,598 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +Utility functions and classes for the *win32* backend. +""" + +# pylint: disable=C0103 +# We want to make it obvious how structs are related + +# pylint: disable=R0903 +# This module contains a number of structs + +import contextlib +import ctypes +import itertools +import threading + +from ctypes import ( + windll, + wintypes) + +from . import AbstractListener, win32_vks as VK + + +# LPDWORD is not in ctypes.wintypes on Python 2 +if not hasattr(wintypes, 'LPDWORD'): + wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD) + + +class MOUSEINPUT(ctypes.Structure): + """Contains information about a simulated mouse event. + """ + MOVE = 0x0001 + LEFTDOWN = 0x0002 + LEFTUP = 0x0004 + RIGHTDOWN = 0x0008 + RIGHTUP = 0x0010 + MIDDLEDOWN = 0x0020 + MIDDLEUP = 0x0040 + XDOWN = 0x0080 + XUP = 0x0100 + WHEEL = 0x0800 + HWHEEL = 0x1000 + ABSOLUTE = 0x8000 + + XBUTTON1 = 0x0001 + XBUTTON2 = 0x0002 + + _fields_ = [ + ('dx', wintypes.LONG), + ('dy', wintypes.LONG), + ('mouseData', wintypes.DWORD), + ('dwFlags', wintypes.DWORD), + ('time', wintypes.DWORD), + ('dwExtraInfo', ctypes.c_void_p)] + + +class KEYBDINPUT(ctypes.Structure): + """Contains information about a simulated keyboard event. + """ + EXTENDEDKEY = 0x0001 + KEYUP = 0x0002 + SCANCODE = 0x0008 + UNICODE = 0x0004 + + _fields_ = [ + ('wVk', wintypes.WORD), + ('wScan', wintypes.WORD), + ('dwFlags', wintypes.DWORD), + ('time', wintypes.DWORD), + ('dwExtraInfo', ctypes.c_void_p)] + + +class HARDWAREINPUT(ctypes.Structure): + """Contains information about a simulated message generated by an input + device other than a keyboard or mouse. + """ + _fields_ = [ + ('uMsg', wintypes.DWORD), + ('wParamL', wintypes.WORD), + ('wParamH', wintypes.WORD)] + + +class INPUT_union(ctypes.Union): + """Represents the union of input types in :class:`INPUT`. + """ + _fields_ = [ + ('mi', MOUSEINPUT), + ('ki', KEYBDINPUT), + ('hi', HARDWAREINPUT)] + + +class INPUT(ctypes.Structure): + """Used by :attr:`SendInput` to store information for synthesizing input + events such as keystrokes, mouse movement, and mouse clicks. + """ + MOUSE = 0 + KEYBOARD = 1 + HARDWARE = 2 + + _fields_ = [ + ('type', wintypes.DWORD), + ('value', INPUT_union)] + + +LPINPUT = ctypes.POINTER(INPUT) + +VkKeyScan = windll.user32.VkKeyScanW +VkKeyScan.argtypes = ( + wintypes.WCHAR,) + +MapVirtualKey = windll.user32.MapVirtualKeyW +MapVirtualKey.argtypes = ( + wintypes.UINT, + wintypes.UINT) +MapVirtualKey.MAPVK_VK_TO_VSC = 0 + +SendInput = windll.user32.SendInput +SendInput.argtypes = ( + wintypes.UINT, + ctypes.c_voidp, # Really LPINPUT + ctypes.c_int) + +GetCurrentThreadId = windll.kernel32.GetCurrentThreadId +GetCurrentThreadId.restype = wintypes.DWORD + + +class MessageLoop(object): + """A class representing a message loop. + """ + #: The message that signals this loop to terminate + WM_STOP = 0x0401 + + _LPMSG = ctypes.POINTER(wintypes.MSG) + + _GetMessage = windll.user32.GetMessageW + _GetMessage.argtypes = ( + ctypes.c_voidp, # Really _LPMSG + wintypes.HWND, + wintypes.UINT, + wintypes.UINT) + _PeekMessage = windll.user32.PeekMessageW + _PeekMessage.argtypes = ( + ctypes.c_voidp, # Really _LPMSG + wintypes.HWND, + wintypes.UINT, + wintypes.UINT, + wintypes.UINT) + _PostThreadMessage = windll.user32.PostThreadMessageW + _PostThreadMessage.argtypes = ( + wintypes.DWORD, + wintypes.UINT, + wintypes.WPARAM, + wintypes.LPARAM) + + PM_NOREMOVE = 0 + + def __init__(self): + self._threadid = None + self._event = threading.Event() + self.thread = None + + def __iter__(self): + """Initialises the message loop and yields all messages until + :meth:`stop` is called. + + :raises AssertionError: if :meth:`start` has not been called + """ + assert self._threadid is not None + + try: + # Pump messages until WM_STOP + while True: + msg = wintypes.MSG() + lpmsg = ctypes.byref(msg) + r = self._GetMessage(lpmsg, None, 0, 0) + if r <= 0 or msg.message == self.WM_STOP: + break + else: + yield msg + + finally: + self._threadid = None + self.thread = None + + def start(self): + """Starts the message loop. + + This method must be called before iterating over messages, and it must + be called from the same thread. + """ + self._threadid = GetCurrentThreadId() + self.thread = threading.current_thread() + + # Create the message loop + msg = wintypes.MSG() + lpmsg = ctypes.byref(msg) + self._PeekMessage(lpmsg, None, 0x0400, 0x0400, self.PM_NOREMOVE) + + # Set the event to signal to other threads that the loop is created + self._event.set() + + def stop(self): + """Stops the message loop. + """ + self._event.wait() + if self._threadid: + self.post(self.WM_STOP, 0, 0) + + def post(self, msg, wparam, lparam): + """Posts a message to this message loop. + + :param ctypes.wintypes.UINT msg: The message. + + :param ctypes.wintypes.WPARAM wparam: The value of ``wParam``. + + :param ctypes.wintypes.LPARAM lparam: The value of ``lParam``. + """ + self._PostThreadMessage(self._threadid, msg, wparam, lparam) + + +class SystemHook(object): + """A class to handle Windows hooks. + """ + #: The hook action value for actions we should check + HC_ACTION = 0 + + _HOOKPROC = ctypes.WINFUNCTYPE( + wintypes.LPARAM, + ctypes.c_int32, wintypes.WPARAM, wintypes.LPARAM) + + _SetWindowsHookEx = windll.user32.SetWindowsHookExW + _SetWindowsHookEx.argtypes = ( + ctypes.c_int, + _HOOKPROC, + wintypes.HINSTANCE, + wintypes.DWORD) + _UnhookWindowsHookEx = windll.user32.UnhookWindowsHookEx + _UnhookWindowsHookEx.argtypes = ( + wintypes.HHOOK,) + _CallNextHookEx = windll.user32.CallNextHookEx + _CallNextHookEx.argtypes = ( + wintypes.HHOOK, + ctypes.c_int, + wintypes.WPARAM, + wintypes.LPARAM) + + #: The registered hook procedures + _HOOKS = {} + + class SuppressException(Exception): + """An exception raised by a hook callback to suppress further + propagation of events. + """ + pass + + def __init__(self, hook_id, on_hook=lambda code, msg, lpdata: None): + self.hook_id = hook_id + self.on_hook = on_hook + self._hook = None + + def __enter__(self): + key = threading.current_thread().ident + assert key not in self._HOOKS + + # Add ourself to lookup table and install the hook + self._HOOKS[key] = self + self._hook = self._SetWindowsHookEx( + self.hook_id, + self._handler, + None, + 0) + + return self + + def __exit__(self, exc_type, value, traceback): + key = threading.current_thread().ident + assert key in self._HOOKS + + if self._hook is not None: + # Uninstall the hook and remove ourself from lookup table + self._UnhookWindowsHookEx(self._hook) + del self._HOOKS[key] + + @staticmethod + @_HOOKPROC + def _handler(code, msg, lpdata): + key = threading.current_thread().ident + self = SystemHook._HOOKS.get(key, None) + if self: + # pylint: disable=W0702; we want to silence errors + try: + self.on_hook(code, msg, lpdata) + except self.SuppressException: + # Return non-zero to stop event propagation + return 1 + except: + # Ignore any errors + pass + # pylint: enable=W0702 + return SystemHook._CallNextHookEx(0, code, msg, lpdata) + + +class ListenerMixin(object): + """A mixin for *win32* event listeners. + + Subclasses should set a value for :attr:`_EVENTS` and implement + :meth:`_handle_message`. + + Subclasses must also be decorated with a decorator compatible with + :meth:`pynput._util.NotifierMixin._receiver` or implement the method + ``_receive()``. + """ + #: The Windows hook ID for the events to capture. + _EVENTS = None + + #: The window message used to signal that an even should be handled. + _WM_PROCESS = 0x410 + + #: Additional window messages to propagate to the subclass handler. + _WM_NOTIFICATIONS = [] + + def suppress_event(self): + """Causes the currently filtered event to be suppressed. + + This has a system wide effect and will generally result in no + applications receiving the event. + + This method will raise an undefined exception. + """ + raise SystemHook.SuppressException() + + def _run(self): + self._message_loop = MessageLoop() + with self._receive(): + self._mark_ready() + self._message_loop.start() + + # pylint: disable=W0702; we want to silence errors + try: + with SystemHook(self._EVENTS, self._handler): + # Just pump messages + for msg in self._message_loop: + if not self.running: + break + if msg.message == self._WM_PROCESS: + self._process(msg.wParam, msg.lParam) + elif msg.message in self._WM_NOTIFICATIONS: + self._on_notification( + msg.message, msg.wParam, msg.lParam) + except: + # This exception will have been passed to the main thread + pass + # pylint: enable=W0702 + + def _stop_platform(self): + try: + self._message_loop.stop() + except AttributeError: + # The loop may not have been created + pass + + @AbstractListener._emitter + def _handler(self, code, msg, lpdata): + """The callback registered with *Windows* for events. + + This method will post the message :attr:`_WM_PROCESS` to the message + loop started with this listener using :meth:`MessageLoop.post`. The + parameters are retrieved with a call to :meth:`_handle`. + """ + try: + converted = self._convert(code, msg, lpdata) + if converted is not None: + self._message_loop.post(self._WM_PROCESS, *converted) + except NotImplementedError: + self._handle_message(code, msg, lpdata) + + if self.suppress: + self.suppress_event() + + def _convert(self, code, msg, lpdata): + """The device specific callback handler. + + This method converts a low-level message and data to a + ``WPARAM`` / ``LPARAM`` pair. + """ + raise NotImplementedError() + + def _process(self, wparam, lparam): + """The device specific callback handler. + + This method performs the actual dispatching of events. + """ + raise NotImplementedError() + + def _handle_message(self, code, msg, lpdata): + """The device specific callback handler. + + This method calls the appropriate callback registered when this + listener was created based on the event. + + This method is only called if :meth:`_convert` is not implemented. + """ + raise NotImplementedError() + + def _on_notification(self, code, wparam, lparam): + """An additional notification handler. + + This method will be called for every message in + :attr:`_WM_NOTIFICATIONS`. + """ + raise NotImplementedError() + + +class KeyTranslator(object): + """A class to translate virtual key codes to characters. + """ + _GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState + _GetAsyncKeyState.argtypes = ( + ctypes.c_int,) + _GetKeyboardLayout = ctypes.windll.user32.GetKeyboardLayout + _GetKeyboardLayout.argtypes = ( + wintypes.DWORD,) + _GetKeyboardState = ctypes.windll.user32.GetKeyboardState + _GetKeyboardState.argtypes = ( + ctypes.c_voidp,) + _GetKeyState = ctypes.windll.user32.GetAsyncKeyState + _GetKeyState.argtypes = ( + ctypes.c_int,) + _MapVirtualKeyEx = ctypes.windll.user32.MapVirtualKeyExW + _MapVirtualKeyEx.argtypes = ( + wintypes.UINT, + wintypes.UINT, + wintypes.HKL) + _ToUnicodeEx = ctypes.windll.user32.ToUnicodeEx + _ToUnicodeEx.argtypes = ( + wintypes.UINT, + wintypes.UINT, + ctypes.c_voidp, + ctypes.c_voidp, + ctypes.c_int, + wintypes.UINT, + wintypes.HKL) + + _MAPVK_VK_TO_VSC = 0 + _MAPVK_VSC_TO_VK = 1 + _MAPVK_VK_TO_CHAR = 2 + + def __init__(self): + self.update_layout() + + def __call__(self, vk, is_press): + """Converts a virtual key code to a string. + + :param int vk: The virtual key code. + + :param bool is_press: Whether this is a press. + + :return: parameters suitable for the :class:`pynput.keyboard.KeyCode` + constructor + + :raises OSError: if a call to any *win32* function fails + """ + # Get a string representation of the key + layout_data = self._layout_data[self._modifier_state()] + scan = self._to_scan(vk, self._layout) + character, is_dead = layout_data[scan] + + return { + 'char': character, + 'is_dead': is_dead, + 'vk': vk, + '_scan': scan} + + def update_layout(self): + """Updates the cached layout data. + """ + self._layout, self._layout_data = self._generate_layout() + + def char_from_scan(self, scan): + """Translates a scan code to a character, if possible. + + :param int scan: The scan code to translate. + + :return: maybe a character + :rtype: str or None + """ + return self._layout_data[(False, False, False)][scan][0] + + def _generate_layout(self): + """Generates the keyboard layout. + + This method will call ``ToUnicodeEx``, which modifies kernel buffers, + so it must *not* be called from the keyboard hook. + + The return value is the tuple ``(layout_handle, layout_data)``, where + ``layout_data`` is a mapping from the tuple ``(shift, ctrl, alt)`` to + an array indexed by scan code containing the data + ``(character, is_dead)``, and ``layout_handle`` is the handle of the + layout. + + :return: a composite layout + """ + layout_data = {} + + state = (ctypes.c_ubyte * 255)() + with self._thread_input() as active_thread: + layout = self._GetKeyboardLayout(active_thread) + vks = [ + self._to_vk(scan, layout) + for scan in range(len(state))] + + for shift, ctrl, alt in itertools.product( + (False, True), (False, True), (False, True)): + current = [(None, False)] * len(state) + layout_data[(shift, ctrl, alt)] = current + + # Update the keyboard state based on the modifier state + state[VK.SHIFT] = 0x80 if shift else 0x00 + state[VK.CONTROL] = 0x80 if ctrl else 0x00 + state[VK.MENU] = 0x80 if alt else 0x00 + + # For each virtual key code... + out = (ctypes.wintypes.WCHAR * 5)() + for (scan, vk) in enumerate(vks): + # ...translate it to a unicode character + count = self._ToUnicodeEx( + vk, scan, ctypes.byref(state), ctypes.byref(out), + len(out), 0, layout) + + # Cache the result if a key is mapped + if count != 0: + character = out[0] + is_dead = count < 0 + current[scan] = (character, is_dead) + + # If the key is dead, flush the keyboard state + if is_dead: + self._ToUnicodeEx( + vk, scan, ctypes.byref(state), + ctypes.byref(out), len(out), 0, layout) + + return (layout, layout_data) + + def _to_scan(self, vk, layout): + """Retrieves the scan code for a virtual key code. + + :param int vk: The virtual key code. + + :param layout: The keyboard layout. + + :return: the scan code + """ + return self._MapVirtualKeyEx( + vk, self._MAPVK_VK_TO_VSC, layout) + + def _to_vk(self, scan, layout): + """Retrieves the virtual key code for a scan code. + + :param int vscan: The scan code. + + :param layout: The keyboard layout. + + :return: the virtual key code + """ + return self._MapVirtualKeyEx( + scan, self._MAPVK_VSC_TO_VK, layout) + + def _modifier_state(self): + """Returns a key into :attr:`_layout_data` for the current modifier + state. + + :return: the current modifier state + """ + shift = bool(self._GetAsyncKeyState(VK.SHIFT) & 0x8000) + ctrl = bool(self._GetAsyncKeyState(VK.CONTROL) & 0x8000) + alt = bool(self._GetAsyncKeyState(VK.MENU) & 0x8000) + return (shift, ctrl, alt) + + @contextlib.contextmanager + def _thread_input(self): + """Yields the current thread ID. + """ + yield GetCurrentThreadId() diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32_vks.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32_vks.py new file mode 100644 index 0000000..7b30238 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/win32_vks.py @@ -0,0 +1,179 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +# pylint: disable=C0111,C0302 + +LBUTTON = 1 +RBUTTON = 2 +CANCEL = 3 +MBUTTON = 4 +XBUTTON1 = 5 +XBUTTON2 = 6 +BACK = 8 +TAB = 9 +CLEAR = 12 +RETURN = 13 +SHIFT = 16 +CONTROL = 17 +MENU = 18 +PAUSE = 19 +CAPITAL = 20 +KANA = 21 +HANGEUL = 21 +HANGUL = 21 +JUNJA = 23 +FINAL = 24 +HANJA = 25 +KANJI = 25 +ESCAPE = 27 +CONVERT = 28 +NONCONVERT = 29 +ACCEPT = 30 +MODECHANGE = 31 +SPACE = 32 +PRIOR = 33 +NEXT = 34 +END = 35 +HOME = 36 +LEFT = 37 +UP = 38 +RIGHT = 39 +DOWN = 40 +SELECT = 41 +PRINT = 42 +EXECUTE = 43 +SNAPSHOT = 44 +INSERT = 45 +DELETE = 46 +HELP = 47 +LWIN = 91 +RWIN = 92 +APPS = 93 +SLEEP = 95 +NUMPAD0 = 96 +NUMPAD1 = 97 +NUMPAD2 = 98 +NUMPAD3 = 99 +NUMPAD4 = 100 +NUMPAD5 = 101 +NUMPAD6 = 102 +NUMPAD7 = 103 +NUMPAD8 = 104 +NUMPAD9 = 105 +MULTIPLY = 106 +ADD = 107 +SEPARATOR = 108 +SUBTRACT = 109 +DECIMAL = 110 +DIVIDE = 111 +F1 = 112 +F2 = 113 +F3 = 114 +F4 = 115 +F5 = 116 +F6 = 117 +F7 = 118 +F8 = 119 +F9 = 120 +F10 = 121 +F11 = 122 +F12 = 123 +F13 = 124 +F14 = 125 +F15 = 126 +F16 = 127 +F17 = 128 +F18 = 129 +F19 = 130 +F20 = 131 +F21 = 132 +F22 = 133 +F23 = 134 +F24 = 135 +NUMLOCK = 144 +SCROLL = 145 +OEM_NEC_EQUAL = 146 +OEM_FJ_JISHO = 146 +OEM_FJ_MASSHOU = 147 +OEM_FJ_TOUROKU = 148 +OEM_FJ_LOYA = 149 +OEM_FJ_ROYA = 150 +LSHIFT = 160 +RSHIFT = 161 +LCONTROL = 162 +RCONTROL = 163 +LMENU = 164 +RMENU = 165 +BROWSER_BACK = 166 +BROWSER_FORWARD = 167 +BROWSER_REFRESH = 168 +BROWSER_STOP = 169 +BROWSER_SEARCH = 170 +BROWSER_FAVORITES = 171 +BROWSER_HOME = 172 +VOLUME_MUTE = 173 +VOLUME_DOWN = 174 +VOLUME_UP = 175 +MEDIA_NEXT_TRACK = 176 +MEDIA_PREV_TRACK = 177 +MEDIA_STOP = 178 +MEDIA_PLAY_PAUSE = 179 +LAUNCH_MAIL = 180 +LAUNCH_MEDIA_SELECT = 181 +LAUNCH_APP1 = 182 +LAUNCH_APP2 = 183 +OEM_1 = 186 +OEM_PLUS = 187 +OEM_COMMA = 188 +OEM_MINUS = 189 +OEM_PERIOD = 190 +OEM_2 = 191 +OEM_3 = 192 +OEM_4 = 219 +OEM_5 = 220 +OEM_6 = 221 +OEM_7 = 222 +OEM_8 = 223 +OEM_AX = 225 +OEM_102 = 226 +ICO_HELP = 227 +ICO_00 = 228 +PROCESSKEY = 229 +ICO_CLEAR = 230 +PACKET = 231 +OEM_RESET = 233 +OEM_JUMP = 234 +OEM_PA1 = 235 +OEM_PA2 = 236 +OEM_PA3 = 237 +OEM_WSCTRL = 238 +OEM_CUSEL = 239 +OEM_ATTN = 240 +OEM_FINISH = 241 +OEM_COPY = 242 +OEM_AUTO = 243 +OEM_ENLW = 244 +OEM_BACKTAB = 245 +ATTN = 246 +CRSEL = 247 +EXSEL = 248 +EREOF = 249 +PLAY = 250 +ZOOM = 251 +NONAME = 252 +PA1 = 253 +OEM_CLEAR = 254 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg.py new file mode 100644 index 0000000..52995f3 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg.py @@ -0,0 +1,496 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +Utility functions and classes for the *Xorg* backend. +""" + +# pylint: disable=R0903 +# We implement stubs + +import contextlib +import functools +import itertools +import operator +import Xlib.display +import Xlib.keysymdef +import Xlib.threaded +import Xlib.XK + +from . import AbstractListener +from .xorg_keysyms import SYMBOLS + + +# Create a display to verify that we have an X connection +def _check_and_initialize(): + display = Xlib.display.Display() + display.close() + + for group in Xlib.keysymdef.__all__: + Xlib.XK.load_keysym_group(group) +_check_and_initialize() +del _check_and_initialize + + +class X11Error(Exception): + """An error that is thrown at the end of a code block managed by a + :func:`display_manager` if an *X11* error occurred. + """ + pass + + +@contextlib.contextmanager +def display_manager(display): + """Traps *X* errors and raises an :class:``X11Error`` at the end if any + error occurred. + + This handler also ensures that the :class:`Xlib.display.Display` being + managed is sync'd. + + :param Xlib.display.Display display: The *X* display. + + :return: the display + :rtype: Xlib.display.Display + """ + errors = [] + + def handler(*args): + """The *Xlib* error handler. + """ + errors.append(args) + + old_handler = display.set_error_handler(handler) + try: + yield display + display.sync() + finally: + display.set_error_handler(old_handler) + if errors: + raise X11Error(errors) + + +def _find_mask(display, symbol): + """Returns the mode flags to use for a modifier symbol. + + :param Xlib.display.Display display: The *X* display. + + :param str symbol: The name of the symbol. + + :return: the modifier mask + """ + # Get the key code for the symbol + modifier_keycode = display.keysym_to_keycode( + Xlib.XK.string_to_keysym(symbol)) + + for index, keycodes in enumerate(display.get_modifier_mapping()): + for keycode in keycodes: + if keycode == modifier_keycode: + return 1 << index + + return 0 + + +def alt_mask(display): + """Returns the *alt* mask flags. + + The first time this function is called for a display, the value is cached. + Subsequent calls will return the cached value. + + :param Xlib.display.Display display: The *X* display. + + :return: the modifier mask + """ + if not hasattr(display, '__alt_mask'): + display.__alt_mask = _find_mask(display, 'Alt_L') + return display.__alt_mask + + +def alt_gr_mask(display): + """Returns the *alt* mask flags. + + The first time this function is called for a display, the value is cached. + Subsequent calls will return the cached value. + + :param Xlib.display.Display display: The *X* display. + + :return: the modifier mask + """ + if not hasattr(display, '__altgr_mask'): + display.__altgr_mask = _find_mask(display, 'Mode_switch') + return display.__altgr_mask + + +def numlock_mask(display): + """Returns the *numlock* mask flags. + + The first time this function is called for a display, the value is cached. + Subsequent calls will return the cached value. + + :param Xlib.display.Display display: The *X* display. + + :return: the modifier mask + """ + if not hasattr(display, '__numlock_mask'): + display.__numlock_mask = _find_mask(display, 'Num_Lock') + return display.__numlock_mask + + +def keysym_is_latin_upper(keysym): + """Determines whether a *keysym* is an upper case *latin* character. + + This is true only if ``XK_A`` <= ``keysym`` <= ` XK_Z``. + + :param in keysym: The *keysym* to check. + """ + return Xlib.XK.XK_A <= keysym <= Xlib.XK.XK_Z + + +def keysym_is_latin_lower(keysym): + """Determines whether a *keysym* is a lower case *latin* character. + + This is true only if ``XK_a`` <= ``keysym`` <= ` XK_z``. + + :param in keysym: The *keysym* to check. + """ + return Xlib.XK.XK_a <= keysym <= Xlib.XK.XK_z + + +def keysym_group(ks1, ks2): + """Generates a group from two *keysyms*. + + The implementation of this function comes from: + + Within each group, if the second element of the group is ``NoSymbol``, + then the group should be treated as if the second element were the same + as the first element, except when the first element is an alphabetic + *KeySym* ``K`` for which both lowercase and uppercase forms are + defined. + + In that case, the group should be treated as if the first element were + the lowercase form of ``K`` and the second element were the uppercase + form of ``K``. + + This function assumes that *alphabetic* means *latin*; this assumption + appears to be consistent with observations of the return values from + ``XGetKeyboardMapping``. + + :param ks1: The first *keysym*. + + :param ks2: The second *keysym*. + + :return: a tuple conforming to the description above + """ + if ks2 == Xlib.XK.NoSymbol: + if keysym_is_latin_upper(ks1): + return (Xlib.XK.XK_a + ks1 - Xlib.XK.XK_A, ks1) + elif keysym_is_latin_lower(ks1): + return (ks1, Xlib.XK.XK_A + ks1 - Xlib.XK.XK_a) + else: + return (ks1, ks1) + else: + return (ks1, ks2) + + +def keysym_normalize(keysym): + """Normalises a list of *keysyms*. + + The implementation of this function comes from: + + If the list (ignoring trailing ``NoSymbol`` entries) is a single + *KeySym* ``K``, then the list is treated as if it were the list + ``K NoSymbol K NoSymbol``. + + If the list (ignoring trailing ``NoSymbol`` entries) is a pair of + *KeySyms* ``K1 K2``, then the list is treated as if it were the list + ``K1 K2 K1 K2``. + + If the list (ignoring trailing ``NoSymbol`` entries) is a triple of + *KeySyms* ``K1 K2 K3``, then the list is treated as if it were the list + ``K1 K2 K3 NoSymbol``. + + This function will also group the *keysyms* using :func:`keysym_group`. + + :param keysyms: A list of keysyms. + + :return: the tuple ``(group_1, group_2)`` or ``None`` + """ + # Remove trailing NoSymbol + stripped = list(reversed(list( + itertools.dropwhile( + lambda n: n == Xlib.XK.NoSymbol, + reversed(keysym))))) + + if not stripped: + return + + elif len(stripped) == 1: + return ( + keysym_group(stripped[0], Xlib.XK.NoSymbol), + keysym_group(stripped[0], Xlib.XK.NoSymbol)) + + elif len(stripped) == 2: + return ( + keysym_group(stripped[0], stripped[1]), + keysym_group(stripped[0], stripped[1])) + + elif len(stripped) == 3: + return ( + keysym_group(stripped[0], stripped[1]), + keysym_group(stripped[2], Xlib.XK.NoSymbol)) + + elif len(stripped) >= 6: + # TODO: Find out why this is necessary; using only the documented + # behaviour may lead to only a US layout being used? + return ( + keysym_group(stripped[0], stripped[1]), + keysym_group(stripped[4], stripped[5])) + + else: + return ( + keysym_group(stripped[0], stripped[1]), + keysym_group(stripped[2], stripped[3])) + + +def index_to_shift(display, index): + """Converts an index in a *key code* list to the corresponding shift state. + + :param Xlib.display.Display display: The display for which to retrieve the + shift mask. + + :param int index: The keyboard mapping *key code* index. + + :return: a shift mask + """ + return ( + (1 << 0 if index & 1 else 0) | + (alt_gr_mask(display) if index & 2 else 0)) + + +def shift_to_index(display, shift): + """Converts an index in a *key code* list to the corresponding shift state. + + :param Xlib.display.Display display: The display for which to retrieve the + shift mask. + + :param int index: The keyboard mapping *key code* index. + + :return: a shift mask + """ + return ( + (1 if shift & 1 else 0) + + (2 if shift & alt_gr_mask(display) else 0)) + + +def keyboard_mapping(display): + """Generates a mapping from *keysyms* to *key codes* and required + modifier shift states. + + :param Xlib.display.Display display: The display for which to retrieve the + keyboard mapping. + + :return: the keyboard mapping + """ + mapping = {} + + shift_mask = 1 << 0 + group_mask = alt_gr_mask(display) + + # Iterate over all keysym lists in the keyboard mapping + min_keycode = display.display.info.min_keycode + keycode_count = display.display.info.max_keycode - min_keycode + 1 + for index, keysyms in enumerate(display.get_keyboard_mapping( + min_keycode, keycode_count)): + key_code = index + min_keycode + + # Normalise the keysym list to yield a tuple containing the two groups + normalized = keysym_normalize(keysyms) + if not normalized: + continue + + # Iterate over the groups to extract the shift and modifier state + for groups, group in zip(normalized, (False, True)): + for keysym, shift in zip(groups, (False, True)): + if not keysym: + continue + shift_state = 0 \ + | (shift_mask if shift else 0) \ + | (group_mask if group else 0) + + # Prefer already known lesser shift states + if keysym in mapping and mapping[keysym][1] < shift_state: + continue + mapping[keysym] = (key_code, shift_state) + + return mapping + + +def char_to_keysym(char): + """Converts a unicode character to a *keysym*. + + :param str char: The unicode character. + + :return: the corresponding *keysym*, or ``0`` if it cannot be found + """ + ordinal = ord(char) + if ordinal < 0x100: + return ordinal + else: + return ordinal | 0x01000000 + + +def symbol_to_keysym(symbol): + """Converts a symbol name to a *keysym*. + + :param str symbol: The name of the symbol. + + :return: the corresponding *keysym*, or ``0`` if it cannot be found + """ + # First try simple translation, the try a module attribute of + # Xlib.keysymdef.xkb and fall back on our pre-generated table + return (0 + or Xlib.XK.string_to_keysym(symbol) + or getattr(Xlib.keysymdef.xkb, "XK_" + symbol, 0) + or SYMBOLS.get(symbol, (0,))[0]) + + +class ListenerMixin(object): + """A mixin for *X* event listeners. + + Subclasses should set a value for :attr:`_EVENTS` and implement + :meth:`_handle_message`. + """ + #: The events for which to listen + _EVENTS = tuple() + + #: We use this instance for parsing the binary data + _EVENT_PARSER = Xlib.protocol.rq.EventField(None) + + def _run(self): + self._display_stop = Xlib.display.Display() + self._display_record = Xlib.display.Display() + self._stopped = False + with display_manager(self._display_record) as dm: + self._context = dm.record_create_context( + 0, + [Xlib.ext.record.AllClients], + [{ + 'core_requests': (0, 0), + 'core_replies': (0, 0), + 'ext_requests': (0, 0, 0, 0), + 'ext_replies': (0, 0, 0, 0), + 'delivered_events': (0, 0), + 'device_events': self._EVENTS, + 'errors': (0, 0), + 'client_started': False, + 'client_died': False}]) + + # pylint: disable=W0702; we want to silence errors + try: + self._initialize(self._display_stop) + self._mark_ready() + if self.suppress: + with display_manager(self._display_stop) as dm: + self._suppress_start(dm) + self._display_record.record_enable_context( + self._context, self._handler) + except: + # This exception will have been passed to the main thread + pass + finally: + if self.suppress: + with display_manager(self._display_stop) as dm: + self._suppress_stop(dm) + self._display_stop.record_disable_context(self._context) + self._display_stop.flush() + self._display_record.record_free_context(self._context) + self._display_stop.close() + self._display_record.close() + # pylint: enable=W0702 + + def _stop_platform(self): + if not hasattr(self, '_context'): + self.wait() + + # Do this asynchronously to avoid deadlocks + self._display_record.record_disable_context(self._context) + + def _suppress_start(self, display): + """Starts suppressing events. + + :param Xlib.display.Display display: The display for which to suppress + events. + """ + raise NotImplementedError() + + def _suppress_stop(self, display): + """Starts suppressing events. + + :param Xlib.display.Display display: The display for which to suppress + events. + """ + raise NotImplementedError() + + @property + def _event_mask(self): + """The event mask. + """ + return functools.reduce(operator.__or__, self._EVENTS, 0) + + @AbstractListener._emitter + def _handler(self, events): + """The callback registered with *X* for mouse events. + + This method will parse the response and call the callbacks registered + on initialisation. + + :param events: The events passed by *X*. This is a binary block + parsable by :attr:`_EVENT_PARSER`. + """ + if not self.running: + raise self.StopException() + + data = events.data + + while data and len(data): + event, data = self._EVENT_PARSER.parse_binary_value( + data, self._display_record.display, None, None) + + injected = event.send_event + self._handle_message(self._display_stop, event, injected) + + def _initialize(self, display): + """Initialises this listener. + + This method is called immediately before the event loop, from the + handler thread. + + :param display: The display being used. + """ + pass + + def _handle_message(self, display, event, injected): + """The device specific callback handler. + + This method calls the appropriate callback registered when this + listener was created based on the event. + + :param display: The display being used. + + :param event: The event. + + :param bool injected: Whether the event was injected. + """ + pass diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg_keysyms.py b/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg_keysyms.py new file mode 100644 index 0000000..7505e89 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/_util/xorg_keysyms.py @@ -0,0 +1,1715 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +# pylint: disable=C0111,C0302 + +SYMBOLS = { + '0': (0x0030, u'\u0030'), + '1': (0x0031, u'\u0031'), + '2': (0x0032, u'\u0032'), + '3': (0x0033, u'\u0033'), + '4': (0x0034, u'\u0034'), + '5': (0x0035, u'\u0035'), + '6': (0x0036, u'\u0036'), + '7': (0x0037, u'\u0037'), + '8': (0x0038, u'\u0038'), + '9': (0x0039, u'\u0039'), + 'A': (0x0041, u'\u0041'), + 'AE': (0x00c6, u'\u00C6'), + 'Aacute': (0x00c1, u'\u00C1'), + 'Abelowdot': (0x1001ea0, u'\u1EA0'), + 'Abreve': (0x01c3, u'\u0102'), + 'Abreveacute': (0x1001eae, u'\u1EAE'), + 'Abrevebelowdot': (0x1001eb6, u'\u1EB6'), + 'Abrevegrave': (0x1001eb0, u'\u1EB0'), + 'Abrevehook': (0x1001eb2, u'\u1EB2'), + 'Abrevetilde': (0x1001eb4, u'\u1EB4'), + 'Acircumflex': (0x00c2, u'\u00C2'), + 'Acircumflexacute': (0x1001ea4, u'\u1EA4'), + 'Acircumflexbelowdot': (0x1001eac, u'\u1EAC'), + 'Acircumflexgrave': (0x1001ea6, u'\u1EA6'), + 'Acircumflexhook': (0x1001ea8, u'\u1EA8'), + 'Acircumflextilde': (0x1001eaa, u'\u1EAA'), + 'Adiaeresis': (0x00c4, u'\u00C4'), + 'Agrave': (0x00c0, u'\u00C0'), + 'Ahook': (0x1001ea2, u'\u1EA2'), + 'Amacron': (0x03c0, u'\u0100'), + 'Aogonek': (0x01a1, u'\u0104'), + 'Arabic_0': (0x1000660, u'\u0660'), + 'Arabic_1': (0x1000661, u'\u0661'), + 'Arabic_2': (0x1000662, u'\u0662'), + 'Arabic_3': (0x1000663, u'\u0663'), + 'Arabic_4': (0x1000664, u'\u0664'), + 'Arabic_5': (0x1000665, u'\u0665'), + 'Arabic_6': (0x1000666, u'\u0666'), + 'Arabic_7': (0x1000667, u'\u0667'), + 'Arabic_8': (0x1000668, u'\u0668'), + 'Arabic_9': (0x1000669, u'\u0669'), + 'Arabic_ain': (0x05d9, u'\u0639'), + 'Arabic_alef': (0x05c7, u'\u0627'), + 'Arabic_alefmaksura': (0x05e9, u'\u0649'), + 'Arabic_beh': (0x05c8, u'\u0628'), + 'Arabic_comma': (0x05ac, u'\u060C'), + 'Arabic_dad': (0x05d6, u'\u0636'), + 'Arabic_dal': (0x05cf, u'\u062F'), + 'Arabic_damma': (0x05ef, u'\u064F'), + 'Arabic_dammatan': (0x05ec, u'\u064C'), + 'Arabic_ddal': (0x1000688, u'\u0688'), + 'Arabic_farsi_yeh': (0x10006cc, u'\u06CC'), + 'Arabic_fatha': (0x05ee, u'\u064E'), + 'Arabic_fathatan': (0x05eb, u'\u064B'), + 'Arabic_feh': (0x05e1, u'\u0641'), + 'Arabic_fullstop': (0x10006d4, u'\u06D4'), + 'Arabic_gaf': (0x10006af, u'\u06AF'), + 'Arabic_ghain': (0x05da, u'\u063A'), + 'Arabic_ha': (0x05e7, u'\u0647'), + 'Arabic_hah': (0x05cd, u'\u062D'), + 'Arabic_hamza': (0x05c1, u'\u0621'), + 'Arabic_hamza_above': (0x1000654, u'\u0654'), + 'Arabic_hamza_below': (0x1000655, u'\u0655'), + 'Arabic_hamzaonalef': (0x05c3, u'\u0623'), + 'Arabic_hamzaonwaw': (0x05c4, u'\u0624'), + 'Arabic_hamzaonyeh': (0x05c6, u'\u0626'), + 'Arabic_hamzaunderalef': (0x05c5, u'\u0625'), + 'Arabic_heh_doachashmee': (0x10006be, u'\u06BE'), + 'Arabic_heh_goal': (0x10006c1, u'\u06C1'), + 'Arabic_jeem': (0x05cc, u'\u062C'), + 'Arabic_jeh': (0x1000698, u'\u0698'), + 'Arabic_kaf': (0x05e3, u'\u0643'), + 'Arabic_kasra': (0x05f0, u'\u0650'), + 'Arabic_kasratan': (0x05ed, u'\u064D'), + 'Arabic_keheh': (0x10006a9, u'\u06A9'), + 'Arabic_khah': (0x05ce, u'\u062E'), + 'Arabic_lam': (0x05e4, u'\u0644'), + 'Arabic_madda_above': (0x1000653, u'\u0653'), + 'Arabic_maddaonalef': (0x05c2, u'\u0622'), + 'Arabic_meem': (0x05e5, u'\u0645'), + 'Arabic_noon': (0x05e6, u'\u0646'), + 'Arabic_noon_ghunna': (0x10006ba, u'\u06BA'), + 'Arabic_peh': (0x100067e, u'\u067E'), + 'Arabic_percent': (0x100066a, u'\u066A'), + 'Arabic_qaf': (0x05e2, u'\u0642'), + 'Arabic_question_mark': (0x05bf, u'\u061F'), + 'Arabic_ra': (0x05d1, u'\u0631'), + 'Arabic_rreh': (0x1000691, u'\u0691'), + 'Arabic_sad': (0x05d5, u'\u0635'), + 'Arabic_seen': (0x05d3, u'\u0633'), + 'Arabic_semicolon': (0x05bb, u'\u061B'), + 'Arabic_shadda': (0x05f1, u'\u0651'), + 'Arabic_sheen': (0x05d4, u'\u0634'), + 'Arabic_sukun': (0x05f2, u'\u0652'), + 'Arabic_superscript_alef': (0x1000670, u'\u0670'), + 'Arabic_tah': (0x05d7, u'\u0637'), + 'Arabic_tatweel': (0x05e0, u'\u0640'), + 'Arabic_tcheh': (0x1000686, u'\u0686'), + 'Arabic_teh': (0x05ca, u'\u062A'), + 'Arabic_tehmarbuta': (0x05c9, u'\u0629'), + 'Arabic_thal': (0x05d0, u'\u0630'), + 'Arabic_theh': (0x05cb, u'\u062B'), + 'Arabic_tteh': (0x1000679, u'\u0679'), + 'Arabic_veh': (0x10006a4, u'\u06A4'), + 'Arabic_waw': (0x05e8, u'\u0648'), + 'Arabic_yeh': (0x05ea, u'\u064A'), + 'Arabic_yeh_baree': (0x10006d2, u'\u06D2'), + 'Arabic_zah': (0x05d8, u'\u0638'), + 'Arabic_zain': (0x05d2, u'\u0632'), + 'Aring': (0x00c5, u'\u00C5'), + 'Armenian_AT': (0x1000538, u'\u0538'), + 'Armenian_AYB': (0x1000531, u'\u0531'), + 'Armenian_BEN': (0x1000532, u'\u0532'), + 'Armenian_CHA': (0x1000549, u'\u0549'), + 'Armenian_DA': (0x1000534, u'\u0534'), + 'Armenian_DZA': (0x1000541, u'\u0541'), + 'Armenian_E': (0x1000537, u'\u0537'), + 'Armenian_FE': (0x1000556, u'\u0556'), + 'Armenian_GHAT': (0x1000542, u'\u0542'), + 'Armenian_GIM': (0x1000533, u'\u0533'), + 'Armenian_HI': (0x1000545, u'\u0545'), + 'Armenian_HO': (0x1000540, u'\u0540'), + 'Armenian_INI': (0x100053b, u'\u053B'), + 'Armenian_JE': (0x100054b, u'\u054B'), + 'Armenian_KE': (0x1000554, u'\u0554'), + 'Armenian_KEN': (0x100053f, u'\u053F'), + 'Armenian_KHE': (0x100053d, u'\u053D'), + 'Armenian_LYUN': (0x100053c, u'\u053C'), + 'Armenian_MEN': (0x1000544, u'\u0544'), + 'Armenian_NU': (0x1000546, u'\u0546'), + 'Armenian_O': (0x1000555, u'\u0555'), + 'Armenian_PE': (0x100054a, u'\u054A'), + 'Armenian_PYUR': (0x1000553, u'\u0553'), + 'Armenian_RA': (0x100054c, u'\u054C'), + 'Armenian_RE': (0x1000550, u'\u0550'), + 'Armenian_SE': (0x100054d, u'\u054D'), + 'Armenian_SHA': (0x1000547, u'\u0547'), + 'Armenian_TCHE': (0x1000543, u'\u0543'), + 'Armenian_TO': (0x1000539, u'\u0539'), + 'Armenian_TSA': (0x100053e, u'\u053E'), + 'Armenian_TSO': (0x1000551, u'\u0551'), + 'Armenian_TYUN': (0x100054f, u'\u054F'), + 'Armenian_VEV': (0x100054e, u'\u054E'), + 'Armenian_VO': (0x1000548, u'\u0548'), + 'Armenian_VYUN': (0x1000552, u'\u0552'), + 'Armenian_YECH': (0x1000535, u'\u0535'), + 'Armenian_ZA': (0x1000536, u'\u0536'), + 'Armenian_ZHE': (0x100053a, u'\u053A'), + 'Armenian_accent': (0x100055b, u'\u055B'), + 'Armenian_amanak': (0x100055c, u'\u055C'), + 'Armenian_apostrophe': (0x100055a, u'\u055A'), + 'Armenian_at': (0x1000568, u'\u0568'), + 'Armenian_ayb': (0x1000561, u'\u0561'), + 'Armenian_ben': (0x1000562, u'\u0562'), + 'Armenian_but': (0x100055d, u'\u055D'), + 'Armenian_cha': (0x1000579, u'\u0579'), + 'Armenian_da': (0x1000564, u'\u0564'), + 'Armenian_dza': (0x1000571, u'\u0571'), + 'Armenian_e': (0x1000567, u'\u0567'), + 'Armenian_exclam': (0x100055c, u'\u055C'), + 'Armenian_fe': (0x1000586, u'\u0586'), + 'Armenian_full_stop': (0x1000589, u'\u0589'), + 'Armenian_ghat': (0x1000572, u'\u0572'), + 'Armenian_gim': (0x1000563, u'\u0563'), + 'Armenian_hi': (0x1000575, u'\u0575'), + 'Armenian_ho': (0x1000570, u'\u0570'), + 'Armenian_hyphen': (0x100058a, u'\u058A'), + 'Armenian_ini': (0x100056b, u'\u056B'), + 'Armenian_je': (0x100057b, u'\u057B'), + 'Armenian_ke': (0x1000584, u'\u0584'), + 'Armenian_ken': (0x100056f, u'\u056F'), + 'Armenian_khe': (0x100056d, u'\u056D'), + 'Armenian_ligature_ew': (0x1000587, u'\u0587'), + 'Armenian_lyun': (0x100056c, u'\u056C'), + 'Armenian_men': (0x1000574, u'\u0574'), + 'Armenian_nu': (0x1000576, u'\u0576'), + 'Armenian_o': (0x1000585, u'\u0585'), + 'Armenian_paruyk': (0x100055e, u'\u055E'), + 'Armenian_pe': (0x100057a, u'\u057A'), + 'Armenian_pyur': (0x1000583, u'\u0583'), + 'Armenian_question': (0x100055e, u'\u055E'), + 'Armenian_ra': (0x100057c, u'\u057C'), + 'Armenian_re': (0x1000580, u'\u0580'), + 'Armenian_se': (0x100057d, u'\u057D'), + 'Armenian_separation_mark': (0x100055d, u'\u055D'), + 'Armenian_sha': (0x1000577, u'\u0577'), + 'Armenian_shesht': (0x100055b, u'\u055B'), + 'Armenian_tche': (0x1000573, u'\u0573'), + 'Armenian_to': (0x1000569, u'\u0569'), + 'Armenian_tsa': (0x100056e, u'\u056E'), + 'Armenian_tso': (0x1000581, u'\u0581'), + 'Armenian_tyun': (0x100057f, u'\u057F'), + 'Armenian_verjaket': (0x1000589, u'\u0589'), + 'Armenian_vev': (0x100057e, u'\u057E'), + 'Armenian_vo': (0x1000578, u'\u0578'), + 'Armenian_vyun': (0x1000582, u'\u0582'), + 'Armenian_yech': (0x1000565, u'\u0565'), + 'Armenian_yentamna': (0x100058a, u'\u058A'), + 'Armenian_za': (0x1000566, u'\u0566'), + 'Armenian_zhe': (0x100056a, u'\u056A'), + 'Atilde': (0x00c3, u'\u00C3'), + 'B': (0x0042, u'\u0042'), + 'Babovedot': (0x1001e02, u'\u1E02'), + 'Byelorussian_SHORTU': (0x06be, u'\u040E'), + 'Byelorussian_shortu': (0x06ae, u'\u045E'), + 'C': (0x0043, u'\u0043'), + 'Cabovedot': (0x02c5, u'\u010A'), + 'Cacute': (0x01c6, u'\u0106'), + 'Ccaron': (0x01c8, u'\u010C'), + 'Ccedilla': (0x00c7, u'\u00C7'), + 'Ccircumflex': (0x02c6, u'\u0108'), + 'ColonSign': (0x10020a1, u'\u20A1'), + 'CruzeiroSign': (0x10020a2, u'\u20A2'), + 'Cyrillic_A': (0x06e1, u'\u0410'), + 'Cyrillic_BE': (0x06e2, u'\u0411'), + 'Cyrillic_CHE': (0x06fe, u'\u0427'), + 'Cyrillic_CHE_descender': (0x10004b6, u'\u04B6'), + 'Cyrillic_CHE_vertstroke': (0x10004b8, u'\u04B8'), + 'Cyrillic_DE': (0x06e4, u'\u0414'), + 'Cyrillic_DZHE': (0x06bf, u'\u040F'), + 'Cyrillic_E': (0x06fc, u'\u042D'), + 'Cyrillic_EF': (0x06e6, u'\u0424'), + 'Cyrillic_EL': (0x06ec, u'\u041B'), + 'Cyrillic_EM': (0x06ed, u'\u041C'), + 'Cyrillic_EN': (0x06ee, u'\u041D'), + 'Cyrillic_EN_descender': (0x10004a2, u'\u04A2'), + 'Cyrillic_ER': (0x06f2, u'\u0420'), + 'Cyrillic_ES': (0x06f3, u'\u0421'), + 'Cyrillic_GHE': (0x06e7, u'\u0413'), + 'Cyrillic_GHE_bar': (0x1000492, u'\u0492'), + 'Cyrillic_HA': (0x06e8, u'\u0425'), + 'Cyrillic_HARDSIGN': (0x06ff, u'\u042A'), + 'Cyrillic_HA_descender': (0x10004b2, u'\u04B2'), + 'Cyrillic_I': (0x06e9, u'\u0418'), + 'Cyrillic_IE': (0x06e5, u'\u0415'), + 'Cyrillic_IO': (0x06b3, u'\u0401'), + 'Cyrillic_I_macron': (0x10004e2, u'\u04E2'), + 'Cyrillic_JE': (0x06b8, u'\u0408'), + 'Cyrillic_KA': (0x06eb, u'\u041A'), + 'Cyrillic_KA_descender': (0x100049a, u'\u049A'), + 'Cyrillic_KA_vertstroke': (0x100049c, u'\u049C'), + 'Cyrillic_LJE': (0x06b9, u'\u0409'), + 'Cyrillic_NJE': (0x06ba, u'\u040A'), + 'Cyrillic_O': (0x06ef, u'\u041E'), + 'Cyrillic_O_bar': (0x10004e8, u'\u04E8'), + 'Cyrillic_PE': (0x06f0, u'\u041F'), + 'Cyrillic_SCHWA': (0x10004d8, u'\u04D8'), + 'Cyrillic_SHA': (0x06fb, u'\u0428'), + 'Cyrillic_SHCHA': (0x06fd, u'\u0429'), + 'Cyrillic_SHHA': (0x10004ba, u'\u04BA'), + 'Cyrillic_SHORTI': (0x06ea, u'\u0419'), + 'Cyrillic_SOFTSIGN': (0x06f8, u'\u042C'), + 'Cyrillic_TE': (0x06f4, u'\u0422'), + 'Cyrillic_TSE': (0x06e3, u'\u0426'), + 'Cyrillic_U': (0x06f5, u'\u0423'), + 'Cyrillic_U_macron': (0x10004ee, u'\u04EE'), + 'Cyrillic_U_straight': (0x10004ae, u'\u04AE'), + 'Cyrillic_U_straight_bar': (0x10004b0, u'\u04B0'), + 'Cyrillic_VE': (0x06f7, u'\u0412'), + 'Cyrillic_YA': (0x06f1, u'\u042F'), + 'Cyrillic_YERU': (0x06f9, u'\u042B'), + 'Cyrillic_YU': (0x06e0, u'\u042E'), + 'Cyrillic_ZE': (0x06fa, u'\u0417'), + 'Cyrillic_ZHE': (0x06f6, u'\u0416'), + 'Cyrillic_ZHE_descender': (0x1000496, u'\u0496'), + 'Cyrillic_a': (0x06c1, u'\u0430'), + 'Cyrillic_be': (0x06c2, u'\u0431'), + 'Cyrillic_che': (0x06de, u'\u0447'), + 'Cyrillic_che_descender': (0x10004b7, u'\u04B7'), + 'Cyrillic_che_vertstroke': (0x10004b9, u'\u04B9'), + 'Cyrillic_de': (0x06c4, u'\u0434'), + 'Cyrillic_dzhe': (0x06af, u'\u045F'), + 'Cyrillic_e': (0x06dc, u'\u044D'), + 'Cyrillic_ef': (0x06c6, u'\u0444'), + 'Cyrillic_el': (0x06cc, u'\u043B'), + 'Cyrillic_em': (0x06cd, u'\u043C'), + 'Cyrillic_en': (0x06ce, u'\u043D'), + 'Cyrillic_en_descender': (0x10004a3, u'\u04A3'), + 'Cyrillic_er': (0x06d2, u'\u0440'), + 'Cyrillic_es': (0x06d3, u'\u0441'), + 'Cyrillic_ghe': (0x06c7, u'\u0433'), + 'Cyrillic_ghe_bar': (0x1000493, u'\u0493'), + 'Cyrillic_ha': (0x06c8, u'\u0445'), + 'Cyrillic_ha_descender': (0x10004b3, u'\u04B3'), + 'Cyrillic_hardsign': (0x06df, u'\u044A'), + 'Cyrillic_i': (0x06c9, u'\u0438'), + 'Cyrillic_i_macron': (0x10004e3, u'\u04E3'), + 'Cyrillic_ie': (0x06c5, u'\u0435'), + 'Cyrillic_io': (0x06a3, u'\u0451'), + 'Cyrillic_je': (0x06a8, u'\u0458'), + 'Cyrillic_ka': (0x06cb, u'\u043A'), + 'Cyrillic_ka_descender': (0x100049b, u'\u049B'), + 'Cyrillic_ka_vertstroke': (0x100049d, u'\u049D'), + 'Cyrillic_lje': (0x06a9, u'\u0459'), + 'Cyrillic_nje': (0x06aa, u'\u045A'), + 'Cyrillic_o': (0x06cf, u'\u043E'), + 'Cyrillic_o_bar': (0x10004e9, u'\u04E9'), + 'Cyrillic_pe': (0x06d0, u'\u043F'), + 'Cyrillic_schwa': (0x10004d9, u'\u04D9'), + 'Cyrillic_sha': (0x06db, u'\u0448'), + 'Cyrillic_shcha': (0x06dd, u'\u0449'), + 'Cyrillic_shha': (0x10004bb, u'\u04BB'), + 'Cyrillic_shorti': (0x06ca, u'\u0439'), + 'Cyrillic_softsign': (0x06d8, u'\u044C'), + 'Cyrillic_te': (0x06d4, u'\u0442'), + 'Cyrillic_tse': (0x06c3, u'\u0446'), + 'Cyrillic_u': (0x06d5, u'\u0443'), + 'Cyrillic_u_macron': (0x10004ef, u'\u04EF'), + 'Cyrillic_u_straight': (0x10004af, u'\u04AF'), + 'Cyrillic_u_straight_bar': (0x10004b1, u'\u04B1'), + 'Cyrillic_ve': (0x06d7, u'\u0432'), + 'Cyrillic_ya': (0x06d1, u'\u044F'), + 'Cyrillic_yeru': (0x06d9, u'\u044B'), + 'Cyrillic_yu': (0x06c0, u'\u044E'), + 'Cyrillic_ze': (0x06da, u'\u0437'), + 'Cyrillic_zhe': (0x06d6, u'\u0436'), + 'Cyrillic_zhe_descender': (0x1000497, u'\u0497'), + 'D': (0x0044, u'\u0044'), + 'Dabovedot': (0x1001e0a, u'\u1E0A'), + 'Dcaron': (0x01cf, u'\u010E'), + 'DongSign': (0x10020ab, u'\u20AB'), + 'Dstroke': (0x01d0, u'\u0110'), + 'E': (0x0045, u'\u0045'), + 'ENG': (0x03bd, u'\u014A'), + 'ETH': (0x00d0, u'\u00D0'), + 'EZH': (0x10001b7, u'\u01B7'), + 'Eabovedot': (0x03cc, u'\u0116'), + 'Eacute': (0x00c9, u'\u00C9'), + 'Ebelowdot': (0x1001eb8, u'\u1EB8'), + 'Ecaron': (0x01cc, u'\u011A'), + 'Ecircumflex': (0x00ca, u'\u00CA'), + 'Ecircumflexacute': (0x1001ebe, u'\u1EBE'), + 'Ecircumflexbelowdot': (0x1001ec6, u'\u1EC6'), + 'Ecircumflexgrave': (0x1001ec0, u'\u1EC0'), + 'Ecircumflexhook': (0x1001ec2, u'\u1EC2'), + 'Ecircumflextilde': (0x1001ec4, u'\u1EC4'), + 'EcuSign': (0x10020a0, u'\u20A0'), + 'Ediaeresis': (0x00cb, u'\u00CB'), + 'Egrave': (0x00c8, u'\u00C8'), + 'Ehook': (0x1001eba, u'\u1EBA'), + 'Emacron': (0x03aa, u'\u0112'), + 'Eogonek': (0x01ca, u'\u0118'), + 'Etilde': (0x1001ebc, u'\u1EBC'), + 'EuroSign': (0x20ac, u'\u20AC'), + 'F': (0x0046, u'\u0046'), + 'FFrancSign': (0x10020a3, u'\u20A3'), + 'Fabovedot': (0x1001e1e, u'\u1E1E'), + 'Farsi_0': (0x10006f0, u'\u06F0'), + 'Farsi_1': (0x10006f1, u'\u06F1'), + 'Farsi_2': (0x10006f2, u'\u06F2'), + 'Farsi_3': (0x10006f3, u'\u06F3'), + 'Farsi_4': (0x10006f4, u'\u06F4'), + 'Farsi_5': (0x10006f5, u'\u06F5'), + 'Farsi_6': (0x10006f6, u'\u06F6'), + 'Farsi_7': (0x10006f7, u'\u06F7'), + 'Farsi_8': (0x10006f8, u'\u06F8'), + 'Farsi_9': (0x10006f9, u'\u06F9'), + 'Farsi_yeh': (0x10006cc, u'\u06CC'), + 'G': (0x0047, u'\u0047'), + 'Gabovedot': (0x02d5, u'\u0120'), + 'Gbreve': (0x02ab, u'\u011E'), + 'Gcaron': (0x10001e6, u'\u01E6'), + 'Gcedilla': (0x03ab, u'\u0122'), + 'Gcircumflex': (0x02d8, u'\u011C'), + 'Georgian_an': (0x10010d0, u'\u10D0'), + 'Georgian_ban': (0x10010d1, u'\u10D1'), + 'Georgian_can': (0x10010ea, u'\u10EA'), + 'Georgian_char': (0x10010ed, u'\u10ED'), + 'Georgian_chin': (0x10010e9, u'\u10E9'), + 'Georgian_cil': (0x10010ec, u'\u10EC'), + 'Georgian_don': (0x10010d3, u'\u10D3'), + 'Georgian_en': (0x10010d4, u'\u10D4'), + 'Georgian_fi': (0x10010f6, u'\u10F6'), + 'Georgian_gan': (0x10010d2, u'\u10D2'), + 'Georgian_ghan': (0x10010e6, u'\u10E6'), + 'Georgian_hae': (0x10010f0, u'\u10F0'), + 'Georgian_har': (0x10010f4, u'\u10F4'), + 'Georgian_he': (0x10010f1, u'\u10F1'), + 'Georgian_hie': (0x10010f2, u'\u10F2'), + 'Georgian_hoe': (0x10010f5, u'\u10F5'), + 'Georgian_in': (0x10010d8, u'\u10D8'), + 'Georgian_jhan': (0x10010ef, u'\u10EF'), + 'Georgian_jil': (0x10010eb, u'\u10EB'), + 'Georgian_kan': (0x10010d9, u'\u10D9'), + 'Georgian_khar': (0x10010e5, u'\u10E5'), + 'Georgian_las': (0x10010da, u'\u10DA'), + 'Georgian_man': (0x10010db, u'\u10DB'), + 'Georgian_nar': (0x10010dc, u'\u10DC'), + 'Georgian_on': (0x10010dd, u'\u10DD'), + 'Georgian_par': (0x10010de, u'\u10DE'), + 'Georgian_phar': (0x10010e4, u'\u10E4'), + 'Georgian_qar': (0x10010e7, u'\u10E7'), + 'Georgian_rae': (0x10010e0, u'\u10E0'), + 'Georgian_san': (0x10010e1, u'\u10E1'), + 'Georgian_shin': (0x10010e8, u'\u10E8'), + 'Georgian_tan': (0x10010d7, u'\u10D7'), + 'Georgian_tar': (0x10010e2, u'\u10E2'), + 'Georgian_un': (0x10010e3, u'\u10E3'), + 'Georgian_vin': (0x10010d5, u'\u10D5'), + 'Georgian_we': (0x10010f3, u'\u10F3'), + 'Georgian_xan': (0x10010ee, u'\u10EE'), + 'Georgian_zen': (0x10010d6, u'\u10D6'), + 'Georgian_zhar': (0x10010df, u'\u10DF'), + 'Greek_ALPHA': (0x07c1, u'\u0391'), + 'Greek_ALPHAaccent': (0x07a1, u'\u0386'), + 'Greek_BETA': (0x07c2, u'\u0392'), + 'Greek_CHI': (0x07d7, u'\u03A7'), + 'Greek_DELTA': (0x07c4, u'\u0394'), + 'Greek_EPSILON': (0x07c5, u'\u0395'), + 'Greek_EPSILONaccent': (0x07a2, u'\u0388'), + 'Greek_ETA': (0x07c7, u'\u0397'), + 'Greek_ETAaccent': (0x07a3, u'\u0389'), + 'Greek_GAMMA': (0x07c3, u'\u0393'), + 'Greek_IOTA': (0x07c9, u'\u0399'), + 'Greek_IOTAaccent': (0x07a4, u'\u038A'), + 'Greek_IOTAdieresis': (0x07a5, u'\u03AA'), + 'Greek_KAPPA': (0x07ca, u'\u039A'), + 'Greek_LAMBDA': (0x07cb, u'\u039B'), + 'Greek_LAMDA': (0x07cb, u'\u039B'), + 'Greek_MU': (0x07cc, u'\u039C'), + 'Greek_NU': (0x07cd, u'\u039D'), + 'Greek_OMEGA': (0x07d9, u'\u03A9'), + 'Greek_OMEGAaccent': (0x07ab, u'\u038F'), + 'Greek_OMICRON': (0x07cf, u'\u039F'), + 'Greek_OMICRONaccent': (0x07a7, u'\u038C'), + 'Greek_PHI': (0x07d6, u'\u03A6'), + 'Greek_PI': (0x07d0, u'\u03A0'), + 'Greek_PSI': (0x07d8, u'\u03A8'), + 'Greek_RHO': (0x07d1, u'\u03A1'), + 'Greek_SIGMA': (0x07d2, u'\u03A3'), + 'Greek_TAU': (0x07d4, u'\u03A4'), + 'Greek_THETA': (0x07c8, u'\u0398'), + 'Greek_UPSILON': (0x07d5, u'\u03A5'), + 'Greek_UPSILONaccent': (0x07a8, u'\u038E'), + 'Greek_UPSILONdieresis': (0x07a9, u'\u03AB'), + 'Greek_XI': (0x07ce, u'\u039E'), + 'Greek_ZETA': (0x07c6, u'\u0396'), + 'Greek_accentdieresis': (0x07ae, u'\u0385'), + 'Greek_alpha': (0x07e1, u'\u03B1'), + 'Greek_alphaaccent': (0x07b1, u'\u03AC'), + 'Greek_beta': (0x07e2, u'\u03B2'), + 'Greek_chi': (0x07f7, u'\u03C7'), + 'Greek_delta': (0x07e4, u'\u03B4'), + 'Greek_epsilon': (0x07e5, u'\u03B5'), + 'Greek_epsilonaccent': (0x07b2, u'\u03AD'), + 'Greek_eta': (0x07e7, u'\u03B7'), + 'Greek_etaaccent': (0x07b3, u'\u03AE'), + 'Greek_finalsmallsigma': (0x07f3, u'\u03C2'), + 'Greek_gamma': (0x07e3, u'\u03B3'), + 'Greek_horizbar': (0x07af, u'\u2015'), + 'Greek_iota': (0x07e9, u'\u03B9'), + 'Greek_iotaaccent': (0x07b4, u'\u03AF'), + 'Greek_iotaaccentdieresis': (0x07b6, u'\u0390'), + 'Greek_iotadieresis': (0x07b5, u'\u03CA'), + 'Greek_kappa': (0x07ea, u'\u03BA'), + 'Greek_lambda': (0x07eb, u'\u03BB'), + 'Greek_lamda': (0x07eb, u'\u03BB'), + 'Greek_mu': (0x07ec, u'\u03BC'), + 'Greek_nu': (0x07ed, u'\u03BD'), + 'Greek_omega': (0x07f9, u'\u03C9'), + 'Greek_omegaaccent': (0x07bb, u'\u03CE'), + 'Greek_omicron': (0x07ef, u'\u03BF'), + 'Greek_omicronaccent': (0x07b7, u'\u03CC'), + 'Greek_phi': (0x07f6, u'\u03C6'), + 'Greek_pi': (0x07f0, u'\u03C0'), + 'Greek_psi': (0x07f8, u'\u03C8'), + 'Greek_rho': (0x07f1, u'\u03C1'), + 'Greek_sigma': (0x07f2, u'\u03C3'), + 'Greek_tau': (0x07f4, u'\u03C4'), + 'Greek_theta': (0x07e8, u'\u03B8'), + 'Greek_upsilon': (0x07f5, u'\u03C5'), + 'Greek_upsilonaccent': (0x07b8, u'\u03CD'), + 'Greek_upsilonaccentdieresis': (0x07ba, u'\u03B0'), + 'Greek_upsilondieresis': (0x07b9, u'\u03CB'), + 'Greek_xi': (0x07ee, u'\u03BE'), + 'Greek_zeta': (0x07e6, u'\u03B6'), + 'H': (0x0048, u'\u0048'), + 'Hcircumflex': (0x02a6, u'\u0124'), + 'Hstroke': (0x02a1, u'\u0126'), + 'I': (0x0049, u'\u0049'), + 'Iabovedot': (0x02a9, u'\u0130'), + 'Iacute': (0x00cd, u'\u00CD'), + 'Ibelowdot': (0x1001eca, u'\u1ECA'), + 'Ibreve': (0x100012c, u'\u012C'), + 'Icircumflex': (0x00ce, u'\u00CE'), + 'Idiaeresis': (0x00cf, u'\u00CF'), + 'Igrave': (0x00cc, u'\u00CC'), + 'Ihook': (0x1001ec8, u'\u1EC8'), + 'Imacron': (0x03cf, u'\u012A'), + 'Iogonek': (0x03c7, u'\u012E'), + 'Itilde': (0x03a5, u'\u0128'), + 'J': (0x004a, u'\u004A'), + 'Jcircumflex': (0x02ac, u'\u0134'), + 'K': (0x004b, u'\u004B'), + 'KP_0': (0xffb0, None), + 'KP_1': (0xffb1, None), + 'KP_2': (0xffb2, None), + 'KP_3': (0xffb3, None), + 'KP_4': (0xffb4, None), + 'KP_5': (0xffb5, None), + 'KP_6': (0xffb6, None), + 'KP_7': (0xffb7, None), + 'KP_8': (0xffb8, None), + 'KP_9': (0xffb9, None), + 'KP_Add': (0xffab, None), + 'KP_Begin': (0xff9d, None), + 'KP_Decimal': (0xffae, None), + 'KP_Delete': (0xff9f, None), + 'KP_Divide': (0xffaf, None), + 'KP_Down': (0xff99, None), + 'KP_End': (0xff9c, None), + 'KP_Enter': (0xff8d, None), + 'KP_Equal': (0xffbd, None), + 'KP_F1': (0xff91, None), + 'KP_F2': (0xff92, None), + 'KP_F3': (0xff93, None), + 'KP_F4': (0xff94, None), + 'KP_Home': (0xff95, None), + 'KP_Insert': (0xff9e, None), + 'KP_Left': (0xff96, None), + 'KP_Multiply': (0xffaa, None), + 'KP_Next': (0xff9b, None), + 'KP_Page_Down': (0xff9b, None), + 'KP_Page_Up': (0xff9a, None), + 'KP_Prior': (0xff9a, None), + 'KP_Right': (0xff98, None), + 'KP_Separator': (0xffac, None), + 'KP_Space': (0xff80, None), + 'KP_Subtract': (0xffad, None), + 'KP_Tab': (0xff89, None), + 'KP_Up': (0xff97, None), + 'Kcedilla': (0x03d3, u'\u0136'), + 'L': (0x004c, u'\u004C'), + 'Lacute': (0x01c5, u'\u0139'), + 'Lbelowdot': (0x1001e36, u'\u1E36'), + 'Lcaron': (0x01a5, u'\u013D'), + 'Lcedilla': (0x03a6, u'\u013B'), + 'LiraSign': (0x10020a4, u'\u20A4'), + 'Lstroke': (0x01a3, u'\u0141'), + 'M': (0x004d, u'\u004D'), + 'Mabovedot': (0x1001e40, u'\u1E40'), + 'Macedonia_DSE': (0x06b5, u'\u0405'), + 'Macedonia_GJE': (0x06b2, u'\u0403'), + 'Macedonia_KJE': (0x06bc, u'\u040C'), + 'Macedonia_dse': (0x06a5, u'\u0455'), + 'Macedonia_gje': (0x06a2, u'\u0453'), + 'Macedonia_kje': (0x06ac, u'\u045C'), + 'MillSign': (0x10020a5, u'\u20A5'), + 'N': (0x004e, u'\u004E'), + 'Nacute': (0x01d1, u'\u0143'), + 'NairaSign': (0x10020a6, u'\u20A6'), + 'Ncaron': (0x01d2, u'\u0147'), + 'Ncedilla': (0x03d1, u'\u0145'), + 'NewSheqelSign': (0x10020aa, u'\u20AA'), + 'Ntilde': (0x00d1, u'\u00D1'), + 'O': (0x004f, u'\u004F'), + 'OE': (0x13bc, u'\u0152'), + 'Oacute': (0x00d3, u'\u00D3'), + 'Obarred': (0x100019f, u'\u019F'), + 'Obelowdot': (0x1001ecc, u'\u1ECC'), + 'Ocaron': (0x10001d1, u'\u01D2'), + 'Ocircumflex': (0x00d4, u'\u00D4'), + 'Ocircumflexacute': (0x1001ed0, u'\u1ED0'), + 'Ocircumflexbelowdot': (0x1001ed8, u'\u1ED8'), + 'Ocircumflexgrave': (0x1001ed2, u'\u1ED2'), + 'Ocircumflexhook': (0x1001ed4, u'\u1ED4'), + 'Ocircumflextilde': (0x1001ed6, u'\u1ED6'), + 'Odiaeresis': (0x00d6, u'\u00D6'), + 'Odoubleacute': (0x01d5, u'\u0150'), + 'Ograve': (0x00d2, u'\u00D2'), + 'Ohook': (0x1001ece, u'\u1ECE'), + 'Ohorn': (0x10001a0, u'\u01A0'), + 'Ohornacute': (0x1001eda, u'\u1EDA'), + 'Ohornbelowdot': (0x1001ee2, u'\u1EE2'), + 'Ohorngrave': (0x1001edc, u'\u1EDC'), + 'Ohornhook': (0x1001ede, u'\u1EDE'), + 'Ohorntilde': (0x1001ee0, u'\u1EE0'), + 'Omacron': (0x03d2, u'\u014C'), + 'Ooblique': (0x00d8, u'\u00D8'), + 'Oslash': (0x00d8, u'\u00D8'), + 'Otilde': (0x00d5, u'\u00D5'), + 'P': (0x0050, u'\u0050'), + 'Pabovedot': (0x1001e56, u'\u1E56'), + 'PesetaSign': (0x10020a7, u'\u20A7'), + 'Q': (0x0051, u'\u0051'), + 'R': (0x0052, u'\u0052'), + 'Racute': (0x01c0, u'\u0154'), + 'Rcaron': (0x01d8, u'\u0158'), + 'Rcedilla': (0x03a3, u'\u0156'), + 'RupeeSign': (0x10020a8, u'\u20A8'), + 'S': (0x0053, u'\u0053'), + 'SCHWA': (0x100018f, u'\u018F'), + 'Sabovedot': (0x1001e60, u'\u1E60'), + 'Sacute': (0x01a6, u'\u015A'), + 'Scaron': (0x01a9, u'\u0160'), + 'Scedilla': (0x01aa, u'\u015E'), + 'Scircumflex': (0x02de, u'\u015C'), + 'Serbian_DJE': (0x06b1, u'\u0402'), + 'Serbian_TSHE': (0x06bb, u'\u040B'), + 'Serbian_dje': (0x06a1, u'\u0452'), + 'Serbian_tshe': (0x06ab, u'\u045B'), + 'Sinh_a': (0x1000d85, u'\u0D85'), + 'Sinh_aa': (0x1000d86, u'\u0D86'), + 'Sinh_aa2': (0x1000dcf, u'\u0DCF'), + 'Sinh_ae': (0x1000d87, u'\u0D87'), + 'Sinh_ae2': (0x1000dd0, u'\u0DD0'), + 'Sinh_aee': (0x1000d88, u'\u0D88'), + 'Sinh_aee2': (0x1000dd1, u'\u0DD1'), + 'Sinh_ai': (0x1000d93, u'\u0D93'), + 'Sinh_ai2': (0x1000ddb, u'\u0DDB'), + 'Sinh_al': (0x1000dca, u'\u0DCA'), + 'Sinh_au': (0x1000d96, u'\u0D96'), + 'Sinh_au2': (0x1000dde, u'\u0DDE'), + 'Sinh_ba': (0x1000db6, u'\u0DB6'), + 'Sinh_bha': (0x1000db7, u'\u0DB7'), + 'Sinh_ca': (0x1000da0, u'\u0DA0'), + 'Sinh_cha': (0x1000da1, u'\u0DA1'), + 'Sinh_dda': (0x1000da9, u'\u0DA9'), + 'Sinh_ddha': (0x1000daa, u'\u0DAA'), + 'Sinh_dha': (0x1000daf, u'\u0DAF'), + 'Sinh_dhha': (0x1000db0, u'\u0DB0'), + 'Sinh_e': (0x1000d91, u'\u0D91'), + 'Sinh_e2': (0x1000dd9, u'\u0DD9'), + 'Sinh_ee': (0x1000d92, u'\u0D92'), + 'Sinh_ee2': (0x1000dda, u'\u0DDA'), + 'Sinh_fa': (0x1000dc6, u'\u0DC6'), + 'Sinh_ga': (0x1000d9c, u'\u0D9C'), + 'Sinh_gha': (0x1000d9d, u'\u0D9D'), + 'Sinh_h2': (0x1000d83, u'\u0D83'), + 'Sinh_ha': (0x1000dc4, u'\u0DC4'), + 'Sinh_i': (0x1000d89, u'\u0D89'), + 'Sinh_i2': (0x1000dd2, u'\u0DD2'), + 'Sinh_ii': (0x1000d8a, u'\u0D8A'), + 'Sinh_ii2': (0x1000dd3, u'\u0DD3'), + 'Sinh_ja': (0x1000da2, u'\u0DA2'), + 'Sinh_jha': (0x1000da3, u'\u0DA3'), + 'Sinh_jnya': (0x1000da5, u'\u0DA5'), + 'Sinh_ka': (0x1000d9a, u'\u0D9A'), + 'Sinh_kha': (0x1000d9b, u'\u0D9B'), + 'Sinh_kunddaliya': (0x1000df4, u'\u0DF4'), + 'Sinh_la': (0x1000dbd, u'\u0DBD'), + 'Sinh_lla': (0x1000dc5, u'\u0DC5'), + 'Sinh_lu': (0x1000d8f, u'\u0D8F'), + 'Sinh_lu2': (0x1000ddf, u'\u0DDF'), + 'Sinh_luu': (0x1000d90, u'\u0D90'), + 'Sinh_luu2': (0x1000df3, u'\u0DF3'), + 'Sinh_ma': (0x1000db8, u'\u0DB8'), + 'Sinh_mba': (0x1000db9, u'\u0DB9'), + 'Sinh_na': (0x1000db1, u'\u0DB1'), + 'Sinh_ndda': (0x1000dac, u'\u0DAC'), + 'Sinh_ndha': (0x1000db3, u'\u0DB3'), + 'Sinh_ng': (0x1000d82, u'\u0D82'), + 'Sinh_ng2': (0x1000d9e, u'\u0D9E'), + 'Sinh_nga': (0x1000d9f, u'\u0D9F'), + 'Sinh_nja': (0x1000da6, u'\u0DA6'), + 'Sinh_nna': (0x1000dab, u'\u0DAB'), + 'Sinh_nya': (0x1000da4, u'\u0DA4'), + 'Sinh_o': (0x1000d94, u'\u0D94'), + 'Sinh_o2': (0x1000ddc, u'\u0DDC'), + 'Sinh_oo': (0x1000d95, u'\u0D95'), + 'Sinh_oo2': (0x1000ddd, u'\u0DDD'), + 'Sinh_pa': (0x1000db4, u'\u0DB4'), + 'Sinh_pha': (0x1000db5, u'\u0DB5'), + 'Sinh_ra': (0x1000dbb, u'\u0DBB'), + 'Sinh_ri': (0x1000d8d, u'\u0D8D'), + 'Sinh_rii': (0x1000d8e, u'\u0D8E'), + 'Sinh_ru2': (0x1000dd8, u'\u0DD8'), + 'Sinh_ruu2': (0x1000df2, u'\u0DF2'), + 'Sinh_sa': (0x1000dc3, u'\u0DC3'), + 'Sinh_sha': (0x1000dc1, u'\u0DC1'), + 'Sinh_ssha': (0x1000dc2, u'\u0DC2'), + 'Sinh_tha': (0x1000dad, u'\u0DAD'), + 'Sinh_thha': (0x1000dae, u'\u0DAE'), + 'Sinh_tta': (0x1000da7, u'\u0DA7'), + 'Sinh_ttha': (0x1000da8, u'\u0DA8'), + 'Sinh_u': (0x1000d8b, u'\u0D8B'), + 'Sinh_u2': (0x1000dd4, u'\u0DD4'), + 'Sinh_uu': (0x1000d8c, u'\u0D8C'), + 'Sinh_uu2': (0x1000dd6, u'\u0DD6'), + 'Sinh_va': (0x1000dc0, u'\u0DC0'), + 'Sinh_ya': (0x1000dba, u'\u0DBA'), + 'T': (0x0054, u'\u0054'), + 'THORN': (0x00de, u'\u00DE'), + 'Tabovedot': (0x1001e6a, u'\u1E6A'), + 'Tcaron': (0x01ab, u'\u0164'), + 'Tcedilla': (0x01de, u'\u0162'), + 'Thai_baht': (0x0ddf, u'\u0E3F'), + 'Thai_bobaimai': (0x0dba, u'\u0E1A'), + 'Thai_chochan': (0x0da8, u'\u0E08'), + 'Thai_chochang': (0x0daa, u'\u0E0A'), + 'Thai_choching': (0x0da9, u'\u0E09'), + 'Thai_chochoe': (0x0dac, u'\u0E0C'), + 'Thai_dochada': (0x0dae, u'\u0E0E'), + 'Thai_dodek': (0x0db4, u'\u0E14'), + 'Thai_fofa': (0x0dbd, u'\u0E1D'), + 'Thai_fofan': (0x0dbf, u'\u0E1F'), + 'Thai_hohip': (0x0dcb, u'\u0E2B'), + 'Thai_honokhuk': (0x0dce, u'\u0E2E'), + 'Thai_khokhai': (0x0da2, u'\u0E02'), + 'Thai_khokhon': (0x0da5, u'\u0E05'), + 'Thai_khokhuat': (0x0da3, u'\u0E03'), + 'Thai_khokhwai': (0x0da4, u'\u0E04'), + 'Thai_khorakhang': (0x0da6, u'\u0E06'), + 'Thai_kokai': (0x0da1, u'\u0E01'), + 'Thai_lakkhangyao': (0x0de5, u'\u0E45'), + 'Thai_lekchet': (0x0df7, u'\u0E57'), + 'Thai_lekha': (0x0df5, u'\u0E55'), + 'Thai_lekhok': (0x0df6, u'\u0E56'), + 'Thai_lekkao': (0x0df9, u'\u0E59'), + 'Thai_leknung': (0x0df1, u'\u0E51'), + 'Thai_lekpaet': (0x0df8, u'\u0E58'), + 'Thai_leksam': (0x0df3, u'\u0E53'), + 'Thai_leksi': (0x0df4, u'\u0E54'), + 'Thai_leksong': (0x0df2, u'\u0E52'), + 'Thai_leksun': (0x0df0, u'\u0E50'), + 'Thai_lochula': (0x0dcc, u'\u0E2C'), + 'Thai_loling': (0x0dc5, u'\u0E25'), + 'Thai_lu': (0x0dc6, u'\u0E26'), + 'Thai_maichattawa': (0x0deb, u'\u0E4B'), + 'Thai_maiek': (0x0de8, u'\u0E48'), + 'Thai_maihanakat': (0x0dd1, u'\u0E31'), + 'Thai_maitaikhu': (0x0de7, u'\u0E47'), + 'Thai_maitho': (0x0de9, u'\u0E49'), + 'Thai_maitri': (0x0dea, u'\u0E4A'), + 'Thai_maiyamok': (0x0de6, u'\u0E46'), + 'Thai_moma': (0x0dc1, u'\u0E21'), + 'Thai_ngongu': (0x0da7, u'\u0E07'), + 'Thai_nikhahit': (0x0ded, u'\u0E4D'), + 'Thai_nonen': (0x0db3, u'\u0E13'), + 'Thai_nonu': (0x0db9, u'\u0E19'), + 'Thai_oang': (0x0dcd, u'\u0E2D'), + 'Thai_paiyannoi': (0x0dcf, u'\u0E2F'), + 'Thai_phinthu': (0x0dda, u'\u0E3A'), + 'Thai_phophan': (0x0dbe, u'\u0E1E'), + 'Thai_phophung': (0x0dbc, u'\u0E1C'), + 'Thai_phosamphao': (0x0dc0, u'\u0E20'), + 'Thai_popla': (0x0dbb, u'\u0E1B'), + 'Thai_rorua': (0x0dc3, u'\u0E23'), + 'Thai_ru': (0x0dc4, u'\u0E24'), + 'Thai_saraa': (0x0dd0, u'\u0E30'), + 'Thai_saraaa': (0x0dd2, u'\u0E32'), + 'Thai_saraae': (0x0de1, u'\u0E41'), + 'Thai_saraaimaimalai': (0x0de4, u'\u0E44'), + 'Thai_saraaimaimuan': (0x0de3, u'\u0E43'), + 'Thai_saraam': (0x0dd3, u'\u0E33'), + 'Thai_sarae': (0x0de0, u'\u0E40'), + 'Thai_sarai': (0x0dd4, u'\u0E34'), + 'Thai_saraii': (0x0dd5, u'\u0E35'), + 'Thai_sarao': (0x0de2, u'\u0E42'), + 'Thai_sarau': (0x0dd8, u'\u0E38'), + 'Thai_saraue': (0x0dd6, u'\u0E36'), + 'Thai_sarauee': (0x0dd7, u'\u0E37'), + 'Thai_sarauu': (0x0dd9, u'\u0E39'), + 'Thai_sorusi': (0x0dc9, u'\u0E29'), + 'Thai_sosala': (0x0dc8, u'\u0E28'), + 'Thai_soso': (0x0dab, u'\u0E0B'), + 'Thai_sosua': (0x0dca, u'\u0E2A'), + 'Thai_thanthakhat': (0x0dec, u'\u0E4C'), + 'Thai_thonangmontho': (0x0db1, u'\u0E11'), + 'Thai_thophuthao': (0x0db2, u'\u0E12'), + 'Thai_thothahan': (0x0db7, u'\u0E17'), + 'Thai_thothan': (0x0db0, u'\u0E10'), + 'Thai_thothong': (0x0db8, u'\u0E18'), + 'Thai_thothung': (0x0db6, u'\u0E16'), + 'Thai_topatak': (0x0daf, u'\u0E0F'), + 'Thai_totao': (0x0db5, u'\u0E15'), + 'Thai_wowaen': (0x0dc7, u'\u0E27'), + 'Thai_yoyak': (0x0dc2, u'\u0E22'), + 'Thai_yoying': (0x0dad, u'\u0E0D'), + 'Tslash': (0x03ac, u'\u0166'), + 'U': (0x0055, u'\u0055'), + 'Uacute': (0x00da, u'\u00DA'), + 'Ubelowdot': (0x1001ee4, u'\u1EE4'), + 'Ubreve': (0x02dd, u'\u016C'), + 'Ucircumflex': (0x00db, u'\u00DB'), + 'Udiaeresis': (0x00dc, u'\u00DC'), + 'Udoubleacute': (0x01db, u'\u0170'), + 'Ugrave': (0x00d9, u'\u00D9'), + 'Uhook': (0x1001ee6, u'\u1EE6'), + 'Uhorn': (0x10001af, u'\u01AF'), + 'Uhornacute': (0x1001ee8, u'\u1EE8'), + 'Uhornbelowdot': (0x1001ef0, u'\u1EF0'), + 'Uhorngrave': (0x1001eea, u'\u1EEA'), + 'Uhornhook': (0x1001eec, u'\u1EEC'), + 'Uhorntilde': (0x1001eee, u'\u1EEE'), + 'Ukrainian_GHE_WITH_UPTURN': (0x06bd, u'\u0490'), + 'Ukrainian_I': (0x06b6, u'\u0406'), + 'Ukrainian_IE': (0x06b4, u'\u0404'), + 'Ukrainian_YI': (0x06b7, u'\u0407'), + 'Ukrainian_ghe_with_upturn': (0x06ad, u'\u0491'), + 'Ukrainian_i': (0x06a6, u'\u0456'), + 'Ukrainian_ie': (0x06a4, u'\u0454'), + 'Ukrainian_yi': (0x06a7, u'\u0457'), + 'Umacron': (0x03de, u'\u016A'), + 'Uogonek': (0x03d9, u'\u0172'), + 'Uring': (0x01d9, u'\u016E'), + 'Utilde': (0x03dd, u'\u0168'), + 'V': (0x0056, u'\u0056'), + 'W': (0x0057, u'\u0057'), + 'Wacute': (0x1001e82, u'\u1E82'), + 'Wcircumflex': (0x1000174, u'\u0174'), + 'Wdiaeresis': (0x1001e84, u'\u1E84'), + 'Wgrave': (0x1001e80, u'\u1E80'), + 'WonSign': (0x10020a9, u'\u20A9'), + 'X': (0x0058, u'\u0058'), + 'Xabovedot': (0x1001e8a, u'\u1E8A'), + 'Y': (0x0059, u'\u0059'), + 'Yacute': (0x00dd, u'\u00DD'), + 'Ybelowdot': (0x1001ef4, u'\u1EF4'), + 'Ycircumflex': (0x1000176, u'\u0176'), + 'Ydiaeresis': (0x13be, u'\u0178'), + 'Ygrave': (0x1001ef2, u'\u1EF2'), + 'Yhook': (0x1001ef6, u'\u1EF6'), + 'Ytilde': (0x1001ef8, u'\u1EF8'), + 'Z': (0x005a, u'\u005A'), + 'Zabovedot': (0x01af, u'\u017B'), + 'Zacute': (0x01ac, u'\u0179'), + 'Zcaron': (0x01ae, u'\u017D'), + 'Zstroke': (0x10001b5, u'\u01B5'), + 'a': (0x0061, u'\u0061'), + 'aacute': (0x00e1, u'\u00E1'), + 'abelowdot': (0x1001ea1, u'\u1EA1'), + 'abovedot': (0x01ff, u'\u02D9'), + 'abreve': (0x01e3, u'\u0103'), + 'abreveacute': (0x1001eaf, u'\u1EAF'), + 'abrevebelowdot': (0x1001eb7, u'\u1EB7'), + 'abrevegrave': (0x1001eb1, u'\u1EB1'), + 'abrevehook': (0x1001eb3, u'\u1EB3'), + 'abrevetilde': (0x1001eb5, u'\u1EB5'), + 'acircumflex': (0x00e2, u'\u00E2'), + 'acircumflexacute': (0x1001ea5, u'\u1EA5'), + 'acircumflexbelowdot': (0x1001ead, u'\u1EAD'), + 'acircumflexgrave': (0x1001ea7, u'\u1EA7'), + 'acircumflexhook': (0x1001ea9, u'\u1EA9'), + 'acircumflextilde': (0x1001eab, u'\u1EAB'), + 'acute': (0x00b4, u'\u00B4'), + 'adiaeresis': (0x00e4, u'\u00E4'), + 'ae': (0x00e6, u'\u00E6'), + 'agrave': (0x00e0, u'\u00E0'), + 'ahook': (0x1001ea3, u'\u1EA3'), + 'amacron': (0x03e0, u'\u0101'), + 'ampersand': (0x0026, u'\u0026'), + 'aogonek': (0x01b1, u'\u0105'), + 'apostrophe': (0x0027, u'\u0027'), + 'approxeq': (0x1002248, u'\u2245'), + 'approximate': (0x08c8, u'\u223C'), + 'aring': (0x00e5, u'\u00E5'), + 'asciicircum': (0x005e, u'\u005E'), + 'asciitilde': (0x007e, u'\u007E'), + 'asterisk': (0x002a, u'\u002A'), + 'at': (0x0040, u'\u0040'), + 'atilde': (0x00e3, u'\u00E3'), + 'b': (0x0062, u'\u0062'), + 'babovedot': (0x1001e03, u'\u1E03'), + 'backslash': (0x005c, u'\u005C'), + 'ballotcross': (0x0af4, u'\u2717'), + 'bar': (0x007c, u'\u007C'), + 'because': (0x1002235, u'\u2235'), + 'botintegral': (0x08a5, u'\u2321'), + 'botleftparens': (0x08ac, u'\u239D'), + 'botleftsqbracket': (0x08a8, u'\u23A3'), + 'botrightparens': (0x08ae, u'\u23A0'), + 'botrightsqbracket': (0x08aa, u'\u23A6'), + 'bott': (0x09f6, u'\u2534'), + 'braceleft': (0x007b, u'\u007B'), + 'braceright': (0x007d, u'\u007D'), + 'bracketleft': (0x005b, u'\u005B'), + 'bracketright': (0x005d, u'\u005D'), + 'braille_blank': (0x1002800, u'\u2800'), + 'braille_dots_1': (0x1002801, u'\u2801'), + 'braille_dots_12': (0x1002803, u'\u2803'), + 'braille_dots_123': (0x1002807, u'\u2807'), + 'braille_dots_1234': (0x100280f, u'\u280f'), + 'braille_dots_12345': (0x100281f, u'\u281f'), + 'braille_dots_123456': (0x100283f, u'\u283f'), + 'braille_dots_1234567': (0x100287f, u'\u287f'), + 'braille_dots_12345678': (0x10028ff, u'\u28ff'), + 'braille_dots_1234568': (0x10028bf, u'\u28bf'), + 'braille_dots_123457': (0x100285f, u'\u285f'), + 'braille_dots_1234578': (0x10028df, u'\u28df'), + 'braille_dots_123458': (0x100289f, u'\u289f'), + 'braille_dots_12346': (0x100282f, u'\u282f'), + 'braille_dots_123467': (0x100286f, u'\u286f'), + 'braille_dots_1234678': (0x10028ef, u'\u28ef'), + 'braille_dots_123468': (0x10028af, u'\u28af'), + 'braille_dots_12347': (0x100284f, u'\u284f'), + 'braille_dots_123478': (0x10028cf, u'\u28cf'), + 'braille_dots_12348': (0x100288f, u'\u288f'), + 'braille_dots_1235': (0x1002817, u'\u2817'), + 'braille_dots_12356': (0x1002837, u'\u2837'), + 'braille_dots_123567': (0x1002877, u'\u2877'), + 'braille_dots_1235678': (0x10028f7, u'\u28f7'), + 'braille_dots_123568': (0x10028b7, u'\u28b7'), + 'braille_dots_12357': (0x1002857, u'\u2857'), + 'braille_dots_123578': (0x10028d7, u'\u28d7'), + 'braille_dots_12358': (0x1002897, u'\u2897'), + 'braille_dots_1236': (0x1002827, u'\u2827'), + 'braille_dots_12367': (0x1002867, u'\u2867'), + 'braille_dots_123678': (0x10028e7, u'\u28e7'), + 'braille_dots_12368': (0x10028a7, u'\u28a7'), + 'braille_dots_1237': (0x1002847, u'\u2847'), + 'braille_dots_12378': (0x10028c7, u'\u28c7'), + 'braille_dots_1238': (0x1002887, u'\u2887'), + 'braille_dots_124': (0x100280b, u'\u280b'), + 'braille_dots_1245': (0x100281b, u'\u281b'), + 'braille_dots_12456': (0x100283b, u'\u283b'), + 'braille_dots_124567': (0x100287b, u'\u287b'), + 'braille_dots_1245678': (0x10028fb, u'\u28fb'), + 'braille_dots_124568': (0x10028bb, u'\u28bb'), + 'braille_dots_12457': (0x100285b, u'\u285b'), + 'braille_dots_124578': (0x10028db, u'\u28db'), + 'braille_dots_12458': (0x100289b, u'\u289b'), + 'braille_dots_1246': (0x100282b, u'\u282b'), + 'braille_dots_12467': (0x100286b, u'\u286b'), + 'braille_dots_124678': (0x10028eb, u'\u28eb'), + 'braille_dots_12468': (0x10028ab, u'\u28ab'), + 'braille_dots_1247': (0x100284b, u'\u284b'), + 'braille_dots_12478': (0x10028cb, u'\u28cb'), + 'braille_dots_1248': (0x100288b, u'\u288b'), + 'braille_dots_125': (0x1002813, u'\u2813'), + 'braille_dots_1256': (0x1002833, u'\u2833'), + 'braille_dots_12567': (0x1002873, u'\u2873'), + 'braille_dots_125678': (0x10028f3, u'\u28f3'), + 'braille_dots_12568': (0x10028b3, u'\u28b3'), + 'braille_dots_1257': (0x1002853, u'\u2853'), + 'braille_dots_12578': (0x10028d3, u'\u28d3'), + 'braille_dots_1258': (0x1002893, u'\u2893'), + 'braille_dots_126': (0x1002823, u'\u2823'), + 'braille_dots_1267': (0x1002863, u'\u2863'), + 'braille_dots_12678': (0x10028e3, u'\u28e3'), + 'braille_dots_1268': (0x10028a3, u'\u28a3'), + 'braille_dots_127': (0x1002843, u'\u2843'), + 'braille_dots_1278': (0x10028c3, u'\u28c3'), + 'braille_dots_128': (0x1002883, u'\u2883'), + 'braille_dots_13': (0x1002805, u'\u2805'), + 'braille_dots_134': (0x100280d, u'\u280d'), + 'braille_dots_1345': (0x100281d, u'\u281d'), + 'braille_dots_13456': (0x100283d, u'\u283d'), + 'braille_dots_134567': (0x100287d, u'\u287d'), + 'braille_dots_1345678': (0x10028fd, u'\u28fd'), + 'braille_dots_134568': (0x10028bd, u'\u28bd'), + 'braille_dots_13457': (0x100285d, u'\u285d'), + 'braille_dots_134578': (0x10028dd, u'\u28dd'), + 'braille_dots_13458': (0x100289d, u'\u289d'), + 'braille_dots_1346': (0x100282d, u'\u282d'), + 'braille_dots_13467': (0x100286d, u'\u286d'), + 'braille_dots_134678': (0x10028ed, u'\u28ed'), + 'braille_dots_13468': (0x10028ad, u'\u28ad'), + 'braille_dots_1347': (0x100284d, u'\u284d'), + 'braille_dots_13478': (0x10028cd, u'\u28cd'), + 'braille_dots_1348': (0x100288d, u'\u288d'), + 'braille_dots_135': (0x1002815, u'\u2815'), + 'braille_dots_1356': (0x1002835, u'\u2835'), + 'braille_dots_13567': (0x1002875, u'\u2875'), + 'braille_dots_135678': (0x10028f5, u'\u28f5'), + 'braille_dots_13568': (0x10028b5, u'\u28b5'), + 'braille_dots_1357': (0x1002855, u'\u2855'), + 'braille_dots_13578': (0x10028d5, u'\u28d5'), + 'braille_dots_1358': (0x1002895, u'\u2895'), + 'braille_dots_136': (0x1002825, u'\u2825'), + 'braille_dots_1367': (0x1002865, u'\u2865'), + 'braille_dots_13678': (0x10028e5, u'\u28e5'), + 'braille_dots_1368': (0x10028a5, u'\u28a5'), + 'braille_dots_137': (0x1002845, u'\u2845'), + 'braille_dots_1378': (0x10028c5, u'\u28c5'), + 'braille_dots_138': (0x1002885, u'\u2885'), + 'braille_dots_14': (0x1002809, u'\u2809'), + 'braille_dots_145': (0x1002819, u'\u2819'), + 'braille_dots_1456': (0x1002839, u'\u2839'), + 'braille_dots_14567': (0x1002879, u'\u2879'), + 'braille_dots_145678': (0x10028f9, u'\u28f9'), + 'braille_dots_14568': (0x10028b9, u'\u28b9'), + 'braille_dots_1457': (0x1002859, u'\u2859'), + 'braille_dots_14578': (0x10028d9, u'\u28d9'), + 'braille_dots_1458': (0x1002899, u'\u2899'), + 'braille_dots_146': (0x1002829, u'\u2829'), + 'braille_dots_1467': (0x1002869, u'\u2869'), + 'braille_dots_14678': (0x10028e9, u'\u28e9'), + 'braille_dots_1468': (0x10028a9, u'\u28a9'), + 'braille_dots_147': (0x1002849, u'\u2849'), + 'braille_dots_1478': (0x10028c9, u'\u28c9'), + 'braille_dots_148': (0x1002889, u'\u2889'), + 'braille_dots_15': (0x1002811, u'\u2811'), + 'braille_dots_156': (0x1002831, u'\u2831'), + 'braille_dots_1567': (0x1002871, u'\u2871'), + 'braille_dots_15678': (0x10028f1, u'\u28f1'), + 'braille_dots_1568': (0x10028b1, u'\u28b1'), + 'braille_dots_157': (0x1002851, u'\u2851'), + 'braille_dots_1578': (0x10028d1, u'\u28d1'), + 'braille_dots_158': (0x1002891, u'\u2891'), + 'braille_dots_16': (0x1002821, u'\u2821'), + 'braille_dots_167': (0x1002861, u'\u2861'), + 'braille_dots_1678': (0x10028e1, u'\u28e1'), + 'braille_dots_168': (0x10028a1, u'\u28a1'), + 'braille_dots_17': (0x1002841, u'\u2841'), + 'braille_dots_178': (0x10028c1, u'\u28c1'), + 'braille_dots_18': (0x1002881, u'\u2881'), + 'braille_dots_2': (0x1002802, u'\u2802'), + 'braille_dots_23': (0x1002806, u'\u2806'), + 'braille_dots_234': (0x100280e, u'\u280e'), + 'braille_dots_2345': (0x100281e, u'\u281e'), + 'braille_dots_23456': (0x100283e, u'\u283e'), + 'braille_dots_234567': (0x100287e, u'\u287e'), + 'braille_dots_2345678': (0x10028fe, u'\u28fe'), + 'braille_dots_234568': (0x10028be, u'\u28be'), + 'braille_dots_23457': (0x100285e, u'\u285e'), + 'braille_dots_234578': (0x10028de, u'\u28de'), + 'braille_dots_23458': (0x100289e, u'\u289e'), + 'braille_dots_2346': (0x100282e, u'\u282e'), + 'braille_dots_23467': (0x100286e, u'\u286e'), + 'braille_dots_234678': (0x10028ee, u'\u28ee'), + 'braille_dots_23468': (0x10028ae, u'\u28ae'), + 'braille_dots_2347': (0x100284e, u'\u284e'), + 'braille_dots_23478': (0x10028ce, u'\u28ce'), + 'braille_dots_2348': (0x100288e, u'\u288e'), + 'braille_dots_235': (0x1002816, u'\u2816'), + 'braille_dots_2356': (0x1002836, u'\u2836'), + 'braille_dots_23567': (0x1002876, u'\u2876'), + 'braille_dots_235678': (0x10028f6, u'\u28f6'), + 'braille_dots_23568': (0x10028b6, u'\u28b6'), + 'braille_dots_2357': (0x1002856, u'\u2856'), + 'braille_dots_23578': (0x10028d6, u'\u28d6'), + 'braille_dots_2358': (0x1002896, u'\u2896'), + 'braille_dots_236': (0x1002826, u'\u2826'), + 'braille_dots_2367': (0x1002866, u'\u2866'), + 'braille_dots_23678': (0x10028e6, u'\u28e6'), + 'braille_dots_2368': (0x10028a6, u'\u28a6'), + 'braille_dots_237': (0x1002846, u'\u2846'), + 'braille_dots_2378': (0x10028c6, u'\u28c6'), + 'braille_dots_238': (0x1002886, u'\u2886'), + 'braille_dots_24': (0x100280a, u'\u280a'), + 'braille_dots_245': (0x100281a, u'\u281a'), + 'braille_dots_2456': (0x100283a, u'\u283a'), + 'braille_dots_24567': (0x100287a, u'\u287a'), + 'braille_dots_245678': (0x10028fa, u'\u28fa'), + 'braille_dots_24568': (0x10028ba, u'\u28ba'), + 'braille_dots_2457': (0x100285a, u'\u285a'), + 'braille_dots_24578': (0x10028da, u'\u28da'), + 'braille_dots_2458': (0x100289a, u'\u289a'), + 'braille_dots_246': (0x100282a, u'\u282a'), + 'braille_dots_2467': (0x100286a, u'\u286a'), + 'braille_dots_24678': (0x10028ea, u'\u28ea'), + 'braille_dots_2468': (0x10028aa, u'\u28aa'), + 'braille_dots_247': (0x100284a, u'\u284a'), + 'braille_dots_2478': (0x10028ca, u'\u28ca'), + 'braille_dots_248': (0x100288a, u'\u288a'), + 'braille_dots_25': (0x1002812, u'\u2812'), + 'braille_dots_256': (0x1002832, u'\u2832'), + 'braille_dots_2567': (0x1002872, u'\u2872'), + 'braille_dots_25678': (0x10028f2, u'\u28f2'), + 'braille_dots_2568': (0x10028b2, u'\u28b2'), + 'braille_dots_257': (0x1002852, u'\u2852'), + 'braille_dots_2578': (0x10028d2, u'\u28d2'), + 'braille_dots_258': (0x1002892, u'\u2892'), + 'braille_dots_26': (0x1002822, u'\u2822'), + 'braille_dots_267': (0x1002862, u'\u2862'), + 'braille_dots_2678': (0x10028e2, u'\u28e2'), + 'braille_dots_268': (0x10028a2, u'\u28a2'), + 'braille_dots_27': (0x1002842, u'\u2842'), + 'braille_dots_278': (0x10028c2, u'\u28c2'), + 'braille_dots_28': (0x1002882, u'\u2882'), + 'braille_dots_3': (0x1002804, u'\u2804'), + 'braille_dots_34': (0x100280c, u'\u280c'), + 'braille_dots_345': (0x100281c, u'\u281c'), + 'braille_dots_3456': (0x100283c, u'\u283c'), + 'braille_dots_34567': (0x100287c, u'\u287c'), + 'braille_dots_345678': (0x10028fc, u'\u28fc'), + 'braille_dots_34568': (0x10028bc, u'\u28bc'), + 'braille_dots_3457': (0x100285c, u'\u285c'), + 'braille_dots_34578': (0x10028dc, u'\u28dc'), + 'braille_dots_3458': (0x100289c, u'\u289c'), + 'braille_dots_346': (0x100282c, u'\u282c'), + 'braille_dots_3467': (0x100286c, u'\u286c'), + 'braille_dots_34678': (0x10028ec, u'\u28ec'), + 'braille_dots_3468': (0x10028ac, u'\u28ac'), + 'braille_dots_347': (0x100284c, u'\u284c'), + 'braille_dots_3478': (0x10028cc, u'\u28cc'), + 'braille_dots_348': (0x100288c, u'\u288c'), + 'braille_dots_35': (0x1002814, u'\u2814'), + 'braille_dots_356': (0x1002834, u'\u2834'), + 'braille_dots_3567': (0x1002874, u'\u2874'), + 'braille_dots_35678': (0x10028f4, u'\u28f4'), + 'braille_dots_3568': (0x10028b4, u'\u28b4'), + 'braille_dots_357': (0x1002854, u'\u2854'), + 'braille_dots_3578': (0x10028d4, u'\u28d4'), + 'braille_dots_358': (0x1002894, u'\u2894'), + 'braille_dots_36': (0x1002824, u'\u2824'), + 'braille_dots_367': (0x1002864, u'\u2864'), + 'braille_dots_3678': (0x10028e4, u'\u28e4'), + 'braille_dots_368': (0x10028a4, u'\u28a4'), + 'braille_dots_37': (0x1002844, u'\u2844'), + 'braille_dots_378': (0x10028c4, u'\u28c4'), + 'braille_dots_38': (0x1002884, u'\u2884'), + 'braille_dots_4': (0x1002808, u'\u2808'), + 'braille_dots_45': (0x1002818, u'\u2818'), + 'braille_dots_456': (0x1002838, u'\u2838'), + 'braille_dots_4567': (0x1002878, u'\u2878'), + 'braille_dots_45678': (0x10028f8, u'\u28f8'), + 'braille_dots_4568': (0x10028b8, u'\u28b8'), + 'braille_dots_457': (0x1002858, u'\u2858'), + 'braille_dots_4578': (0x10028d8, u'\u28d8'), + 'braille_dots_458': (0x1002898, u'\u2898'), + 'braille_dots_46': (0x1002828, u'\u2828'), + 'braille_dots_467': (0x1002868, u'\u2868'), + 'braille_dots_4678': (0x10028e8, u'\u28e8'), + 'braille_dots_468': (0x10028a8, u'\u28a8'), + 'braille_dots_47': (0x1002848, u'\u2848'), + 'braille_dots_478': (0x10028c8, u'\u28c8'), + 'braille_dots_48': (0x1002888, u'\u2888'), + 'braille_dots_5': (0x1002810, u'\u2810'), + 'braille_dots_56': (0x1002830, u'\u2830'), + 'braille_dots_567': (0x1002870, u'\u2870'), + 'braille_dots_5678': (0x10028f0, u'\u28f0'), + 'braille_dots_568': (0x10028b0, u'\u28b0'), + 'braille_dots_57': (0x1002850, u'\u2850'), + 'braille_dots_578': (0x10028d0, u'\u28d0'), + 'braille_dots_58': (0x1002890, u'\u2890'), + 'braille_dots_6': (0x1002820, u'\u2820'), + 'braille_dots_67': (0x1002860, u'\u2860'), + 'braille_dots_678': (0x10028e0, u'\u28e0'), + 'braille_dots_68': (0x10028a0, u'\u28a0'), + 'braille_dots_7': (0x1002840, u'\u2840'), + 'braille_dots_78': (0x10028c0, u'\u28c0'), + 'braille_dots_8': (0x1002880, u'\u2880'), + 'breve': (0x01a2, u'\u02D8'), + 'brokenbar': (0x00a6, u'\u00A6'), + 'c': (0x0063, u'\u0063'), + 'cabovedot': (0x02e5, u'\u010B'), + 'cacute': (0x01e6, u'\u0107'), + 'careof': (0x0ab8, u'\u2105'), + 'caret': (0x0afc, u'\u2038'), + 'caron': (0x01b7, u'\u02C7'), + 'ccaron': (0x01e8, u'\u010D'), + 'ccedilla': (0x00e7, u'\u00E7'), + 'ccircumflex': (0x02e6, u'\u0109'), + 'cedilla': (0x00b8, u'\u00B8'), + 'cent': (0x00a2, u'\u00A2'), + 'checkerboard': (0x09e1, u'\u2592'), + 'checkmark': (0x0af3, u'\u2713'), + 'circle': (0x0bcf, u'\u25CB'), + 'club': (0x0aec, u'\u2663'), + 'colon': (0x003a, u'\u003A'), + 'comma': (0x002c, u'\u002C'), + 'containsas': (0x100220B, u'\u220B'), + 'copyright': (0x00a9, u'\u00A9'), + 'cr': (0x09e4, u'\u240D'), + 'crossinglines': (0x09ee, u'\u253C'), + 'cuberoot': (0x100221B, u'\u221B'), + 'currency': (0x00a4, u'\u00A4'), + 'd': (0x0064, u'\u0064'), + 'dabovedot': (0x1001e0b, u'\u1E0B'), + 'dagger': (0x0af1, u'\u2020'), + 'dcaron': (0x01ef, u'\u010F'), + 'dead_A': (0xfe81, None), + 'dead_E': (0xfe83, None), + 'dead_I': (0xfe85, None), + 'dead_O': (0xfe87, None), + 'dead_U': (0xfe89, None), + 'dead_a': (0xfe80, None), + 'dead_abovecomma': (0xfe64, u'\u0315'), + 'dead_abovedot': (0xfe56, u'\u0307'), + 'dead_abovereversedcomma': (0xfe65, u'\u0312'), + 'dead_abovering': (0xfe58, u'\u030A'), + 'dead_aboveverticalline': (0xfe91, u'\u030D'), + 'dead_acute': (0xfe51, u'\u0301'), + 'dead_belowbreve': (0xfe6b, u'\u032E'), + 'dead_belowcircumflex': (0xfe69, u'\u032D'), + 'dead_belowcomma': (0xfe6e, u'\u0326'), + 'dead_belowdiaeresis': (0xfe6c, u'\u0324'), + 'dead_belowdot': (0xfe60, u'\u0323'), + 'dead_belowmacron': (0xfe68, u'\u0331'), + 'dead_belowring': (0xfe67, u'\u0325'), + 'dead_belowtilde': (0xfe6a, u'\u0330'), + 'dead_belowverticalline': (0xfe92, u'\u0329'), + 'dead_breve': (0xfe55, u'\u0306'), + 'dead_capital_schwa': (0xfe8b, None), + 'dead_caron': (0xfe5a, u'\u030C'), + 'dead_cedilla': (0xfe5b, u'\u0327'), + 'dead_circumflex': (0xfe52, u'\u0302'), + 'dead_currency': (0xfe6f, None), + 'dead_diaeresis': (0xfe57, u'\u0308'), + 'dead_doubleacute': (0xfe59, u'\u030B'), + 'dead_doublegrave': (0xfe66, u'\u030F'), + 'dead_e': (0xfe82, None), + 'dead_grave': (0xfe50, u'\u0300'), + 'dead_greek': (0xfe8c, None), + 'dead_hook': (0xfe61, u'\u0309'), + 'dead_horn': (0xfe62, u'\u031B'), + 'dead_i': (0xfe84, None), + 'dead_invertedbreve': (0xfe6d, u'\u032F'), + 'dead_iota': (0xfe5d, u'\u0345'), + 'dead_longsolidusoverlay': (0xfe93, u'\u0338'), + 'dead_lowline': (0xfe90, u'\u0332'), + 'dead_macron': (0xfe54, u'\u0304'), + 'dead_o': (0xfe86, None), + 'dead_ogonek': (0xfe5c, u'\u0328'), + 'dead_semivoiced_sound': (0xfe5f, None), + 'dead_small_schwa': (0xfe8a, None), + 'dead_stroke': (0xfe63, u'\u0335'), + 'dead_tilde': (0xfe53, u'\u0303'), + 'dead_u': (0xfe88, None), + 'dead_voiced_sound': (0xfe5e, None), + 'degree': (0x00b0, u'\u00B0'), + 'diaeresis': (0x00a8, u'\u00A8'), + 'diamond': (0x0aed, u'\u2666'), + 'digitspace': (0x0aa5, u'\u2007'), + 'dintegral': (0x100222C, u'\u222C'), + 'division': (0x00f7, u'\u00F7'), + 'dollar': (0x0024, u'\u0024'), + 'doubbaselinedot': (0x0aaf, u'\u2025'), + 'doubleacute': (0x01bd, u'\u02DD'), + 'doubledagger': (0x0af2, u'\u2021'), + 'doublelowquotemark': (0x0afe, u'\u201E'), + 'downarrow': (0x08fe, u'\u2193'), + 'downstile': (0x0bc4, u'\u230A'), + 'downtack': (0x0bc2, u'\u22A4'), + 'dstroke': (0x01f0, u'\u0111'), + 'e': (0x0065, u'\u0065'), + 'eabovedot': (0x03ec, u'\u0117'), + 'eacute': (0x00e9, u'\u00E9'), + 'ebelowdot': (0x1001eb9, u'\u1EB9'), + 'ecaron': (0x01ec, u'\u011B'), + 'ecircumflex': (0x00ea, u'\u00EA'), + 'ecircumflexacute': (0x1001ebf, u'\u1EBF'), + 'ecircumflexbelowdot': (0x1001ec7, u'\u1EC7'), + 'ecircumflexgrave': (0x1001ec1, u'\u1EC1'), + 'ecircumflexhook': (0x1001ec3, u'\u1EC3'), + 'ecircumflextilde': (0x1001ec5, u'\u1EC5'), + 'ediaeresis': (0x00eb, u'\u00EB'), + 'egrave': (0x00e8, u'\u00E8'), + 'ehook': (0x1001ebb, u'\u1EBB'), + 'eightsubscript': (0x1002088, u'\u2088'), + 'eightsuperior': (0x1002078, u'\u2078'), + 'elementof': (0x1002208, u'\u2208'), + 'ellipsis': (0x0aae, u'\u2026'), + 'em3space': (0x0aa3, u'\u2004'), + 'em4space': (0x0aa4, u'\u2005'), + 'emacron': (0x03ba, u'\u0113'), + 'emdash': (0x0aa9, u'\u2014'), + 'emptyset': (0x1002205, u'\u2205'), + 'emspace': (0x0aa1, u'\u2003'), + 'endash': (0x0aaa, u'\u2013'), + 'eng': (0x03bf, u'\u014B'), + 'enspace': (0x0aa2, u'\u2002'), + 'eogonek': (0x01ea, u'\u0119'), + 'equal': (0x003d, u'\u003D'), + 'eth': (0x00f0, u'\u00F0'), + 'etilde': (0x1001ebd, u'\u1EBD'), + 'exclam': (0x0021, u'\u0021'), + 'exclamdown': (0x00a1, u'\u00A1'), + 'ezh': (0x1000292, u'\u0292'), + 'f': (0x0066, u'\u0066'), + 'fabovedot': (0x1001e1f, u'\u1E1F'), + 'femalesymbol': (0x0af8, u'\u2640'), + 'ff': (0x09e3, u'\u240C'), + 'figdash': (0x0abb, u'\u2012'), + 'fiveeighths': (0x0ac5, u'\u215D'), + 'fivesixths': (0x0ab7, u'\u215A'), + 'fivesubscript': (0x1002085, u'\u2085'), + 'fivesuperior': (0x1002075, u'\u2075'), + 'fourfifths': (0x0ab5, u'\u2158'), + 'foursubscript': (0x1002084, u'\u2084'), + 'foursuperior': (0x1002074, u'\u2074'), + 'fourthroot': (0x100221C, u'\u221C'), + 'function': (0x08f6, u'\u0192'), + 'g': (0x0067, u'\u0067'), + 'gabovedot': (0x02f5, u'\u0121'), + 'gbreve': (0x02bb, u'\u011F'), + 'gcaron': (0x10001e7, u'\u01E7'), + 'gcedilla': (0x03bb, u'\u0123'), + 'gcircumflex': (0x02f8, u'\u011D'), + 'grave': (0x0060, u'\u0060'), + 'greater': (0x003e, u'\u003E'), + 'greaterthanequal': (0x08be, u'\u2265'), + 'guillemotleft': (0x00ab, u'\u00AB'), + 'guillemotright': (0x00bb, u'\u00BB'), + 'h': (0x0068, u'\u0068'), + 'hairspace': (0x0aa8, u'\u200A'), + 'hcircumflex': (0x02b6, u'\u0125'), + 'heart': (0x0aee, u'\u2665'), + 'hebrew_aleph': (0x0ce0, u'\u05D0'), + 'hebrew_ayin': (0x0cf2, u'\u05E2'), + 'hebrew_bet': (0x0ce1, u'\u05D1'), + 'hebrew_chet': (0x0ce7, u'\u05D7'), + 'hebrew_dalet': (0x0ce3, u'\u05D3'), + 'hebrew_doublelowline': (0x0cdf, u'\u2017'), + 'hebrew_finalkaph': (0x0cea, u'\u05DA'), + 'hebrew_finalmem': (0x0ced, u'\u05DD'), + 'hebrew_finalnun': (0x0cef, u'\u05DF'), + 'hebrew_finalpe': (0x0cf3, u'\u05E3'), + 'hebrew_finalzade': (0x0cf5, u'\u05E5'), + 'hebrew_gimel': (0x0ce2, u'\u05D2'), + 'hebrew_he': (0x0ce4, u'\u05D4'), + 'hebrew_kaph': (0x0ceb, u'\u05DB'), + 'hebrew_lamed': (0x0cec, u'\u05DC'), + 'hebrew_mem': (0x0cee, u'\u05DE'), + 'hebrew_nun': (0x0cf0, u'\u05E0'), + 'hebrew_pe': (0x0cf4, u'\u05E4'), + 'hebrew_qoph': (0x0cf7, u'\u05E7'), + 'hebrew_resh': (0x0cf8, u'\u05E8'), + 'hebrew_samech': (0x0cf1, u'\u05E1'), + 'hebrew_shin': (0x0cf9, u'\u05E9'), + 'hebrew_taw': (0x0cfa, u'\u05EA'), + 'hebrew_tet': (0x0ce8, u'\u05D8'), + 'hebrew_waw': (0x0ce5, u'\u05D5'), + 'hebrew_yod': (0x0ce9, u'\u05D9'), + 'hebrew_zade': (0x0cf6, u'\u05E6'), + 'hebrew_zain': (0x0ce6, u'\u05D6'), + 'horizlinescan1': (0x09ef, u'\u23BA'), + 'horizlinescan3': (0x09f0, u'\u23BB'), + 'horizlinescan5': (0x09f1, u'\u2500'), + 'horizlinescan7': (0x09f2, u'\u23BC'), + 'horizlinescan9': (0x09f3, u'\u23BD'), + 'hstroke': (0x02b1, u'\u0127'), + 'ht': (0x09e2, u'\u2409'), + 'hyphen': (0x00ad, u'\u00AD'), + 'i': (0x0069, u'\u0069'), + 'iacute': (0x00ed, u'\u00ED'), + 'ibelowdot': (0x1001ecb, u'\u1ECB'), + 'ibreve': (0x100012d, u'\u012D'), + 'icircumflex': (0x00ee, u'\u00EE'), + 'identical': (0x08cf, u'\u2261'), + 'idiaeresis': (0x00ef, u'\u00EF'), + 'idotless': (0x02b9, u'\u0131'), + 'ifonlyif': (0x08cd, u'\u21D4'), + 'igrave': (0x00ec, u'\u00EC'), + 'ihook': (0x1001ec9, u'\u1EC9'), + 'imacron': (0x03ef, u'\u012B'), + 'implies': (0x08ce, u'\u21D2'), + 'includedin': (0x08da, u'\u2282'), + 'includes': (0x08db, u'\u2283'), + 'infinity': (0x08c2, u'\u221E'), + 'integral': (0x08bf, u'\u222B'), + 'intersection': (0x08dc, u'\u2229'), + 'iogonek': (0x03e7, u'\u012F'), + 'itilde': (0x03b5, u'\u0129'), + 'j': (0x006a, u'\u006A'), + 'jcircumflex': (0x02bc, u'\u0135'), + 'jot': (0x0bca, u'\u2218'), + 'k': (0x006b, u'\u006B'), + 'kana_A': (0x04b1, u'\u30A2'), + 'kana_CHI': (0x04c1, u'\u30C1'), + 'kana_E': (0x04b4, u'\u30A8'), + 'kana_FU': (0x04cc, u'\u30D5'), + 'kana_HA': (0x04ca, u'\u30CF'), + 'kana_HE': (0x04cd, u'\u30D8'), + 'kana_HI': (0x04cb, u'\u30D2'), + 'kana_HO': (0x04ce, u'\u30DB'), + 'kana_I': (0x04b2, u'\u30A4'), + 'kana_KA': (0x04b6, u'\u30AB'), + 'kana_KE': (0x04b9, u'\u30B1'), + 'kana_KI': (0x04b7, u'\u30AD'), + 'kana_KO': (0x04ba, u'\u30B3'), + 'kana_KU': (0x04b8, u'\u30AF'), + 'kana_MA': (0x04cf, u'\u30DE'), + 'kana_ME': (0x04d2, u'\u30E1'), + 'kana_MI': (0x04d0, u'\u30DF'), + 'kana_MO': (0x04d3, u'\u30E2'), + 'kana_MU': (0x04d1, u'\u30E0'), + 'kana_N': (0x04dd, u'\u30F3'), + 'kana_NA': (0x04c5, u'\u30CA'), + 'kana_NE': (0x04c8, u'\u30CD'), + 'kana_NI': (0x04c6, u'\u30CB'), + 'kana_NO': (0x04c9, u'\u30CE'), + 'kana_NU': (0x04c7, u'\u30CC'), + 'kana_O': (0x04b5, u'\u30AA'), + 'kana_RA': (0x04d7, u'\u30E9'), + 'kana_RE': (0x04da, u'\u30EC'), + 'kana_RI': (0x04d8, u'\u30EA'), + 'kana_RO': (0x04db, u'\u30ED'), + 'kana_RU': (0x04d9, u'\u30EB'), + 'kana_SA': (0x04bb, u'\u30B5'), + 'kana_SE': (0x04be, u'\u30BB'), + 'kana_SHI': (0x04bc, u'\u30B7'), + 'kana_SO': (0x04bf, u'\u30BD'), + 'kana_SU': (0x04bd, u'\u30B9'), + 'kana_TA': (0x04c0, u'\u30BF'), + 'kana_TE': (0x04c3, u'\u30C6'), + 'kana_TO': (0x04c4, u'\u30C8'), + 'kana_TSU': (0x04c2, u'\u30C4'), + 'kana_U': (0x04b3, u'\u30A6'), + 'kana_WA': (0x04dc, u'\u30EF'), + 'kana_WO': (0x04a6, u'\u30F2'), + 'kana_YA': (0x04d4, u'\u30E4'), + 'kana_YO': (0x04d6, u'\u30E8'), + 'kana_YU': (0x04d5, u'\u30E6'), + 'kana_a': (0x04a7, u'\u30A1'), + 'kana_closingbracket': (0x04a3, u'\u300D'), + 'kana_comma': (0x04a4, u'\u3001'), + 'kana_conjunctive': (0x04a5, u'\u30FB'), + 'kana_e': (0x04aa, u'\u30A7'), + 'kana_fullstop': (0x04a1, u'\u3002'), + 'kana_i': (0x04a8, u'\u30A3'), + 'kana_o': (0x04ab, u'\u30A9'), + 'kana_openingbracket': (0x04a2, u'\u300C'), + 'kana_tsu': (0x04af, u'\u30C3'), + 'kana_u': (0x04a9, u'\u30A5'), + 'kana_ya': (0x04ac, u'\u30E3'), + 'kana_yo': (0x04ae, u'\u30E7'), + 'kana_yu': (0x04ad, u'\u30E5'), + 'kcedilla': (0x03f3, u'\u0137'), + 'kra': (0x03a2, u'\u0138'), + 'l': (0x006c, u'\u006C'), + 'lacute': (0x01e5, u'\u013A'), + 'latincross': (0x0ad9, u'\u271D'), + 'lbelowdot': (0x1001e37, u'\u1E37'), + 'lcaron': (0x01b5, u'\u013E'), + 'lcedilla': (0x03b6, u'\u013C'), + 'leftarrow': (0x08fb, u'\u2190'), + 'leftdoublequotemark': (0x0ad2, u'\u201C'), + 'leftmiddlecurlybrace': (0x08af, u'\u23A8'), + 'leftradical': (0x08a1, u'\u23B7'), + 'leftsinglequotemark': (0x0ad0, u'\u2018'), + 'leftt': (0x09f4, u'\u251C'), + 'lefttack': (0x0bdc, u'\u22A3'), + 'less': (0x003c, u'\u003C'), + 'lessthanequal': (0x08bc, u'\u2264'), + 'lf': (0x09e5, u'\u240A'), + 'logicaland': (0x08de, u'\u2227'), + 'logicalor': (0x08df, u'\u2228'), + 'lowleftcorner': (0x09ed, u'\u2514'), + 'lowrightcorner': (0x09ea, u'\u2518'), + 'lstroke': (0x01b3, u'\u0142'), + 'm': (0x006d, u'\u006D'), + 'mabovedot': (0x1001e41, u'\u1E41'), + 'macron': (0x00af, u'\u00AF'), + 'malesymbol': (0x0af7, u'\u2642'), + 'maltesecross': (0x0af0, u'\u2720'), + 'masculine': (0x00ba, u'\u00BA'), + 'minus': (0x002d, u'\u002D'), + 'minutes': (0x0ad6, u'\u2032'), + 'mu': (0x00b5, u'\u00B5'), + 'multiply': (0x00d7, u'\u00D7'), + 'musicalflat': (0x0af6, u'\u266D'), + 'musicalsharp': (0x0af5, u'\u266F'), + 'n': (0x006e, u'\u006E'), + 'nabla': (0x08c5, u'\u2207'), + 'nacute': (0x01f1, u'\u0144'), + 'ncaron': (0x01f2, u'\u0148'), + 'ncedilla': (0x03f1, u'\u0146'), + 'ninesubscript': (0x1002089, u'\u2089'), + 'ninesuperior': (0x1002079, u'\u2079'), + 'nl': (0x09e8, u'\u2424'), + 'nobreakspace': (0x00a0, u'\u00A0'), + 'notapproxeq': (0x1002247, u'\u2247'), + 'notelementof': (0x1002209, u'\u2209'), + 'notequal': (0x08bd, u'\u2260'), + 'notidentical': (0x1002262, u'\u2262'), + 'notsign': (0x00ac, u'\u00AC'), + 'ntilde': (0x00f1, u'\u00F1'), + 'numbersign': (0x0023, u'\u0023'), + 'numerosign': (0x06b0, u'\u2116'), + 'o': (0x006f, u'\u006F'), + 'oacute': (0x00f3, u'\u00F3'), + 'obarred': (0x1000275, u'\u0275'), + 'obelowdot': (0x1001ecd, u'\u1ECD'), + 'ocaron': (0x10001d2, u'\u01D2'), + 'ocircumflex': (0x00f4, u'\u00F4'), + 'ocircumflexacute': (0x1001ed1, u'\u1ED1'), + 'ocircumflexbelowdot': (0x1001ed9, u'\u1ED9'), + 'ocircumflexgrave': (0x1001ed3, u'\u1ED3'), + 'ocircumflexhook': (0x1001ed5, u'\u1ED5'), + 'ocircumflextilde': (0x1001ed7, u'\u1ED7'), + 'odiaeresis': (0x00f6, u'\u00F6'), + 'odoubleacute': (0x01f5, u'\u0151'), + 'oe': (0x13bd, u'\u0153'), + 'ogonek': (0x01b2, u'\u02DB'), + 'ograve': (0x00f2, u'\u00F2'), + 'ohook': (0x1001ecf, u'\u1ECF'), + 'ohorn': (0x10001a1, u'\u01A1'), + 'ohornacute': (0x1001edb, u'\u1EDB'), + 'ohornbelowdot': (0x1001ee3, u'\u1EE3'), + 'ohorngrave': (0x1001edd, u'\u1EDD'), + 'ohornhook': (0x1001edf, u'\u1EDF'), + 'ohorntilde': (0x1001ee1, u'\u1EE1'), + 'omacron': (0x03f2, u'\u014D'), + 'oneeighth': (0x0ac3, u'\u215B'), + 'onefifth': (0x0ab2, u'\u2155'), + 'onehalf': (0x00bd, u'\u00BD'), + 'onequarter': (0x00bc, u'\u00BC'), + 'onesixth': (0x0ab6, u'\u2159'), + 'onesubscript': (0x1002081, u'\u2081'), + 'onesuperior': (0x00b9, u'\u00B9'), + 'onethird': (0x0ab0, u'\u2153'), + 'ooblique': (0x00f8, u'\u00F8'), + 'ordfeminine': (0x00aa, u'\u00AA'), + 'oslash': (0x00f8, u'\u00F8'), + 'otilde': (0x00f5, u'\u00F5'), + 'overline': (0x047e, u'\u203E'), + 'p': (0x0070, u'\u0070'), + 'pabovedot': (0x1001e57, u'\u1E57'), + 'paragraph': (0x00b6, u'\u00B6'), + 'parenleft': (0x0028, u'\u0028'), + 'parenright': (0x0029, u'\u0029'), + 'partdifferential': (0x1002202, u'\u2202'), + 'partialderivative': (0x08ef, u'\u2202'), + 'percent': (0x0025, u'\u0025'), + 'period': (0x002e, u'\u002E'), + 'periodcentered': (0x00b7, u'\u00B7'), + 'permille': (0x0ad5, u'\u2030'), + 'phonographcopyright': (0x0afb, u'\u2117'), + 'plus': (0x002b, u'\u002B'), + 'plusminus': (0x00b1, u'\u00B1'), + 'prescription': (0x0ad4, u'\u211E'), + 'prolongedsound': (0x04b0, u'\u30FC'), + 'punctspace': (0x0aa6, u'\u2008'), + 'q': (0x0071, u'\u0071'), + 'quad': (0x0bcc, u'\u2395'), + 'question': (0x003f, u'\u003F'), + 'questiondown': (0x00bf, u'\u00BF'), + 'quotedbl': (0x0022, u'\u0022'), + 'r': (0x0072, u'\u0072'), + 'racute': (0x01e0, u'\u0155'), + 'radical': (0x08d6, u'\u221A'), + 'rcaron': (0x01f8, u'\u0159'), + 'rcedilla': (0x03b3, u'\u0157'), + 'registered': (0x00ae, u'\u00AE'), + 'rightarrow': (0x08fd, u'\u2192'), + 'rightdoublequotemark': (0x0ad3, u'\u201D'), + 'rightmiddlecurlybrace': (0x08b0, u'\u23AC'), + 'rightsinglequotemark': (0x0ad1, u'\u2019'), + 'rightt': (0x09f5, u'\u2524'), + 'righttack': (0x0bfc, u'\u22A2'), + 's': (0x0073, u'\u0073'), + 'sabovedot': (0x1001e61, u'\u1E61'), + 'sacute': (0x01b6, u'\u015B'), + 'scaron': (0x01b9, u'\u0161'), + 'scedilla': (0x01ba, u'\u015F'), + 'schwa': (0x1000259, u'\u0259'), + 'scircumflex': (0x02fe, u'\u015D'), + 'seconds': (0x0ad7, u'\u2033'), + 'section': (0x00a7, u'\u00A7'), + 'semicolon': (0x003b, u'\u003B'), + 'semivoicedsound': (0x04df, u'\u309C'), + 'seveneighths': (0x0ac6, u'\u215E'), + 'sevensubscript': (0x1002087, u'\u2087'), + 'sevensuperior': (0x1002077, u'\u2077'), + 'similarequal': (0x08c9, u'\u2243'), + 'singlelowquotemark': (0x0afd, u'\u201A'), + 'sixsubscript': (0x1002086, u'\u2086'), + 'sixsuperior': (0x1002076, u'\u2076'), + 'slash': (0x002f, u'\u002F'), + 'soliddiamond': (0x09e0, u'\u25C6'), + 'space': (0x0020, u'\u0020'), + 'squareroot': (0x100221A, u'\u221A'), + 'ssharp': (0x00df, u'\u00DF'), + 'sterling': (0x00a3, u'\u00A3'), + 'stricteq': (0x1002263, u'\u2263'), + 't': (0x0074, u'\u0074'), + 'tabovedot': (0x1001e6b, u'\u1E6B'), + 'tcaron': (0x01bb, u'\u0165'), + 'tcedilla': (0x01fe, u'\u0163'), + 'telephone': (0x0af9, u'\u260E'), + 'telephonerecorder': (0x0afa, u'\u2315'), + 'therefore': (0x08c0, u'\u2234'), + 'thinspace': (0x0aa7, u'\u2009'), + 'thorn': (0x00fe, u'\u00FE'), + 'threeeighths': (0x0ac4, u'\u215C'), + 'threefifths': (0x0ab4, u'\u2157'), + 'threequarters': (0x00be, u'\u00BE'), + 'threesubscript': (0x1002083, u'\u2083'), + 'threesuperior': (0x00b3, u'\u00B3'), + 'tintegral': (0x100222D, u'\u222D'), + 'topintegral': (0x08a4, u'\u2320'), + 'topleftparens': (0x08ab, u'\u239B'), + 'topleftsqbracket': (0x08a7, u'\u23A1'), + 'toprightparens': (0x08ad, u'\u239E'), + 'toprightsqbracket': (0x08a9, u'\u23A4'), + 'topt': (0x09f7, u'\u252C'), + 'trademark': (0x0ac9, u'\u2122'), + 'tslash': (0x03bc, u'\u0167'), + 'twofifths': (0x0ab3, u'\u2156'), + 'twosubscript': (0x1002082, u'\u2082'), + 'twosuperior': (0x00b2, u'\u00B2'), + 'twothirds': (0x0ab1, u'\u2154'), + 'u': (0x0075, u'\u0075'), + 'uacute': (0x00fa, u'\u00FA'), + 'ubelowdot': (0x1001ee5, u'\u1EE5'), + 'ubreve': (0x02fd, u'\u016D'), + 'ucircumflex': (0x00fb, u'\u00FB'), + 'udiaeresis': (0x00fc, u'\u00FC'), + 'udoubleacute': (0x01fb, u'\u0171'), + 'ugrave': (0x00f9, u'\u00F9'), + 'uhook': (0x1001ee7, u'\u1EE7'), + 'uhorn': (0x10001b0, u'\u01B0'), + 'uhornacute': (0x1001ee9, u'\u1EE9'), + 'uhornbelowdot': (0x1001ef1, u'\u1EF1'), + 'uhorngrave': (0x1001eeb, u'\u1EEB'), + 'uhornhook': (0x1001eed, u'\u1EED'), + 'uhorntilde': (0x1001eef, u'\u1EEF'), + 'umacron': (0x03fe, u'\u016B'), + 'underscore': (0x005f, u'\u005F'), + 'union': (0x08dd, u'\u222A'), + 'uogonek': (0x03f9, u'\u0173'), + 'uparrow': (0x08fc, u'\u2191'), + 'upleftcorner': (0x09ec, u'\u250C'), + 'uprightcorner': (0x09eb, u'\u2510'), + 'upstile': (0x0bd3, u'\u2308'), + 'uptack': (0x0bce, u'\u22A5'), + 'uring': (0x01f9, u'\u016F'), + 'utilde': (0x03fd, u'\u0169'), + 'v': (0x0076, u'\u0076'), + 'variation': (0x08c1, u'\u221D'), + 'vertbar': (0x09f8, u'\u2502'), + 'voicedsound': (0x04de, u'\u309B'), + 'vt': (0x09e9, u'\u240B'), + 'w': (0x0077, u'\u0077'), + 'wacute': (0x1001e83, u'\u1E83'), + 'wcircumflex': (0x1000175, u'\u0175'), + 'wdiaeresis': (0x1001e85, u'\u1E85'), + 'wgrave': (0x1001e81, u'\u1E81'), + 'x': (0x0078, u'\u0078'), + 'xabovedot': (0x1001e8b, u'\u1E8B'), + 'y': (0x0079, u'\u0079'), + 'yacute': (0x00fd, u'\u00FD'), + 'ybelowdot': (0x1001ef5, u'\u1EF5'), + 'ycircumflex': (0x1000177, u'\u0177'), + 'ydiaeresis': (0x00ff, u'\u00FF'), + 'yen': (0x00a5, u'\u00A5'), + 'ygrave': (0x1001ef3, u'\u1EF3'), + 'yhook': (0x1001ef7, u'\u1EF7'), + 'ytilde': (0x1001ef9, u'\u1EF9'), + 'z': (0x007a, u'\u007A'), + 'zabovedot': (0x01bf, u'\u017C'), + 'zacute': (0x01bc, u'\u017A'), + 'zcaron': (0x01be, u'\u017E'), + 'zerosubscript': (0x1002080, u'\u2080'), + 'zerosuperior': (0x1002070, u'\u2070'), + 'zstroke': (0x10001b6, u'\u01B6')} + +DEAD_KEYS = { + u'\u0307': u'\u02D9', + u'\u030A': u'\u02DA', + u'\u0301': u'\u00B4', + u'\u0306': u'\u02D8', + u'\u030C': u'\u02C7', + u'\u0327': u'\u00B8', + u'\u0302': u'\u005E', + u'\u0308': u'\u00A8', + u'\u030B': u'\u02DD', + u'\u0300': u'\u0060', + u'\u0345': u'\u037A', + u'\u0332': u'\u005F', + u'\u0304': u'\u00AF', + u'\u0328': u'\u02DB', + u'\u0303': u'\u007E'} + +KEYPAD_KEYS = { + 'KP_0': 0xffb0, + 'KP_1': 0xffb1, + 'KP_2': 0xffb2, + 'KP_3': 0xffb3, + 'KP_4': 0xffb4, + 'KP_5': 0xffb5, + 'KP_6': 0xffb6, + 'KP_7': 0xffb7, + 'KP_8': 0xffb8, + 'KP_9': 0xffb9, + 'KP_Add': 0xffab, + 'KP_Begin': 0xff9d, + 'KP_Decimal': 0xffae, + 'KP_Delete': 0xff9f, + 'KP_Divide': 0xffaf, + 'KP_Down': 0xff99, + 'KP_End': 0xff9c, + 'KP_Enter': 0xff8d, + 'KP_Equal': 0xffbd, + 'KP_F1': 0xff91, + 'KP_F2': 0xff92, + 'KP_F3': 0xff93, + 'KP_F4': 0xff94, + 'KP_Home': 0xff95, + 'KP_Insert': 0xff9e, + 'KP_Left': 0xff96, + 'KP_Multiply': 0xffaa, + 'KP_Next': 0xff9b, + 'KP_Page_Down': 0xff9b, + 'KP_Page_Up': 0xff9a, + 'KP_Prior': 0xff9a, + 'KP_Right': 0xff98, + 'KP_Separator': 0xffac, + 'KP_Space': 0xff80, + 'KP_Subtract': 0xffad, + 'KP_Tab': 0xff89, + 'KP_Up': 0xff97} + +CHARS = { + codepoint: name + for name, (keysym, codepoint) in SYMBOLS.items() + if codepoint} + +KEYSYMS = { + keysym: name + for name, (keysym, codepoint) in SYMBOLS.items() + if codepoint} diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__init__.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__init__.py new file mode 100644 index 0000000..34a1921 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__init__.py @@ -0,0 +1,249 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The module containing keyboard classes. + +See the documentation for more information. +""" + +# pylint: disable=C0103 +# KeyCode, Key, Controller and Listener are not constants + +import itertools + +from pynput._util import backend, Events + + +backend = backend(__name__) +KeyCode = backend.KeyCode +Key = backend.Key +Controller = backend.Controller +Listener = backend.Listener +del backend + + +# pylint: disable=C0326; it is easier to read column aligned keys +#: The keys used as modifiers; the first value in each tuple is the +#: base modifier to use for subsequent modifiers. +_MODIFIER_KEYS = ( + (Key.alt_gr, (Key.alt_gr.value,)), + (Key.alt, (Key.alt.value, Key.alt_l.value, Key.alt_r.value)), + (Key.cmd, (Key.cmd.value, Key.cmd_l.value, Key.cmd_r.value)), + (Key.ctrl, (Key.ctrl.value, Key.ctrl_l.value, Key.ctrl_r.value)), + (Key.shift, (Key.shift.value, Key.shift_l.value, Key.shift_r.value))) + +#: Normalised modifiers as a mapping from virtual key code to basic modifier. +_NORMAL_MODIFIERS = { + value: key + for combination in _MODIFIER_KEYS + for key, value in zip( + itertools.cycle((combination[0],)), + combination[1])} + +#: Control codes to transform into key codes when typing +_CONTROL_CODES = { + '\n': Key.enter, + '\r': Key.enter, + '\t': Key.tab} +# pylint: enable=C0326 + + +class Events(Events): + """A keyboard event listener supporting synchronous iteration over the + events. + + Possible events are: + + :class:`Events.Press` + A key was pressed. + + :class:`Events.Release` + A key was released. + """ + _Listener = Listener + + class Press(Events.Event): + """A key press event. + """ + def __init__(self, key, injected): + #: The key. + self.key = key + + #: Whether this event is synthetic. + self.injected = injected + + class Release(Events.Event): + """A key release event. + """ + def __init__(self, key, injected): + #: The key. + self.key = key + + #: Whether this event is synthetic. + self.injected = injected + + def __init__(self): + super(Events, self).__init__( + on_press=self.Press, + on_release=self.Release) + + +class HotKey(object): + """A combination of keys acting as a hotkey. + + This class acts as a container of hotkey state for a keyboard listener. + + :param set keys: The collection of keys that must be pressed for this + hotkey to activate. Please note that a common limitation of the + hardware is that at most three simultaneously pressed keys are + supported, so using more keys may not work. + + :param callable on_activate: The activation callback. + """ + def __init__(self, keys, on_activate): + self._state = set() + self._keys = set(keys) + self._on_activate = on_activate + + @staticmethod + def parse(keys): + """Parses a key combination string. + + Key combination strings are sequences of key identifiers separated by + ``'+'``. Key identifiers are either single characters representing a + keyboard key, such as ``'a'``, or special key names identified by names + enclosed by brackets, such as ``''``. + + Keyboard keys are case-insensitive. + + :raises ValueError: if a part of the keys string is invalid, or if it + contains multiple equal parts + """ + def parts(): + start = 0 + for i, c in enumerate(keys): + if c == '+' and i != start: + yield keys[start:i] + start = i + 1 + if start == len(keys): + raise ValueError(keys) + else: + yield keys[start:] + + def parse(s): + if len(s) == 1: + return KeyCode.from_char(s.lower()) + elif len(s) > 2 and (s[0], s[-1]) == ('<', '>'): + p = s[1:-1] + try: + # We want to represent modifiers as Key instances, and all + # other keys as KeyCodes + key = Key[p.lower()] + if key in _NORMAL_MODIFIERS.values(): + return key + else: + return KeyCode.from_vk(key.value.vk) + except KeyError: + try: + return KeyCode.from_vk(int(p)) + except ValueError: + raise ValueError(s) + else: + raise ValueError(s) + + # Split the string and parse the individual parts + raw_parts = list(parts()) + parsed_parts = [ + parse(s) + for s in raw_parts] + + # Ensure no duplicate parts + if len(parsed_parts) != len(set(parsed_parts)): + raise ValueError(keys) + else: + return parsed_parts + + def press(self, key): + """Updates the hotkey state for a pressed key. + + If the key is not currently pressed, but is the last key for the full + combination, the activation callback will be invoked. + + Please note that the callback will only be invoked once. + + :param key: The key being pressed. + :type key: Key or KeyCode + """ + if key in self._keys and key not in self._state: + self._state.add(key) + if self._state == self._keys: + self._on_activate() + + def release(self, key): + """Updates the hotkey state for a released key. + + :param key: The key being released. + :type key: Key or KeyCode + """ + if key in self._state: + self._state.remove(key) + + +class GlobalHotKeys(Listener): + """A keyboard listener supporting a number of global hotkeys. + + This is a convenience wrapper to simplify registering a number of global + hotkeys. + + :param dict hotkeys: A mapping from hotkey description to hotkey action. + Keys are strings passed to :meth:`HotKey.parse`. + + :raises ValueError: if any hotkey description is invalid + """ + def __init__(self, hotkeys, *args, **kwargs): + self._hotkeys = [ + HotKey(HotKey.parse(key), value) + for key, value in hotkeys.items()] + super(GlobalHotKeys, self).__init__( + on_press=self._on_press, + on_release=self._on_release, + *args, + **kwargs) + + def _on_press(self, key, injected): + """The press callback. + + This is automatically registered upon creation. + + :param key: The key provided by the base class. + :param injected: Whether the event was injected. + """ + if not injected: + for hotkey in self._hotkeys: + hotkey.press(self.canonical(key)) + + def _on_release(self, key, injected): + """The release callback. + + This is automatically registered upon creation. + + :param key: The key provided by the base class. + :param injected: Whether the event was injected. + """ + if not injected: + for hotkey in self._hotkeys: + hotkey.release(self.canonical(key)) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34af5f0eecdba2d21066b61d25e88fc2855ba8d7 GIT binary patch literal 10172 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 TdZ}LqKAxrchx(m|>%9LBF;@}B literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_base.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..184f2193a10c404fcf068cd464dc5cea27456adb GIT binary patch literal 28744 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_darwin.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_darwin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3f2906cb1a26d48304502a30ff16389289d159b GIT binary patch literal 13381 zcmd5?dr(~0dB1me@4nb&-wz%_D*+O_AV5g6kSxnVfNX37jzN~SjlEuRuf)PW$h{Xy zkfkOWPXn%8ph>FL#Hnz{)8N`ooasyLOdESL&Ga$TvRXT=?l$zT^6yn|LXL>e)l|n=ey^g$M>D{o$sHmRx<@*;-h~W%^aYpf5(Ip^o7XA1Wi%b zD3%ISEX``-beM*xHm*r%!`g%{tV=LqCZP}O6Na!MVGJ7+rm!ht4x1Ad;fjPMY)M$d z)bEAcF+y0Hl+n$A*gtC8i>q3DN~fH}HH;DK9=% zWD7xh0O{qb0UIu2l-OH3ITk)Jr3w0`L+0U8E-=nbolix1HV{ip#JL2Q6r*A+l?+@+ z@qthxIx;vEYBk@*iUUEnRNehp?Tq;|yjAHHk_idy7s)U%ROtDE zp`j^3HLO4g@hP&>)-{jn>t zWRR8&L+AQW4L&t=7gi<(X(n<$DsXr0kh*I?;y~g=Qi;R}M0!3Yj&eL{(b8O>_Uv=N#{qzSb`J8XksFAIhJHomj@;j=Q%!7Xir3#JTGExHY!FB650_N zfmf)Zu;i$X5M*7WI0{4t71qEq)v}tfj$>Hu%hX#1cv#QsUZ%nZnDmTffX?fN&V!FK zMPfoE!LhOEz=*;St1$4ZfZs+7kZY8NN>gJH+aA*N1(Z{o7@gL@&I z+BJ+rhHr^n8i%phj>H8?b7@@Ck6(`R7X?8J7-s;>=}_NBIX?0nnAlsKA79%?<<(I&)1?!ZKJWITG26QCeDF)6mew-Bk( z2BX8n7`9GKNfi;&1oGX}u0lVzZpnNRnj!24GE1%7DSOSFu<*6{uVp&2w$2szs;%=K zFT_@jof`n5Mhe0T5Nmp?z>Hq|>^zRuTL&jEIYogfzqIL|m05jJcIq@tLMCQM_LC zDml<99kypnEx%G$d=_d|D>*yVs#VI0&qA#_C1;0P0i~??EY#YoK*O%*pm4UeLdkQfC^B8H+;&ch+&cLBMJOXV(# z(7V5Z0Q&|$1PMtCI!V%vj7E7PwIt_*3WLX)DH#f?nTORv@yJNhf;^G5(YVN?EC3Og zV0m0Qz)$4kJZd3{5m4*$xL|mqk+g9x8PrQUfs0>|OzKcbhC=5_W~HAvR&JsmI&Cs8 z3MdRfVnX0i3rPA18RO|nRjiTp7?cSQ!NdTG=A|l~3uoug-myge4$n2;k}q>=Y1f;_U+=zo=-q?a z`kt)4H*a@txJ+L6Cr-*!yY$$%`tG?Xt83FsdE4`LccvqAd?~upu`<1(rM(Z&o!-<_ zCV$@I%v-F#bb7AsU)rBJmv!#@SWDT1`IZCs7>%`U(@eR%B}MzOsDgnaI~Fx9HDzL1 z=YFiUKYyV0p2KKuhgU*Ta4DFX$~v2{s4?H#cF$K~J-EqOO&#lXl%;a+c&6b-@Op5y zy6v{589wzjZKmf&-}S!lR<7uNXnNDMsim!l*7cO#J7?uvq5pzL$ryoG7XCWdq0eP8P*Jx|?t2+O>g>rai`|dFIdm00CY(q=w9qT0KY-PMM z6RbZ1KQ$=YWa9;pp2ZyqryWx@hKdD^p=g>g^SKCp8H7gVVfb8xu?#}1@-US_=v0Kc z41!S+6`zZ+ltJiK9@a7lgNms9T!gI*!l?4FmqD0Rgrf|?tRkFc5EUxIRR&>E5$-Yw ztBUZHK~$;;ZyAJ5Mfl1f>?*=v2H{W!P6;WLV;ZhMbWe{!^QCkM#Q4zb!AiOG~ zt_;GbB6gQS_*F!p45CU!>?wn&RuOy4AZk=ZeHlcpifAZ<*rg&G%OL7h#J)0!-6~># z8AL!uG?hW@Q4zs1h`lNzR0dJ6BAUw}8dO9}8APLsI8X+$PertrLF`u%ZJFN0`O zc^oW*2(qEKo0Yw5xT6fJMdfp-4B~)_I1GsKqHa-Q+(RnjXcYMhcNaql9Na#k<1{u zjHCg{5hT+{t{_2Ge)kfR7m-AfoJYbU;gBSdTtt#W5<`OBe)p?LaN~FPOGpNhJdFe` zZg&MFUqdp5L`0HC(uw2*l7m3*(}5t(AI4-mlHUe05bWW*;mP+P=|w`eEx23ZvAV>- z{x=erAH1Z;)J0x0orlA@04H=#GL1wh1T?yg^VmHS1KVV*fDfL>4wUq`UxqyS30zn% z&VkWO2WFV0q~*ZO#lQ)L;~_4LNSX@=;nxAbL-0Ecza#K_2!2Q5*9pI4lJ>&Eb|eRp zbRao|#WNFG9R6iFu%tkKaf=|)otcyF8oOPOf`tP2s+1OtgqPDl(NyErQHIIxm| zZ0(`hg$NIuee%UxF?wFoOiqw}pJW?&F7jmWx#4q9_u_W(oMb1~h{!}dIu)6SP6}KJ zr2outujG&+ms0Ub*n%b|p)WjJ*bEJx8R&`h44xg>h9r%3J%Bv(v}7yc2w$=l_4G5n z&-M+T8ImdsP2;&svDBnc(y#&8;!0*2kVFfeeam}#pXlu#mMY{@Zj6HgeH{8|%WfA} z1z9t%K}6UEr>K{yJ7&j1+k9K5A!pt_+nu+#76#`BGd(%Wp4r}QDXV)SG9Sqd=d62Y zPv`BvYqllZvMy(DobB6|`rKU-@WE<&ib2I26O%st2&RGvD(s=^Pj>T@2)j( zFzXGjh91dzPtFeJJ+*6|rmUxFHFzTDd1Q7V@9?iV8nTXtW2Ex<1u!v?Nb%hR_&<-q_ zyTP;$Hv@5wA1N3a2`^ZRvLO>!?04vE6ezCi^Frtb(jGe;rR6^BYixSo7`pB6$oUV?>0Xu3@+0_tO2C6KrZ;W@ zDQC1jLd|GJwU(%URT_Ji5>=yYkJ=xXXkL@1lND)t%&5Go_#A_t+aA(dF!7<;Xj@2Y z6eFLqL4#XA@>fhxQT5b8N}w-mXzCnA!`~EjMSG6AOb0asB}0oHi5ruR0FWmEh@bpC ze83EyrvHGxM$^<)qYkS7srE9>{~3UY*bZtWO>4VEkIN$=+nes2PN1>w$^?IMx^e4x zz!ef3=UPwTy-Hj-*{Z_+1NaGeKl7hBMz`t@t?YTDD_ei)*8+CwH!PKO(7@yNh&Ll~ zA;B3hF_-X8j#y0izl4mSPM#uKF!4)9#Xd%=5>`cy*xPEHic6;=66H%lm7fZEp+j*B{FI4=uTFx_(^s*HvrwC$jb@^6p(3@y5*c znUzs6X*oJK8Ljo$Ct9fe39`6{UIJPT0tq zdZ-0zfgaJus1eQcZSrK>$?!jhhShBWR*-vJ79_`%Hg74q04wfWnyUwO)QEP5o}t24 z&NNoL1yG1`HpmZ@$=_QhzhQ@b7x2M-@3z2UerQ`JBuPFRYPSW>2YB3IZwn;9V_PO9 zNj~n%w*{^S_}~_NTOj$kt=<;6nwTYAH>WA+hutKm0ZkFWi%IY&zzfN}a~jYW^+Pan zbfI4_Qy|EV%57|kcwyibXxZL)1qjg`s$MD49I(98bPTS+@J$ zxnuxP6%lo|43W|SP}DLgGm!PrLF&+$sG>?MDl<^l z`X$KlxR&{UM4}Ffq>J#A$)Hvi^M(=G2SDy*{64jh{{<4$s%tFsd0IKzP5g@=W0Kg)UA!T?VfLsF6*-P(EIk5JAsBp-FK{?Q~-=%KV3Iddm1tC zelhbtxfZ@^?9yq!r8%OW~8kg%mMp{>9*P$<~)7^~lsC`8kG z)~L)l@}>Aqt}@?LGCPybGHowG?bJe$IjXM!ZgY!jqyc;cP%6#n&%x}!`n{sG`8+-f zGH4oz(nxJizH;YfBWlIq7xe5HEv z?!F(rfM9DV3>82OaXo@&4L#l4-PiRLT9t-))IpLh(m&YKce=0lnaJs2v@jpV_m2Lf*$UoiJeG6*1Y!8El2C^+WNKHBiY&`?{K-=6N{$2t9H%RkaacW zT>IV+_1|*!1D{>{ZVX-@%+(%v$DFM_ev{AEbiI3cwfgbJ?!2!$!>-k}XW`%1o(}}S zZ+qRA3mkmsiEQ9xhRHXER-S$Rg`0G?;n+!efp!U=q$cERf^sKd<%(k4oDP&u^Kd9~5v`|$|D-2xIFEaU>!1Cd>`lH$UqigjK zXX_un+5N5~SKpnj>0UH`=&H%P{nz@J`j_jMuYBNczXPekrNQOy761G04!BdV39U5d zs@vy!UVZY@&F5*#Ui}e8lWzar?sYB1{(JK)^j6e;VHXVWHyo$;Qs3@<J9u0fsxi;^I}r$c#orB}qbBy?~z4rnSY52odAp zHU~~N8gPQrq;(*snKZgHsp?MQK~W&4Z9A8w85F2Pl&C5wIKP7{9;;D&PQL=@pBep( z0hF*|ryZuEG*H9~ouI;0(FAX87jadSQ2dgj6B7zdzOJa8c2Y`3erXN1HLZDDr}Wei zD14R~?*T5p&*qXgl-ApV#*y3>z`jrzp&=Bns`3Z%>H@bS!x)OTZK2o?=cuc{ql#1g zbPf*LmpER0(D4Xed!m8k#GrHh#lm^_#RnaOhy;?oiAWUdfhaUjL-ai=C##Dod(2L`i$oRccML~ss14>o(EDgF|EsjSr0Bm7sXMyLIJlW0q!Z3 zcME9VQodid+VEM(n)VjOaY6nQ@7sQu3IYvemfCbumBGBl@xChr7LLl6In6IU^~=3E zPiW4ZuW5XH_pO@FrNcMbIV1YXI2SwTl5<+HH!L>D;yYW>kazjkT#Z>*6Z`x$Eu|R z-fs6Tyfpt(hR@mdt{V4#y6K_pbtwMu-Ka9YYkQ>+g<#Wt0hjiBwf1fw^%GxJ_aW_1 zI%uH5hV2#{>|vt*iPGnBQ(N#4i}XI*J1{&X>;AvRd@_OdVT?=_JgXB=F&=OE_{&I+ zAwi!p9`EP)G!i_!%Tr_qV|WcmE}Ud1vhQK?50OYnh}{TJMf|@Z!O`Y_0tC)de}i$< zl zH?#np?O(5?OqK=1ykXT5${Q;dO!KByS4(M(ls2h(MI4D4=Z&k*AeNfv&8zO_(iq`K z>Q>BGta?ZdIksM9@wLnjZr17<=cZlHG=5}1#2oz97`>ON|MiBTf#wOg;D2zq$D$`D zgJ3J{lHe+E1YE#$94ux@FZ)@_-hj9VlSKrP4k#0dvmZ}p3vQT*!=OC)WVBK4%Hv69 z5DHy+LJ=b<5j3b?l>c&dtP#E+3^)bx6J)FyMJD5UC?kd@XYOBP4Gi z`C}w2NZv;BCrEyPWDSU90H??(NHP8hW;J4#t`|kvQB3~`37J5TW2_Yk+PUr4XxX7Q?%t1otyT2LOn<}NM4JUcHN_Zd~BrXmY-9ubtC2S z%-Zr!7Z88dDh1aozE#SVce)|N>&K|evr5?kxW8$Ys)rfs-IX`m)-^_xV}mh!ovV~{ zv$l(-y>r|`Vm`4+VSMum%`v)ju3;fKAKauMx;af->0^tYHOHQ;W6vf9iOs-i4P8Gs Rli_Y8uO~mIFhxH2e*xrWH1Plc literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_dummy.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_dummy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34cbd51147141242ac2ac07b57d1ba94a31805d6 GIT binary patch literal 421 zcmXw$yH3L}6hQ4JeJE-dzQAIu1hFWB39*!=qGIY4hRBJpTC1@g*-jxWdWle-E3y|QwPG}WJ(ae#YDWx6BfK(Rv z0m&-Y=4s=ES`y*NjVKDzrWhtH5Tgw;2^&Xm*pD_2n`r908C?`$n&1-ZrtdM; z9GbygSO*Hs)wtL6)0FExO`C3-F$>0Tj7->~+oI?3h_;?+cTJ^o^umY@Oz1)wT?#j6 zmC9FO=yX1#8&Dfsh>VuCTWNJ1A5Ewg4h~C}uh|l;52&(obPaW;nc+13xkFsmyTRG- gk literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_uinput.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_uinput.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa1b6b37c1dcd6149147af63ebbb0ab6f255a352 GIT binary patch literal 21313 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%0As9df!fc14YJX*7GuF{8GzBPBnV07l*E2>>8 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_win32.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/__pycache__/_win32.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..427c0fd122451b31d63b869370b07f636611b4e6 GIT binary patch literal 17438 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 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_base.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_base.py new file mode 100644 index 0000000..6035743 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_base.py @@ -0,0 +1,754 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +This module contains the base implementation. + +The actual interface to keyboard classes is defined here, but the +implementation is located in a platform dependent module. +""" + +# pylint: disable=R0903 +# We implement stubs + +import contextlib +import enum +import threading +import unicodedata + +import six + +from pynput._util import AbstractListener, prefix +from pynput import _logger + + +class KeyCode(object): + """ + A :class:`KeyCode` represents the description of a key code used by the + operating system. + """ + #: The names of attributes used as platform extensions. + _PLATFORM_EXTENSIONS = [] + + def __init__(self, vk=None, char=None, is_dead=False, **kwargs): + self.vk = vk + self.char = six.text_type(char) if char is not None else None + self.is_dead = is_dead + + if self.is_dead: + try: + self.combining = unicodedata.lookup( + 'COMBINING ' + unicodedata.name(self.char)) + except KeyError: + self.is_dead = False + self.combining = None + if self.is_dead and not self.combining: + raise KeyError(char) + else: + self.combining = None + + for key in self._PLATFORM_EXTENSIONS: + setattr(self, key, kwargs.pop(key, None)) + if kwargs: + raise ValueError(kwargs) + + + def __repr__(self): + if self.is_dead: + return '[%s]' % repr(self.char) + if self.char is not None: + return repr(self.char) + else: + return '<%d>' % self.vk + + def __str__(self): + return repr(self) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if self.char is not None and other.char is not None: + return self.char == other.char and self.is_dead == other.is_dead + else: + return self.vk == other.vk and all( + getattr(self, f) == getattr(other, f) + for f in self._PLATFORM_EXTENSIONS) + + def __hash__(self): + return hash(repr(self)) + + def join(self, key): + """Applies this dead key to another key and returns the result. + + Joining a dead key with space (``' '``) or itself yields the non-dead + version of this key, if one exists; for example, + ``KeyCode.from_dead('~').join(KeyCode.from_char(' '))`` equals + ``KeyCode.from_char('~')`` and + ``KeyCode.from_dead('~').join(KeyCode.from_dead('~'))``. + + :param KeyCode key: The key to join with this key. + + :return: a key code + + :raises ValueError: if the keys cannot be joined + """ + # A non-dead key cannot be joined + if not self.is_dead: + raise ValueError(self) + + # Joining two of the same keycodes, or joining with space, yields the + # non-dead version of the key + if key.char == ' ' or self == key: + return self.from_char(self.char) + + # Otherwise we combine the characters + if key.char is not None: + combined = unicodedata.normalize( + 'NFC', + key.char + self.combining) + if combined: + return self.from_char(combined) + + raise ValueError(key) + + @classmethod + def from_vk(cls, vk, **kwargs): + """Creates a key from a virtual key code. + + :param vk: The virtual key code. + + :param kwargs: Any other parameters to pass. + + :return: a key code + """ + return cls(vk=vk, **kwargs) + + @classmethod + def from_char(cls, char, **kwargs): + """Creates a key from a character. + + :param str char: The character. + + :return: a key code + """ + return cls(char=char, **kwargs) + + @classmethod + def from_dead(cls, char, **kwargs): + """Creates a dead key. + + :param char: The dead key. This should be the unicode character + representing the stand alone character, such as ``'~'`` for + *COMBINING TILDE*. + + :return: a key code + """ + return cls(char=char, is_dead=True, **kwargs) + + +class Key(enum.Enum): + """A class representing various buttons that may not correspond to + letters. This includes modifier keys and function keys. + + The actual values for these items differ between platforms. Some platforms + may have additional buttons, but these are guaranteed to be present + everywhere. + """ + #: A generic Alt key. This is a modifier. + alt = KeyCode.from_vk(0) + + #: The left Alt key. This is a modifier. + alt_l = KeyCode.from_vk(0) + + #: The right Alt key. This is a modifier. + alt_r = KeyCode.from_vk(0) + + #: The AltGr key. This is a modifier. + alt_gr = KeyCode.from_vk(0) + + #: The Backspace key. + backspace = KeyCode.from_vk(0) + + #: The CapsLock key. + caps_lock = KeyCode.from_vk(0) + + #: A generic command button. On *PC* platforms, this corresponds to the + #: Super key or Windows key, and on *Mac* it corresponds to the Command + #: key. This may be a modifier. + cmd = KeyCode.from_vk(0) + + #: The left command button. On *PC* platforms, this corresponds to the + #: Super key or Windows key, and on *Mac* it corresponds to the Command + #: key. This may be a modifier. + cmd_l = KeyCode.from_vk(0) + + #: The right command button. On *PC* platforms, this corresponds to the + #: Super key or Windows key, and on *Mac* it corresponds to the Command + #: key. This may be a modifier. + cmd_r = KeyCode.from_vk(0) + + #: A generic Ctrl key. This is a modifier. + ctrl = KeyCode.from_vk(0) + + #: The left Ctrl key. This is a modifier. + ctrl_l = KeyCode.from_vk(0) + + #: The right Ctrl key. This is a modifier. + ctrl_r = KeyCode.from_vk(0) + + #: The Delete key. + delete = KeyCode.from_vk(0) + + #: A down arrow key. + down = KeyCode.from_vk(0) + + #: The End key. + end = KeyCode.from_vk(0) + + #: The Enter or Return key. + enter = KeyCode.from_vk(0) + + #: The Esc key. + esc = KeyCode.from_vk(0) + + #: The function keys. F1 to F20 are defined. + f1 = KeyCode.from_vk(0) + f2 = KeyCode.from_vk(0) + f3 = KeyCode.from_vk(0) + f4 = KeyCode.from_vk(0) + f5 = KeyCode.from_vk(0) + f6 = KeyCode.from_vk(0) + f7 = KeyCode.from_vk(0) + f8 = KeyCode.from_vk(0) + f9 = KeyCode.from_vk(0) + f10 = KeyCode.from_vk(0) + f11 = KeyCode.from_vk(0) + f12 = KeyCode.from_vk(0) + f13 = KeyCode.from_vk(0) + f14 = KeyCode.from_vk(0) + f15 = KeyCode.from_vk(0) + f16 = KeyCode.from_vk(0) + f17 = KeyCode.from_vk(0) + f18 = KeyCode.from_vk(0) + f19 = KeyCode.from_vk(0) + f20 = KeyCode.from_vk(0) + + #: The Home key. + home = KeyCode.from_vk(0) + + #: A left arrow key. + left = KeyCode.from_vk(0) + + #: The PageDown key. + page_down = KeyCode.from_vk(0) + + #: The PageUp key. + page_up = KeyCode.from_vk(0) + + #: A right arrow key. + right = KeyCode.from_vk(0) + + #: A generic Shift key. This is a modifier. + shift = KeyCode.from_vk(0) + + #: The left Shift key. This is a modifier. + shift_l = KeyCode.from_vk(0) + + #: The right Shift key. This is a modifier. + shift_r = KeyCode.from_vk(0) + + #: The Space key. + space = KeyCode.from_vk(0) + + #: The Tab key. + tab = KeyCode.from_vk(0) + + #: An up arrow key. + up = KeyCode.from_vk(0) + + #: The play/pause toggle. + media_play_pause = KeyCode.from_vk(0) + + #: The volume mute button. + media_volume_mute = KeyCode.from_vk(0) + + #: The volume down button. + media_volume_down = KeyCode.from_vk(0) + + #: The volume up button. + media_volume_up = KeyCode.from_vk(0) + + #: The previous track button. + media_previous = KeyCode.from_vk(0) + + #: The next track button. + media_next = KeyCode.from_vk(0) + + #: The Insert key. This may be undefined for some platforms. + insert = KeyCode.from_vk(0) + + #: The Menu key. This may be undefined for some platforms. + menu = KeyCode.from_vk(0) + + #: The NumLock key. This may be undefined for some platforms. + num_lock = KeyCode.from_vk(0) + + #: The Pause/Break key. This may be undefined for some platforms. + pause = KeyCode.from_vk(0) + + #: The PrintScreen key. This may be undefined for some platforms. + print_screen = KeyCode.from_vk(0) + + #: The ScrollLock key. This may be undefined for some platforms. + scroll_lock = KeyCode.from_vk(0) + + +class Controller(object): + """A controller for sending virtual keyboard events to the system. + """ + #: The virtual key codes + _KeyCode = KeyCode + + #: The various keys. + _Key = Key + + class InvalidKeyException(Exception): + """The exception raised when an invalid ``key`` parameter is passed to + either :meth:`Controller.press` or :meth:`Controller.release`. + + Its first argument is the ``key`` parameter. + """ + pass + + class InvalidCharacterException(Exception): + """The exception raised when an invalid character is encountered in + the string passed to :meth:`Controller.type`. + + Its first argument is the index of the character in the string, and the + second the character. + """ + pass + + def __init__(self): + self._log = _logger(self.__class__) + self._modifiers_lock = threading.RLock() + self._modifiers = set() + self._caps_lock = False + self._dead_key = None + + def press(self, key): + """Presses a key. + + A key may be either a string of length 1, one of the :class:`Key` + members or a :class:`KeyCode`. + + Strings will be transformed to :class:`KeyCode` using + :meth:`KeyCode.char`. Members of :class:`Key` will be translated to + their :meth:`~Key.value`. + + :param key: The key to press. + + :raises InvalidKeyException: if the key is invalid + + :raises ValueError: if ``key`` is a string, but its length is not ``1`` + """ + resolved = self._resolve(key) + if resolved is None: + raise self.InvalidKeyException(key) + self._update_modifiers(resolved, True) + + # Update caps lock state + if resolved == self._Key.caps_lock.value: + self._caps_lock = not self._caps_lock + + # If we currently have a dead key pressed, join it with this key + original = resolved + if self._dead_key: + try: + resolved = self._dead_key.join(resolved) + except ValueError: + self._handle(self._dead_key, True) + self._handle(self._dead_key, False) + + # If the key is a dead key, keep it for later + if resolved.is_dead: + self._dead_key = resolved + return + + try: + self._handle(resolved, True) + except self.InvalidKeyException: + if resolved != original: + self._handle(self._dead_key, True) + self._handle(self._dead_key, False) + self._handle(original, True) + + self._dead_key = None + + def release(self, key): + """Releases a key. + + A key may be either a string of length 1, one of the :class:`Key` + members or a :class:`KeyCode`. + + Strings will be transformed to :class:`KeyCode` using + :meth:`KeyCode.char`. Members of :class:`Key` will be translated to + their :meth:`~Key.value`. + + :param key: The key to release. If this is a string, it is passed to + :meth:`touches` and the returned releases are used. + + :raises InvalidKeyException: if the key is invalid + + :raises ValueError: if ``key`` is a string, but its length is not ``1`` + """ + resolved = self._resolve(key) + if resolved is None: + raise self.InvalidKeyException(key) + self._update_modifiers(resolved, False) + + # Ignore released dead keys + if resolved.is_dead: + return + + self._handle(resolved, False) + + def tap(self, key): + """Presses and releases a key. + + This is equivalent to the following code:: + + controller.press(key) + controller.release(key) + + :param key: The key to press. + + :raises InvalidKeyException: if the key is invalid + + :raises ValueError: if ``key`` is a string, but its length is not ``1`` + """ + self.press(key) + self.release(key) + + def touch(self, key, is_press): + """Calls either :meth:`press` or :meth:`release` depending on the value + of ``is_press``. + + :param key: The key to press or release. + + :param bool is_press: Whether to press the key. + + :raises InvalidKeyException: if the key is invalid + """ + if is_press: + self.press(key) + else: + self.release(key) + + @contextlib.contextmanager + def pressed(self, *args): + """Executes a block with some keys pressed. + + :param keys: The keys to keep pressed. + """ + for key in args: + self.press(key) + + try: + yield + finally: + for key in reversed(args): + self.release(key) + + def type(self, string): + """Types a string. + + This method will send all key presses and releases necessary to type + all characters in the string. + + :param str string: The string to type. + + :raises InvalidCharacterException: if an untypable character is + encountered + """ + from . import _CONTROL_CODES + for i, character in enumerate(string): + key = _CONTROL_CODES.get(character, character) + try: + self.press(key) + self.release(key) + + except (ValueError, self.InvalidKeyException): + raise self.InvalidCharacterException(i, character) + + @property + @contextlib.contextmanager + def modifiers(self): + """The currently pressed modifier keys. + + Please note that this reflects only the internal state of this + controller, and not the state of the operating system keyboard buffer. + This property cannot be used to determine whether a key is physically + pressed. + + Only the generic modifiers will be set; when pressing either + :attr:`Key.shift_l`, :attr:`Key.shift_r` or :attr:`Key.shift`, only + :attr:`Key.shift` will be present. + + Use this property within a context block thus:: + + with controller.modifiers as modifiers: + with_block() + + This ensures that the modifiers cannot be modified by another thread. + """ + with self._modifiers_lock: + yield set( + self._as_modifier(modifier) + for modifier in self._modifiers) + + @property + def alt_pressed(self): + """Whether any *alt* key is pressed. + + Please note that this reflects only the internal state of this + controller. See :attr:`modifiers` for more information. + """ + with self.modifiers as modifiers: + return self._Key.alt in modifiers + + @property + def alt_gr_pressed(self): + """Whether *altgr* is pressed. + + Please note that this reflects only the internal state of this + controller. See :attr:`modifiers` for more information. + """ + with self.modifiers as modifiers: + return self._Key.alt_gr in modifiers + + @property + def ctrl_pressed(self): + """Whether any *ctrl* key is pressed. + + Please note that this reflects only the internal state of this + controller. See :attr:`modifiers` for more information. + """ + with self.modifiers as modifiers: + return self._Key.ctrl in modifiers + + @property + def shift_pressed(self): + """Whether any *shift* key is pressed, or *caps lock* is toggled. + + Please note that this reflects only the internal state of this + controller. See :attr:`modifiers` for more information. + """ + if self._caps_lock: + return True + + with self.modifiers as modifiers: + return self._Key.shift in modifiers + + def _resolve(self, key): + """Resolves a key to a :class:`KeyCode` instance. + + This method will convert any key representing a character to uppercase + if a shift modifier is active. + + :param key: The key to resolve. + + :return: a key code, or ``None`` if it cannot be resolved + """ + # Use the value for the key constants + if key in (k for k in self._Key): + return key.value + + # Convert strings to key codes + if isinstance(key, six.string_types): + if len(key) != 1: + raise ValueError(key) + return self._KeyCode.from_char(key) + + # Assume this is a proper key + if isinstance(key, self._KeyCode): + if key.char is not None and self.shift_pressed: + return self._KeyCode(vk=key.vk, char=key.char.upper()) + else: + return key + + def _update_modifiers(self, key, is_press): + """Updates the current modifier list. + + If ``key`` is not a modifier, no action is taken. + + :param key: The key being pressed or released. + """ + # Check whether the key is a modifier + if self._as_modifier(key): + with self._modifiers_lock: + if is_press: + self._modifiers.add(key) + else: + try: + self._modifiers.remove(key) + except KeyError: + pass + + def _as_modifier(self, key): + """Returns a key as the modifier used internally if defined. + + This method will convert values like :attr:`Key.alt_r.value` and + :attr:`Key.shift_l.value` to :attr:`Key.alt` and :attr:`Key.shift`. + + :param key: The possible modifier key. + + :return: the base modifier key, or ``None`` if ``key`` is not a + modifier + """ + from . import _NORMAL_MODIFIERS + return _NORMAL_MODIFIERS.get(key, None) + + def _handle(self, key, is_press): + """The platform implementation of the actual emitting of keyboard + events. + + This is a platform dependent implementation. + + :param Key key: The key to handle. + + :param bool is_press: Whether this is a key press event. + """ + raise NotImplementedError() + + +# pylint: disable=W0223; This is also an abstract class +class Listener(AbstractListener): + """A listener for keyboard events. + + Instances of this class can be used as context managers. This is equivalent + to the following code:: + + listener.start() + try: + listener.wait() + with_statements() + finally: + listener.stop() + + This class inherits from :class:`threading.Thread` and supports all its + methods. It will set :attr:`daemon` to ``True`` when created. + + All callback arguments are optional; a callback may take less arguments + than actually passed, but not more, unless they are optional. + + :param callable on_press: The callback to call when a button is pressed. + + It will be called with the arguments ``(key, injected)``, where ``key`` + is a :class:`KeyCode`, a :class:`Key` or ``None`` if the key is + unknown, and ``injected`` whether the event was injected and thus not + generated by an actual input device. + + Please note that not all backends support ``injected`` and will always + set it to ``False``. + + :param callable on_release: The callback to call when a button is released. + + It will be called with the arguments ``(key, injected)``, where ``key`` + is a :class:`KeyCode`, a :class:`Key` or ``None`` if the key is + unknown, and ``injected`` whether the event was injected and thus not + generated by an actual input device. + + Please note that not all backends support ``injected`` and will always + set it to ``False``. + + :param bool suppress: Whether to suppress events. Setting this to ``True`` + will prevent the input events from being passed to the rest of the + system. + + :param kwargs: Any non-standard platform dependent options. These should be + prefixed with the platform name thus: ``darwin_``, ``uinput_``, + ``xorg_`` or ``win32_``. + + Supported values are: + + ``darwin_intercept`` + A callable taking the arguments ``(event_type, event)``, where + ``event_type`` is ``Quartz.kCGEventKeyDown`` or + ``Quartz.kCGEventKeyUp``, and ``event`` is a ``CGEventRef``. + + This callable can freely modify the event using functions like + ``Quartz.CGEventSetIntegerValueField``. If this callable does not + return the event, the event is suppressed system wide. + + ``uinput_device_paths`` + A list of device paths. + + If this is specified, *pynput* will limit the number of devices + checked for the capabilities needed to those passed, otherwise all + system devices will be used. Passing this might be required if an + incorrect device is chosen. + + ``win32_event_filter`` + A callable taking the arguments ``(msg, data)``, where ``msg`` is + the current message, and ``data`` associated data as a + `KBDLLHOOKSTRUCT `_. + + If this callback returns ``False``, the event will not be + propagated to the listener callback. + + If ``self.suppress_event()`` is called, the event is suppressed + system wide. + """ + def __init__(self, on_press=None, on_release=None, suppress=False, + **kwargs): + self._log = _logger(self.__class__) + option_prefix = prefix(Listener, self.__class__) + self._options = { + key[len(option_prefix):]: value + for key, value in kwargs.items() + if key.startswith(option_prefix)} + super(Listener, self).__init__( + on_press=self._wrap(on_press, 2), + on_release=self._wrap(on_release, 2), + suppress=suppress) +# pylint: enable=W0223 + + def canonical(self, key): + """Performs normalisation of a key. + + This method attempts to convert key events to their canonical form, so + that events will equal regardless of modifier state. + + This method will convert upper case keys to lower case keys, convert + any modifiers with a right and left version to the same value, and may + slow perform additional platform dependent normalisation. + + :param key: The key to normalise. + :type key: Key or KeyCode + + :return: a key + :rtype: Key or KeyCode + """ + from pynput.keyboard import Key, KeyCode, _NORMAL_MODIFIERS + if isinstance(key, KeyCode) and key.char is not None: + return KeyCode.from_char(key.char.lower()) + elif isinstance(key, Key) and key.value in _NORMAL_MODIFIERS: + return _NORMAL_MODIFIERS[key.value] + elif isinstance(key, Key) and key.value.vk is not None: + return KeyCode.from_vk(key.value.vk) + else: + return key diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_darwin.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_darwin.py new file mode 100644 index 0000000..4065164 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_darwin.py @@ -0,0 +1,367 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The keyboard implementation for *macOS*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +import enum + +from Quartz import ( + CGEventCreateKeyboardEvent, + CGEventGetFlags, + CGEventGetIntegerValueField, + CGEventGetType, + CGEventKeyboardGetUnicodeString, + CGEventKeyboardSetUnicodeString, + CGEventMaskBit, + CGEventPost, + CGEventSetFlags, + kCGEventFlagMaskAlternate, + kCGEventFlagMaskCommand, + kCGEventFlagMaskControl, + kCGEventFlagMaskShift, + kCGEventFlagsChanged, + kCGEventKeyDown, + kCGEventKeyUp, + kCGHIDEventTap, + kCGKeyboardEventKeycode, + NSEvent, + NSSystemDefined) + +from pynput._util.darwin import ( + get_unicode_to_keycode_map, + keycode_context, + ListenerMixin) +from pynput._util.darwin_vks import SYMBOLS +from . import _base + + +# From hidsystem/ev_keymap.h +NX_KEYTYPE_PLAY = 16 +NX_KEYTYPE_MUTE = 7 +NX_KEYTYPE_SOUND_DOWN = 1 +NX_KEYTYPE_SOUND_UP = 0 +NX_KEYTYPE_NEXT = 17 +NX_KEYTYPE_PREVIOUS = 18 +NX_KEYTYPE_EJECT = 14 + +# pylint: disable=C0103; We want to use the names from the C API +# This is undocumented, but still widely known +kSystemDefinedEventMediaKeysSubtype = 8 + +# We extract this here since the name is very long +otherEventWithType = getattr( + NSEvent, + 'otherEventWithType_' + 'location_' + 'modifierFlags_' + 'timestamp_' + 'windowNumber_' + 'context_' + 'subtype_' + 'data1_' + 'data2_') +# pylint: enable=C0103 + + +class KeyCode(_base.KeyCode): + _PLATFORM_EXTENSIONS = ( + # Whether this is a media key + '_is_media', + ) + + # Be explicit about fields + _is_media = None + + @classmethod + def _from_media(cls, vk, **kwargs): + """Creates a media key from a key code. + + :param int vk: The key code. + + :return: a key code + """ + return cls.from_vk(vk, _is_media=True, **kwargs) + + def _event(self, modifiers, mapping, is_pressed): + """This key as a *Quartz* event. + + :param set modifiers: The currently active modifiers. + + :param mapping: The current keyboard mapping. + + :param bool is_press: Whether to generate a press event. + + :return: a *Quartz* event + """ + vk = self.vk or mapping.get(self.char) + if self._is_media: + result = otherEventWithType( + NSSystemDefined, + (0, 0), + 0xa00 if is_pressed else 0xb00, + 0, + 0, + 0, + 8, + (self.vk << 16) | ((0xa if is_pressed else 0xb) << 8), + -1).CGEvent() + else: + result = CGEventCreateKeyboardEvent( + None, 0 if vk is None else vk, is_pressed) + + CGEventSetFlags( + result, + 0 + | (kCGEventFlagMaskAlternate + if Key.alt in modifiers else 0) + + | (kCGEventFlagMaskCommand + if Key.cmd in modifiers else 0) + + | (kCGEventFlagMaskControl + if Key.ctrl in modifiers else 0) + + | (kCGEventFlagMaskShift + if Key.shift in modifiers else 0)) + + if vk is None and self.char is not None: + CGEventKeyboardSetUnicodeString( + result, len(self.char), self.char) + + return result + + +# pylint: disable=W0212 +class Key(enum.Enum): + # Default keys + alt = KeyCode.from_vk(0x3A) + alt_l = KeyCode.from_vk(0x3A) + alt_r = KeyCode.from_vk(0x3D) + alt_gr = KeyCode.from_vk(0x3D) + backspace = KeyCode.from_vk(0x33) + caps_lock = KeyCode.from_vk(0x39) + cmd = KeyCode.from_vk(0x37) + cmd_l = KeyCode.from_vk(0x37) + cmd_r = KeyCode.from_vk(0x36) + ctrl = KeyCode.from_vk(0x3B) + ctrl_l = KeyCode.from_vk(0x3B) + ctrl_r = KeyCode.from_vk(0x3E) + delete = KeyCode.from_vk(0x75) + down = KeyCode.from_vk(0x7D) + end = KeyCode.from_vk(0x77) + enter = KeyCode.from_vk(0x24) + esc = KeyCode.from_vk(0x35) + f1 = KeyCode.from_vk(0x7A) + f2 = KeyCode.from_vk(0x78) + f3 = KeyCode.from_vk(0x63) + f4 = KeyCode.from_vk(0x76) + f5 = KeyCode.from_vk(0x60) + f6 = KeyCode.from_vk(0x61) + f7 = KeyCode.from_vk(0x62) + f8 = KeyCode.from_vk(0x64) + f9 = KeyCode.from_vk(0x65) + f10 = KeyCode.from_vk(0x6D) + f11 = KeyCode.from_vk(0x67) + f12 = KeyCode.from_vk(0x6F) + f13 = KeyCode.from_vk(0x69) + f14 = KeyCode.from_vk(0x6B) + f15 = KeyCode.from_vk(0x71) + f16 = KeyCode.from_vk(0x6A) + f17 = KeyCode.from_vk(0x40) + f18 = KeyCode.from_vk(0x4F) + f19 = KeyCode.from_vk(0x50) + f20 = KeyCode.from_vk(0x5A) + home = KeyCode.from_vk(0x73) + left = KeyCode.from_vk(0x7B) + page_down = KeyCode.from_vk(0x79) + page_up = KeyCode.from_vk(0x74) + right = KeyCode.from_vk(0x7C) + shift = KeyCode.from_vk(0x38) + shift_l = KeyCode.from_vk(0x38) + shift_r = KeyCode.from_vk(0x3C) + space = KeyCode.from_vk(0x31, char=' ') + tab = KeyCode.from_vk(0x30) + up = KeyCode.from_vk(0x7E) + + media_play_pause = KeyCode._from_media(NX_KEYTYPE_PLAY) + media_volume_mute = KeyCode._from_media(NX_KEYTYPE_MUTE) + media_volume_down = KeyCode._from_media(NX_KEYTYPE_SOUND_DOWN) + media_volume_up = KeyCode._from_media(NX_KEYTYPE_SOUND_UP) + media_previous = KeyCode._from_media(NX_KEYTYPE_PREVIOUS) + media_next = KeyCode._from_media(NX_KEYTYPE_NEXT) + media_eject = KeyCode._from_media(NX_KEYTYPE_EJECT) +# pylint: enable=W0212 + + +class Controller(_base.Controller): + _KeyCode = KeyCode + _Key = Key + + def __init__(self): + super(Controller, self).__init__() + self._mapping = get_unicode_to_keycode_map() + + def _handle(self, key, is_press): + with self.modifiers as modifiers: + CGEventPost( + kCGHIDEventTap, + (key if key not in (k for k in Key) else key.value)._event( + modifiers, self._mapping, is_press)) + + +class Listener(ListenerMixin, _base.Listener): + #: The events that we listen to + _EVENTS = ( + CGEventMaskBit(kCGEventKeyDown) | + CGEventMaskBit(kCGEventKeyUp) | + CGEventMaskBit(kCGEventFlagsChanged) | + CGEventMaskBit(NSSystemDefined) + ) + + # pylint: disable=W0212 + #: A mapping from keysym to special key + _SPECIAL_KEYS = { + (key.value.vk, key.value._is_media): key + for key in Key} + # pylint: enable=W0212 + + #: The event flags set for the various modifier keys + _MODIFIER_FLAGS = { + Key.alt: kCGEventFlagMaskAlternate, + Key.alt_l: kCGEventFlagMaskAlternate, + Key.alt_r: kCGEventFlagMaskAlternate, + Key.cmd: kCGEventFlagMaskCommand, + Key.cmd_l: kCGEventFlagMaskCommand, + Key.cmd_r: kCGEventFlagMaskCommand, + Key.ctrl: kCGEventFlagMaskControl, + Key.ctrl_l: kCGEventFlagMaskControl, + Key.ctrl_r: kCGEventFlagMaskControl, + Key.shift: kCGEventFlagMaskShift, + Key.shift_l: kCGEventFlagMaskShift, + Key.shift_r: kCGEventFlagMaskShift} + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._flags = 0 + self._context = None + self._intercept = self._options.get( + 'intercept', + None) + + def _run(self): + with keycode_context() as context: + self._context = context + try: + super(Listener, self)._run() + finally: + self._context = None + + def _handle_message(self, _proxy, event_type, event, _refcon, injected): + # Convert the event to a KeyCode; this may fail, and in that case we + # pass None + try: + key = self._event_to_key(event) + except IndexError: + key = None + + try: + if event_type == kCGEventKeyDown: + # This is a normal key press + self.on_press(key, injected) + + elif event_type == kCGEventKeyUp: + # This is a normal key release + self.on_release(key, injected) + + elif key == Key.caps_lock: + # We only get an event when caps lock is toggled, so we fake + # press and release + self.on_press(key, injected) + self.on_release(key, injected) + + elif event_type == NSSystemDefined: + sys_event = NSEvent.eventWithCGEvent_(event) + if sys_event.subtype() == kSystemDefinedEventMediaKeysSubtype: + # The key in the special key dict; True since it is a media + # key + key = ((sys_event.data1() & 0xffff0000) >> 16, True) + if key in self._SPECIAL_KEYS: + flags = sys_event.data1() & 0x0000ffff + is_press = ((flags & 0xff00) >> 8) == 0x0a + if is_press: + self.on_press(self._SPECIAL_KEYS[key]) + else: + self.on_release(self._SPECIAL_KEYS[key]) + + else: + # This is a modifier event---excluding caps lock---for which we + # must check the current modifier state to determine whether + # the key was pressed or released + flags = CGEventGetFlags(event) + is_press = flags & self._MODIFIER_FLAGS.get(key, 0) + if is_press: + self.on_press(key, injected) + else: + self.on_release(key, injected) + + finally: + # Store the current flag mask to be able to detect modifier state + # changes + self._flags = CGEventGetFlags(event) + + def _event_to_key(self, event): + """Converts a *Quartz* event to a :class:`KeyCode`. + + :param event: The event to convert. + + :return: a :class:`pynput.keyboard.KeyCode` + + :raises IndexError: if the key code is invalid + """ + vk = CGEventGetIntegerValueField( + event, kCGKeyboardEventKeycode) + event_type = CGEventGetType(event) + is_media = True if event_type == NSSystemDefined else None + + # First try special keys... + key = (vk, is_media) + if key in self._SPECIAL_KEYS: + return self._SPECIAL_KEYS[key] + + # ...then try characters... + length, chars = CGEventKeyboardGetUnicodeString( + event, 100, None, None) + try: + printable = chars.isprintable() + except AttributeError: + printable = chars.isalnum() + if not printable and vk in SYMBOLS \ + and CGEventGetFlags(event) \ + & kCGEventFlagMaskControl: + return KeyCode.from_char(SYMBOLS[vk], vk=vk) + elif length > 0: + return KeyCode.from_char(chars, vk=vk) + + # ...and fall back on a virtual key code + return KeyCode.from_vk(vk) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_dummy.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_dummy.py new file mode 100644 index 0000000..10727f6 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_dummy.py @@ -0,0 +1,23 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +This module contains a dummy implementation. + +It cannot be used, but importing it will not raise any exceptions. +""" + +from ._base import Controller, Key, KeyCode, Listener diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_uinput.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_uinput.py new file mode 100644 index 0000000..2f63dd3 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_uinput.py @@ -0,0 +1,446 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The keyboard implementation for *uinput*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +import enum +import errno +import functools +import os +import re +import subprocess + +import evdev + +from evdev.events import KeyEvent + +from pynput._util import xorg_keysyms +from pynput._util.uinput import ListenerMixin +from . import _base + + +class KeyCode(_base.KeyCode): + _PLATFORM_EXTENSIONS = ( + # The name for this key + '_x_name', + '_kernel_name', + ) + + # Be explicit about fields + _x_name = None + _kernel_name = None +# pylint: enable=W0212 + + @classmethod + def _from_name(cls, x_name, kernel_name, **kwargs): + """Creates a key from a name. + + :param str x_name: The X name. + + :param str kernel_name: The kernel name. + + :return: a key code + """ + try: + vk = getattr(evdev.ecodes, kernel_name) + except AttributeError: + vk = None + return cls.from_vk( + vk, _x_name=x_name, _kernel_name=kernel_name, **kwargs) + + +# pylint: disable=W0212 +class Key(enum.Enum): + alt = KeyCode._from_name('Alt_L', 'KEY_LEFTALT') + alt_l = KeyCode._from_name('Alt_L', 'KEY_LEFTALT') + alt_r = KeyCode._from_name('Alt_R', 'KEY_RIGHTALT') + alt_gr = KeyCode._from_name('Mode_switch', 'KEY_RIGHTALT') + backspace = KeyCode._from_name('BackSpace', 'KEY_BACKSPACE') + caps_lock = KeyCode._from_name('Caps_Lock', 'KEY_CAPSLOCK') + cmd = KeyCode._from_name('Super_L', 'KEY_LEFTMETA') + cmd_l = KeyCode._from_name('Super_L', 'KEY_LEFTMETA') + cmd_r = KeyCode._from_name('Super_R', 'KEY_RIGHTMETA') + ctrl = KeyCode._from_name('Control_L', 'KEY_LEFTCTRL') + ctrl_l = KeyCode._from_name('Control_L', 'KEY_LEFTCTRL') + ctrl_r = KeyCode._from_name('Control_R', 'KEY_RIGHTCTRL') + delete = KeyCode._from_name('Delete', 'KEY_DELETE') + down = KeyCode._from_name('Down', 'KEY_DOWN') + end = KeyCode._from_name('End', 'KEY_END') + enter = KeyCode._from_name('Return', 'KEY_ENTER') + esc = KeyCode._from_name('Escape', 'KEY_ESC') + f1 = KeyCode._from_name('F1', 'KEY_F1') + f2 = KeyCode._from_name('F2', 'KEY_F2') + f3 = KeyCode._from_name('F3', 'KEY_F3') + f4 = KeyCode._from_name('F4', 'KEY_F4') + f5 = KeyCode._from_name('F5', 'KEY_F5') + f6 = KeyCode._from_name('F6', 'KEY_F6') + f7 = KeyCode._from_name('F7', 'KEY_F7') + f8 = KeyCode._from_name('F8', 'KEY_F8') + f9 = KeyCode._from_name('F9', 'KEY_F9') + f10 = KeyCode._from_name('F10', 'KEY_F10') + f11 = KeyCode._from_name('F11', 'KEY_F11') + f12 = KeyCode._from_name('F12', 'KEY_F12') + f13 = KeyCode._from_name('F13', 'KEY_F13') + f14 = KeyCode._from_name('F14', 'KEY_F14') + f15 = KeyCode._from_name('F15', 'KEY_F15') + f16 = KeyCode._from_name('F16', 'KEY_F16') + f17 = KeyCode._from_name('F17', 'KEY_F17') + f18 = KeyCode._from_name('F18', 'KEY_F18') + f19 = KeyCode._from_name('F19', 'KEY_F19') + f20 = KeyCode._from_name('F20', 'KEY_F20') + home = KeyCode._from_name('Home', 'KEY_HOME') + left = KeyCode._from_name('Left', 'KEY_LEFT') + page_down = KeyCode._from_name('Page_Down', 'KEY_PAGEDOWN') + page_up = KeyCode._from_name('Page_Up', 'KEY_PAGEUP') + right = KeyCode._from_name('Right', 'KEY_RIGHT') + shift = KeyCode._from_name('Shift_L', 'KEY_LEFTSHIFT') + shift_l = KeyCode._from_name('Shift_L', 'KEY_LEFTSHIFT') + shift_r = KeyCode._from_name('Shift_R', 'KEY_RIGHTSHIFT') + space = KeyCode._from_name('space', 'KEY_SPACE', char=' ') + tab = KeyCode._from_name('Tab', 'KEY_TAB', char='\t') + up = KeyCode._from_name('Up', 'KEY_UP') + + media_play_pause = KeyCode._from_name('Play', 'KEY_PLAYPAUSE') + media_volume_mute = KeyCode._from_name('Mute', 'KEY_MUTE') + media_volume_down = KeyCode._from_name('LowerVolume', 'KEY_VOLUMEDOWN') + media_volume_up = KeyCode._from_name('RaiseVolume', 'KEY_VOLUMEUP') + media_previous = KeyCode._from_name('Prev', 'KEY_PREVIOUSSONG') + media_next = KeyCode._from_name('Next', 'KEY_NEXTSONG') + + insert = KeyCode._from_name('Insert', 'KEY_INSERT') + menu = KeyCode._from_name('Menu', 'KEY_MENU') + num_lock = KeyCode._from_name('Num_Lock', 'KEY_NUMLOCK') + pause = KeyCode._from_name('Pause', 'KEY_PAUSE') + print_screen = KeyCode._from_name('Print', 'KEY_SYSRQ') + scroll_lock = KeyCode._from_name('Scroll_Lock', 'KEY_SCROLLLOCK') +# pylint: enable=W0212 + + +class Layout(object): + """A description of the keyboard layout. + """ + #: A regular expression to parse keycodes in the dumpkeys output + #: + #: The groups are: keycode number, key names. + KEYCODE_RE = re.compile( + r'keycode\s+(\d+)\s+=(.*)') + + class Key(object): + """A key in a keyboard layout. + """ + def __init__(self, normal, shifted, alt, alt_shifted): + self._values = ( + normal, + shifted, + alt, + alt_shifted) + + def __str__(self): + return ('<' + 'normal: {}, ' + 'shifted: {}, ' + 'alternative: {}, ' + 'shifted alternative: {}>').format( + self.normal, self.shifted, self.alt, self.alt_shifted) + + __repr__ = __str__ + + def __iter__(self): + return iter(self._values) + + def __getitem__(self, i): + return self._values[i] + + @property + def normal(self): + """The normal key. + """ + return self._values[0] + + @property + def shifted(self): + """The shifted key. + """ + return self._values[1] + + @property + def alt(self): + """The alternative key. + """ + return self._values[2] + + @property + def alt_shifted(self): + """The shifted alternative key. + """ + return self._values[3] + + def __init__(self): + def as_char(k): + return k.value.char if isinstance(k, Key) else k.char + self._vk_table = self._load() + self._char_table = { + as_char(key): ( + vk, + set() + | {Key.shift} if i & 1 else set() + | {Key.alt_gr} if i & 2 else set()) + for vk, keys in self._vk_table.items() + for i, key in enumerate(keys) + if key is not None and as_char(key) is not None} + + def for_vk(self, vk, modifiers): + """Reads a key for a virtual key code and modifier state. + + :param int vk: The virtual key code. + + :param set modifiers: A set of modifiers. + + :return: a mapped key + + :raises KeyError: if ``vk`` is an unknown key + """ + return self._vk_table[vk][ + 0 + | (1 if Key.shift in modifiers else 0) + | (2 if Key.alt_gr in modifiers else 0)] + + def for_char(self, char): + """Reads a virtual key code and modifier state for a character. + + :param str char: The character. + + :return: the tuple ``(vk, modifiers)`` + + :raises KeyError: if ``vk`` is an unknown key + """ + return self._char_table[char] + + @functools.lru_cache() + def _load(self): + """Loads the keyboard layout. + + For simplicity, we call out to the ``dumpkeys`` binary. In the future, + we may want to implement this ourselves. + """ + result = {} + for keycode, names in self.KEYCODE_RE.findall( + subprocess.check_output( + ['dumpkeys', '--full-table', '--keys-only']).decode('utf-8')): + vk = int(keycode) + keys = tuple( + self._parse(vk, name) + for name in names.split()[:4]) + if any(key is not None for key in keys): + result[vk] = self.Key(*keys) + return result + + def _parse(self, vk, name): + """Parses a single key from the ``dumpkeys`` output. + + :param int vk: The key code. + + :param str name: The key name. + + :return: a key representation + """ + try: + # First try special keys... + return next( + key + for key in Key + if key.value._x_name == name) + except StopIteration: + # ...then characters... + try: + _, char = xorg_keysyms.SYMBOLS[name.lstrip('+')] + if char: + return KeyCode.from_char(char, vk=vk) + except KeyError: + pass + + # ...and finally special dumpkeys names + try: + return KeyCode.from_char({ + 'one': '1', + 'two': '2', + 'three': '3', + 'four': '4', + 'five': '5', + 'six': '6', + 'seven': '7', + 'eight': '8', + 'nine': '9', + 'zero': '0'}[name]) + except KeyError: + pass + + +class Controller(_base.Controller): + _KeyCode = KeyCode + _Key = Key + + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + self._layout = LAYOUT + self._dev = evdev.UInput() + + def __del__(self): + if hasattr(self, '_dev'): + self._dev.close() + + def _handle(self, key, is_press): + # Resolve the key to a virtual key code and a possible set of required + # modifiers + try: + vk, required_modifiers = self._to_vk_and_modifiers(key) + except ValueError: + raise self.InvalidKeyException(key) + + # Determine how we need to modify the modifier state + if is_press and required_modifiers is not None: + with self.modifiers as modifiers: + vk, required_modifiers = self._layout.for_char(key.char) + to_press = { + getattr(evdev.ecodes, key.value._kernel_name) + for key in (required_modifiers - modifiers)} + to_release = { + getattr(evdev.ecodes, key.value._kernel_name) + for key in (modifiers - required_modifiers)} + else: + to_release = set() + to_press = set() + + # Update the modifier state, send the key, and finally release any + # modifiers + cleanup = [] + try: + for k in to_release: + self._send(k, False) + cleanup.append((k, True)) + for k in to_press: + self._send(k, True) + cleanup.append((k, False)) + + self._send(vk, is_press) + + finally: + for e in reversed(cleanup): + # pylint: disable E722; we want to suppress exceptions + try: + self._send(*e) + except: + pass + # pylint: enable E722 + + self._dev.syn() + + def _to_vk_and_modifiers(self, key): + """Resolves a key to a virtual key code and a modifier set. + + :param key: The key to resolve. + :type key: Key or KeyCode + + :return: a virtual key code and possible required modifiers + """ + if hasattr(key, 'vk') and key.vk is not None: + return (key.vk, None) + elif hasattr(key, 'char') and key.char is not None: + return self._layout.for_char(key.char) + else: + raise ValueError(key) + + def _send(self, vk, is_press): + """Sends a virtual key event. + + This method does not perform ``SYN``. + + :param int vk: The virtual key. + + :param bool is_press: Whether this is a press event. + """ + self._dev.write(evdev.ecodes.EV_KEY, vk, int(is_press)) + + +class Listener(ListenerMixin, _base.Listener): + _EVENTS = ( + evdev.ecodes.EV_KEY,) + + #: A + _MODIFIERS = { + Key.alt.value.vk: Key.alt, + Key.alt_l.value.vk: Key.alt, + Key.alt_r.value.vk: Key.alt, + Key.alt_gr.value.vk: Key.alt_gr, + Key.shift.value.vk: Key.shift, + Key.shift_l.value.vk: Key.shift, + Key.shift_r.value.vk: Key.shift} + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._layout = LAYOUT + self._modifiers = set() + + def _handle_message(self, event): + is_press = event.value in (KeyEvent.key_down, KeyEvent.key_hold) + vk = event.code + + # Update the modifier state + if vk in self._MODIFIERS: + modifier = self._MODIFIERS[vk] + if is_press: + self._modifiers.add(modifier) + elif modifier in self._modifiers: + self._modifiers.remove(modifier) + + # Attempt to map the virtual key code to a key + try: + key = self._layout.for_vk(vk, self._modifiers) + except KeyError: + try: + key = next( + key + for key in Key + if key.value.vk == vk) + except StopIteration: + key = KeyCode.from_vk(vk) + + # We do not know whether these events are injected + if is_press: + self.on_press(key, False) + else: + self.on_release(key, False) + + +try: + #: The keyboard layout. + LAYOUT = Layout() +except subprocess.CalledProcessError as e: + raise ImportError('failed to load keyboard layout: "' + str(e) + ( + '"; please make sure you are root' if os.getuid() != 1 else '"')) +except OSError as e: + raise ImportError({ + errno.ENOENT: 'the binary dumpkeys is not installed'}.get( + e.args[0], + str(e))) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_win32.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_win32.py new file mode 100644 index 0000000..fbbcc98 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_win32.py @@ -0,0 +1,389 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The keyboard implementation for *Windows*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +import contextlib +import ctypes +import enum +import six + +from ctypes import wintypes + +import pynput._util.win32_vks as VK + +from pynput._util import AbstractListener +from pynput._util.win32 import ( + INPUT, + INPUT_union, + KEYBDINPUT, + KeyTranslator, + ListenerMixin, + MapVirtualKey, + SendInput, + SystemHook, + VkKeyScan) +from . import _base + + +class KeyCode(_base.KeyCode): + _PLATFORM_EXTENSIONS = ( + # Any extra flags. + '_flags', + + #: The scan code. + '_scan', + ) + + # Be explicit about fields + _flags = None + _scan = None + + def _parameters(self, is_press): + """The parameters to pass to ``SendInput`` to generate this key. + + :param bool is_press: Whether to generate a press event. + + :return: all arguments to pass to ``SendInput`` for this key + + :rtype: dict + + :raise ValueError: if this key is a unicode character that cannot be + represented by a single UTF-16 value + """ + if self.vk: + vk = self.vk + scan = self._scan \ + or MapVirtualKey(vk, MapVirtualKey.MAPVK_VK_TO_VSC) + flags = 0 + elif ord(self.char) > 0xFFFF: + raise ValueError + else: + res = VkKeyScan(self.char) + if (res >> 8) & 0xFF == 0: + vk = res & 0xFF + scan = self._scan \ + or MapVirtualKey(vk, MapVirtualKey.MAPVK_VK_TO_VSC) + flags = 0 + else: + vk = 0 + scan = ord(self.char) + flags = KEYBDINPUT.UNICODE + state_flags = (KEYBDINPUT.KEYUP if not is_press else 0) + return dict( + dwFlags=(self._flags or 0) | flags | state_flags, + wVk=vk, + wScan=scan) + + @classmethod + def _from_ext(cls, vk, **kwargs): + """Creates an extended key code. + + :param vk: The virtual key code. + + :param kwargs: Any other parameters to pass. + + :return: a key code + """ + return cls.from_vk(vk, _flags=KEYBDINPUT.EXTENDEDKEY, **kwargs) + + +# pylint: disable=W0212 +class Key(enum.Enum): + alt = KeyCode.from_vk(VK.MENU) + alt_l = KeyCode.from_vk(VK.LMENU) + alt_r = KeyCode._from_ext(VK.RMENU) + alt_gr = KeyCode.from_vk(VK.RMENU) + backspace = KeyCode.from_vk(VK.BACK) + caps_lock = KeyCode.from_vk(VK.CAPITAL) + cmd = KeyCode.from_vk(VK.LWIN) + cmd_l = KeyCode.from_vk(VK.LWIN) + cmd_r = KeyCode.from_vk(VK.RWIN) + ctrl = KeyCode.from_vk(VK.CONTROL) + ctrl_l = KeyCode.from_vk(VK.LCONTROL) + ctrl_r = KeyCode._from_ext(VK.RCONTROL) + delete = KeyCode._from_ext(VK.DELETE) + down = KeyCode._from_ext(VK.DOWN) + end = KeyCode._from_ext(VK.END) + enter = KeyCode.from_vk(VK.RETURN) + esc = KeyCode.from_vk(VK.ESCAPE) + f1 = KeyCode.from_vk(VK.F1) + f2 = KeyCode.from_vk(VK.F2) + f3 = KeyCode.from_vk(VK.F3) + f4 = KeyCode.from_vk(VK.F4) + f5 = KeyCode.from_vk(VK.F5) + f6 = KeyCode.from_vk(VK.F6) + f7 = KeyCode.from_vk(VK.F7) + f8 = KeyCode.from_vk(VK.F8) + f9 = KeyCode.from_vk(VK.F9) + f10 = KeyCode.from_vk(VK.F10) + f11 = KeyCode.from_vk(VK.F11) + f12 = KeyCode.from_vk(VK.F12) + f13 = KeyCode.from_vk(VK.F13) + f14 = KeyCode.from_vk(VK.F14) + f15 = KeyCode.from_vk(VK.F15) + f16 = KeyCode.from_vk(VK.F16) + f17 = KeyCode.from_vk(VK.F17) + f18 = KeyCode.from_vk(VK.F18) + f19 = KeyCode.from_vk(VK.F19) + f20 = KeyCode.from_vk(VK.F20) + f21 = KeyCode.from_vk(VK.F21) + f22 = KeyCode.from_vk(VK.F22) + f23 = KeyCode.from_vk(VK.F23) + f24 = KeyCode.from_vk(VK.F24) + home = KeyCode._from_ext(VK.HOME) + left = KeyCode._from_ext(VK.LEFT) + page_down = KeyCode._from_ext(VK.NEXT) + page_up = KeyCode._from_ext(VK.PRIOR) + right = KeyCode._from_ext(VK.RIGHT) + shift = KeyCode.from_vk(VK.LSHIFT) + shift_l = KeyCode.from_vk(VK.LSHIFT) + shift_r = KeyCode.from_vk(VK.RSHIFT) + space = KeyCode.from_vk(VK.SPACE, char=' ') + tab = KeyCode.from_vk(VK.TAB) + up = KeyCode._from_ext(VK.UP) + + media_play_pause = KeyCode._from_ext(VK.MEDIA_PLAY_PAUSE) + media_stop = KeyCode._from_ext(VK.MEDIA_STOP) + media_volume_mute = KeyCode._from_ext(VK.VOLUME_MUTE) + media_volume_down = KeyCode._from_ext(VK.VOLUME_DOWN) + media_volume_up = KeyCode._from_ext(VK.VOLUME_UP) + media_previous = KeyCode._from_ext(VK.MEDIA_PREV_TRACK) + media_next = KeyCode._from_ext(VK.MEDIA_NEXT_TRACK) + + insert = KeyCode._from_ext(VK.INSERT) + menu = KeyCode.from_vk(VK.APPS) + num_lock = KeyCode._from_ext(VK.NUMLOCK) + pause = KeyCode.from_vk(VK.PAUSE) + print_screen = KeyCode._from_ext(VK.SNAPSHOT) + scroll_lock = KeyCode.from_vk(VK.SCROLL) +# pylint: enable=W0212 + + +class Controller(_base.Controller): + _KeyCode = KeyCode + _Key = Key + + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + + def _handle(self, key, is_press): + try: + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.KEYBOARD, + value=INPUT_union( + ki=KEYBDINPUT(**key._parameters(is_press))))), + ctypes.sizeof(INPUT)) + except ValueError: + # If key._parameters raises ValueError, the key is a unicode + # characters outsice of the range of a single UTF-16 value, and we + # must break it up into its surrogates + byte_data = bytearray(key.char.encode('utf-16le')) + surrogates = [ + byte_data[i] | (byte_data[i + 1] << 8) + for i in range(0, len(byte_data), 2)] + + state_flags = KEYBDINPUT.UNICODE \ + | (KEYBDINPUT.KEYUP if not is_press else 0) + + SendInput( + len(surrogates), + (INPUT * len(surrogates))(*( + INPUT( + INPUT.KEYBOARD, + INPUT_union( + ki=KEYBDINPUT( + dwFlags=state_flags, + wScan=scan))) + for scan in surrogates)), + ctypes.sizeof(INPUT)) + + +class Listener(ListenerMixin, _base.Listener): + #: The Windows hook ID for low level keyboard events, ``WH_KEYBOARD_LL`` + _EVENTS = 13 + + _WM_INPUTLANGCHANGE = 0x0051 + _WM_KEYDOWN = 0x0100 + _WM_KEYUP = 0x0101 + _WM_SYSKEYDOWN = 0x0104 + _WM_SYSKEYUP = 0x0105 + + # A bit flag attached to messages indicating that the payload is an actual + # UTF-16 character code + _UTF16_FLAG = 0x1000 + + # A bit flag attached to messages indicating that the event was injected + _INJECTED_FLAG = 0x2000 + + # A special virtual key code designating unicode characters + _VK_PACKET = 0xE7 + + #: The messages that correspond to a key press + _PRESS_MESSAGES = (_WM_KEYDOWN, _WM_SYSKEYDOWN) + + #: The messages that correspond to a key release + _RELEASE_MESSAGES = (_WM_KEYUP, _WM_SYSKEYUP) + + #: Additional window messages to propagate to the subclass handler. + _WM_NOTIFICATIONS = ( + _WM_INPUTLANGCHANGE, + ) + + #: A mapping from keysym to special key + _SPECIAL_KEYS = { + key.value.vk: key + for key in Key} + + _HANDLED_EXCEPTIONS = ( + SystemHook.SuppressException,) + + class _KBDLLHOOKSTRUCT(ctypes.Structure): + """Contains information about a mouse event passed to a + ``WH_KEYBOARD_LL`` hook procedure, ``LowLevelKeyboardProc``. + """ + LLKHF_INJECTED = 0x00000010 + LLKHF_LOWER_IL_INJECTED = 0x00000002 + _fields_ = [ + ('vkCode', wintypes.DWORD), + ('scanCode', wintypes.DWORD), + ('flags', wintypes.DWORD), + ('time', wintypes.DWORD), + ('dwExtraInfo', ctypes.c_void_p)] + + #: A pointer to a :class:`KBDLLHOOKSTRUCT` + _LPKBDLLHOOKSTRUCT = ctypes.POINTER(_KBDLLHOOKSTRUCT) + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._translator = KeyTranslator() + self._event_filter = self._options.get( + 'event_filter', + lambda msg, data: True) + + def _convert(self, code, msg, lpdata): + if code != SystemHook.HC_ACTION: + return + + data = ctypes.cast(lpdata, self._LPKBDLLHOOKSTRUCT).contents + is_packet = data.vkCode == self._VK_PACKET + injected = (data.flags & (0 + | self._KBDLLHOOKSTRUCT.LLKHF_INJECTED + | self._KBDLLHOOKSTRUCT.LLKHF_LOWER_IL_INJECTED)) != 0 + message = (msg + | (self._UTF16_FLAG if is_packet else 0) + | (self._INJECTED_FLAG if injected else 0)) + + # Suppress further propagation of the event if it is filtered + if self._event_filter(msg, data) is False: + return None + elif is_packet: + return (message, data.scanCode) + else: + return (message, data.vkCode) + + @AbstractListener._emitter + def _process(self, wparam, lparam): + msg = wparam + vk = lparam + + # If the key has the UTF-16 flag, we treat it as a unicode character, + # otherwise convert the event to a KeyCode; this may fail, and in that + # case we pass None + is_utf16 = msg & self._UTF16_FLAG + injected = bool(msg & self._INJECTED_FLAG) + message = msg & ~(self._UTF16_FLAG | self._INJECTED_FLAG) + if is_utf16: + scan = vk + key = KeyCode.from_char(six.unichr(scan)) + else: + try: + key = self._event_to_key(msg, vk) + except OSError: + key = None + + if message in self._PRESS_MESSAGES: + self.on_press(key, injected) + + elif message in self._RELEASE_MESSAGES: + self.on_release(key, injected) + + # pylint: disable=R0201 + @contextlib.contextmanager + def _receive(self): + """An empty context manager; we do not need to fake keyboard events. + """ + yield + # pylint: enable=R0201 + + def _on_notification(self, code, wparam, lparam): + """Receives ``WM_INPUTLANGCHANGE`` and updates the cached layout. + """ + if code == self._WM_INPUTLANGCHANGE: + self._translator.update_layout() + + def _event_to_key(self, msg, vk): + """Converts an :class:`_KBDLLHOOKSTRUCT` to a :class:`KeyCode`. + + :param msg: The message received. + + :param vk: The virtual key code to convert. + + :return: a :class:`pynput.keyboard.KeyCode` + + :raises OSError: if the message and data could not be converted + """ + # If the virtual key code corresponds to a Key value, we prefer that + if vk in self._SPECIAL_KEYS: + return self._SPECIAL_KEYS[vk] + else: + return KeyCode(**self._translate( + vk, + msg in self._PRESS_MESSAGES)) + + def _translate(self, vk, is_press): + """Translates a virtual key code to a parameter list passable to + :class:`pynput.keyboard.KeyCode`. + + :param int vk: The virtual key code. + + :param bool is_press: Whether this is a press event. + + :return: a parameter list to the :class:`pynput.keyboard.KeyCode` + constructor + """ + return self._translator(vk, is_press) + + def canonical(self, key): + # If the key has a scan code, and we can find the character for it, + # return that, otherwise call the super class + scan = getattr(key, '_scan', None) + if scan is not None: + char = self._translator.char_from_scan(scan) + if char is not None: + return KeyCode.from_char(char) + + return super(Listener, self).canonical(key) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_xorg.py b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_xorg.py new file mode 100644 index 0000000..7011a5a --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/keyboard/_xorg.py @@ -0,0 +1,667 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The keyboard implementation for *Xorg*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +# pylint: disable=W0611 +try: + import pynput._util.xorg +except Exception as e: + raise ImportError('failed to acquire X connection: {}'.format(str(e)), e) +# pylint: enable=W0611 + +import enum +import threading + +import Xlib.display +import Xlib.ext +import Xlib.ext.xtest +import Xlib.X +import Xlib.XK +import Xlib.protocol +import Xlib.keysymdef.xkb + +from pynput._util import NotifierMixin +from pynput._util.xorg import ( + alt_mask, + alt_gr_mask, + char_to_keysym, + display_manager, + index_to_shift, + keyboard_mapping, + ListenerMixin, + numlock_mask, + shift_to_index, + symbol_to_keysym) +from pynput._util.xorg_keysyms import ( + CHARS, + DEAD_KEYS, + KEYPAD_KEYS, + KEYSYMS, + SYMBOLS) +from . import _base + + +class KeyCode(_base.KeyCode): + _PLATFORM_EXTENSIONS = ( + # The symbol name for this key + '_symbol', + ) + + # Be explicit about fields + _symbol = None + + @classmethod + def _from_symbol(cls, symbol, **kwargs): + """Creates a key from a symbol. + + :param str symbol: The symbol name. + + :return: a key code + """ + # First try simple translation + keysym = Xlib.XK.string_to_keysym(symbol) + if keysym: + return cls.from_vk(keysym, _symbol=symbol, **kwargs) + + # If that fails, try checking a module attribute of Xlib.keysymdef.xkb + if not keysym: + # pylint: disable=W0702; we want to ignore errors + try: + symbol = 'XK_' + symbol + return cls.from_vk( + getattr(Xlib.keysymdef.xkb, symbol, 0), + _symbol=symbol, + **kwargs) + except: + return cls.from_vk( + SYMBOLS.get(symbol, (0,))[0], + _symbol=symbol, + **kwargs) + # pylint: enable=W0702 + + @classmethod + def _from_media(cls, name, **kwargs): + """Creates a media key from a partial name. + + :param str name: The name. The actual symbol name will be this string + with ``'XF86_Audio'`` prepended. + + :return: a key code + """ + return cls._from_symbol('XF86_Audio' + name, **kwargs) + + +# pylint: disable=W0212 +class Key(enum.Enum): + # Default keys + alt = KeyCode._from_symbol('Alt_L') + alt_l = KeyCode._from_symbol('Alt_L') + alt_r = KeyCode._from_symbol('Alt_R') + alt_gr = KeyCode._from_symbol('Mode_switch') + backspace = KeyCode._from_symbol('BackSpace') + caps_lock = KeyCode._from_symbol('Caps_Lock') + cmd = KeyCode._from_symbol('Super_L') + cmd_l = KeyCode._from_symbol('Super_L') + cmd_r = KeyCode._from_symbol('Super_R') + ctrl = KeyCode._from_symbol('Control_L') + ctrl_l = KeyCode._from_symbol('Control_L') + ctrl_r = KeyCode._from_symbol('Control_R') + delete = KeyCode._from_symbol('Delete') + down = KeyCode._from_symbol('Down') + end = KeyCode._from_symbol('End') + enter = KeyCode._from_symbol('Return') + esc = KeyCode._from_symbol('Escape') + f1 = KeyCode._from_symbol('F1') + f2 = KeyCode._from_symbol('F2') + f3 = KeyCode._from_symbol('F3') + f4 = KeyCode._from_symbol('F4') + f5 = KeyCode._from_symbol('F5') + f6 = KeyCode._from_symbol('F6') + f7 = KeyCode._from_symbol('F7') + f8 = KeyCode._from_symbol('F8') + f9 = KeyCode._from_symbol('F9') + f10 = KeyCode._from_symbol('F10') + f11 = KeyCode._from_symbol('F11') + f12 = KeyCode._from_symbol('F12') + f13 = KeyCode._from_symbol('F13') + f14 = KeyCode._from_symbol('F14') + f15 = KeyCode._from_symbol('F15') + f16 = KeyCode._from_symbol('F16') + f17 = KeyCode._from_symbol('F17') + f18 = KeyCode._from_symbol('F18') + f19 = KeyCode._from_symbol('F19') + f20 = KeyCode._from_symbol('F20') + home = KeyCode._from_symbol('Home') + left = KeyCode._from_symbol('Left') + page_down = KeyCode._from_symbol('Page_Down') + page_up = KeyCode._from_symbol('Page_Up') + right = KeyCode._from_symbol('Right') + shift = KeyCode._from_symbol('Shift_L') + shift_l = KeyCode._from_symbol('Shift_L') + shift_r = KeyCode._from_symbol('Shift_R') + space = KeyCode._from_symbol('space', char=' ') + tab = KeyCode._from_symbol('Tab') + up = KeyCode._from_symbol('Up') + + media_play_pause = KeyCode._from_media('Play') + media_volume_mute = KeyCode._from_media('Mute') + media_volume_down = KeyCode._from_media('LowerVolume') + media_volume_up = KeyCode._from_media('RaiseVolume') + media_previous = KeyCode._from_media('Prev') + media_next = KeyCode._from_media('Next') + + insert = KeyCode._from_symbol('Insert') + menu = KeyCode._from_symbol('Menu') + num_lock = KeyCode._from_symbol('Num_Lock') + pause = KeyCode._from_symbol('Pause') + print_screen = KeyCode._from_symbol('Print') + scroll_lock = KeyCode._from_symbol('Scroll_Lock') +# pylint: enable=W0212 + + +class Controller(NotifierMixin, _base.Controller): + _KeyCode = KeyCode + _Key = Key + + #: The shift mask for :attr:`Key.ctrl` + CTRL_MASK = Xlib.X.ControlMask + + #: The shift mask for :attr:`Key.shift` + SHIFT_MASK = Xlib.X.ShiftMask + + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + self._display = Xlib.display.Display() + self._keyboard_mapping = None + self._borrows = {} + self._borrow_lock = threading.RLock() + + # pylint: disable=C0103; this is treated as a class scope constant, but + # we cannot set it in the class scope, as it requires a Display instance + self.ALT_MASK = alt_mask(self._display) + self.ALT_GR_MASK = alt_gr_mask(self._display) + # pylint: enable=C0103 + + def __del__(self): + if hasattr(self, '_display'): + self._display.close() + + @property + def keyboard_mapping(self): + """A mapping from *keysyms* to *key codes*. + + Each value is the tuple ``(key_code, shift_state)``. By sending an + event with the specified *key code* and shift state, the specified + *keysym* will be touched. + """ + if not self._keyboard_mapping: + self._update_keyboard_mapping() + return self._keyboard_mapping + + def _handle(self, key, is_press): + """Resolves a key identifier and sends a keyboard event. + + :param int key: The key to handle. + :param bool is_press: Whether this is a press. + """ + event = Xlib.display.event.KeyPress if is_press \ + else Xlib.display.event.KeyRelease + keysym = self._keysym(key) + + # Make sure to verify that the key was resolved + if keysym is None: + raise self.InvalidKeyException(key) + + # If the key has a virtual key code, use that immediately with + # fake_input; fake input,being an X server extension, has access to + # more internal state that we do + if key.vk is not None: + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input( + dm, + Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, + dm.keysym_to_keycode(key.vk)) + + # Otherwise use XSendEvent; we need to use this in the general case to + # work around problems with keyboard layouts + else: + try: + keycode, shift_state = self.keyboard_mapping[keysym] + self._send_key(event, keycode, shift_state) + + except KeyError: + with self._borrow_lock: + keycode, index, count = self._borrows[keysym] + self._send_key( + event, + keycode, + index_to_shift(self._display, index)) + count += 1 if is_press else -1 + self._borrows[keysym] = (keycode, index, count) + + # Notify any running listeners + self._emit('_on_fake_event', key, is_press) + + def _keysym(self, key): + """Converts a key to a *keysym*. + + :param KeyCode key: The key code to convert. + """ + return self._resolve_dead(key) if key.is_dead else None \ + or self._resolve_special(key) \ + or self._resolve_normal(key) \ + or self._resolve_borrowed(key) \ + or self._resolve_borrowing(key) + + def _send_key(self, event, keycode, shift_state): + """Sends a single keyboard event. + + :param event: The *X* keyboard event. + + :param int keycode: The calculated keycode. + + :param int shift_state: The shift state. The actual value used is + :attr:`shift_state` or'd with this value. + """ + with display_manager(self._display) as dm, self.modifiers as modifiers: + # Under certain cimcumstances, such as when running under Xephyr, + # the value returned by dm.get_input_focus is an int + window = dm.get_input_focus().focus + send_event = getattr( + window, + 'send_event', + lambda event: dm.send_event(window, event)) + send_event(event( + detail=keycode, + state=shift_state | self._shift_mask(modifiers), + time=0, + root=dm.screen().root, + window=window, + same_screen=0, + child=Xlib.X.NONE, + root_x=0, root_y=0, event_x=0, event_y=0)) + + def _resolve_dead(self, key): + """Tries to resolve a dead key. + + :param str identifier: The identifier to resolve. + """ + # pylint: disable=W0702; we want to ignore errors + try: + keysym, _ = SYMBOLS[CHARS[key.combining]] + except: + return None + # pylint: enable=W0702 + + if keysym not in self.keyboard_mapping: + return None + + return keysym + + def _resolve_special(self, key): + """Tries to resolve a special key. + + A special key has the :attr:`~KeyCode.vk` attribute set. + + :param KeyCode key: The key to resolve. + """ + if not key.vk: + return None + + return key.vk + + def _resolve_normal(self, key): + """Tries to resolve a normal key. + + A normal key exists on the keyboard, and is typed by pressing + and releasing a simple key, possibly in combination with a modifier. + + :param KeyCode key: The key to resolve. + """ + keysym = self._key_to_keysym(key) + if keysym is None: + return None + + if keysym not in self.keyboard_mapping: + return None + + return keysym + + def _resolve_borrowed(self, key): + """Tries to resolve a key by looking up the already borrowed *keysyms*. + + A borrowed *keysym* does not exist on the keyboard, but has been + temporarily added to the layout. + + :param KeyCode key: The key to resolve. + """ + keysym = self._key_to_keysym(key) + if keysym is None: + return None + + with self._borrow_lock: + if keysym not in self._borrows: + return None + + return keysym + + def _resolve_borrowing(self, key): + """Tries to resolve a key by modifying the layout temporarily. + + A borrowed *keysym* does not exist on the keyboard, but is temporarily + added to the layout. + + :param KeyCode key: The key to resolve. + """ + keysym = self._key_to_keysym(key) + if keysym is None: + return None + + mapping = self._display.get_keyboard_mapping(8, 255 - 8) + + def i2kc(index): + return index + 8 + + def kc2i(keycode): + return keycode - 8 + + #: Finds a keycode and index by looking at already used keycodes + def reuse(): + for _, (keycode, _, _) in self._borrows.items(): + keycodes = mapping[kc2i(keycode)] + + # Only the first four items are addressable by X + for index in range(4): + if not keycodes[index]: + return keycode, index + + #: Finds a keycode and index by using a new keycode + def borrow(): + for i, keycodes in enumerate(mapping): + if not any(keycodes): + return i2kc(i), 0 + + #: Finds a keycode and index by reusing an old, unused one + def overwrite(): + for keysym, (keycode, index, count) in self._borrows.items(): + if count < 1: + del self._borrows[keysym] + return keycode, index + + #: Registers a keycode for a specific key and modifier state + def register(dm, keycode, index): + i = kc2i(keycode) + + # Check for use of empty mapping with a character that has upper + # and lower forms + lower = key.char.lower() + upper = key.char.upper() + if lower != upper and len(lower) == 1 and len(upper) == 1 and all( + m == Xlib.XK.NoSymbol + for m in mapping[i]): + lower = self._key_to_keysym(KeyCode.from_char(lower)) + upper = self._key_to_keysym(KeyCode.from_char(upper)) + if lower: + mapping[i][0] = lower + self._borrows[lower] = (keycode, 0, 0) + if upper: + mapping[i][1] = upper + self._borrows[upper] = (keycode, 1, 0) + else: + mapping[i][index] = keysym + self._borrows[keysym] = (keycode, index, 0) + dm.change_keyboard_mapping(keycode, mapping[i:i + 1]) + + try: + with display_manager(self._display) as dm, self._borrow_lock as _: + # First try an already used keycode, then try a new one, and + # fall back on reusing one that is not currently pressed + register(dm, *( + reuse() or + borrow() or + overwrite())) + return keysym + + except TypeError: + return None + + def _key_to_keysym(self, key): + """Converts a character key code to a *keysym*. + + :param KeyCode key: The key code. + + :return: a keysym if found + :rtype: int or None + """ + # If the key code already has a VK, simply return it + if key.vk is not None: + return key.vk + + # If the character has no associated symbol, we try to map the + # character to a keysym + symbol = CHARS.get(key.char, None) + if symbol is None: + return char_to_keysym(key.char) + + # Otherwise we attempt to convert the symbol to a keysym + # pylint: disable=W0702; we want to ignore errors + try: + return symbol_to_keysym(symbol) + except: + try: + return SYMBOLS[symbol][0] + except: + return None + # pylint: enable=W0702 + + def _shift_mask(self, modifiers): + """The *X* modifier mask to apply for a set of modifiers. + + :param set modifiers: A set of active modifiers for which to get the + shift mask. + """ + return ( + 0 + | (self.ALT_MASK + if Key.alt in modifiers else 0) + + | (self.ALT_GR_MASK + if Key.alt_gr in modifiers else 0) + + | (self.CTRL_MASK + if Key.ctrl in modifiers else 0) + + | (self.SHIFT_MASK + if Key.shift in modifiers else 0)) + + def _update_keyboard_mapping(self): + """Updates the keyboard mapping. + """ + with display_manager(self._display) as dm: + self._keyboard_mapping = keyboard_mapping(dm) + + +@Controller._receiver +class Listener(ListenerMixin, _base.Listener): + _EVENTS = ( + Xlib.X.KeyPress, + Xlib.X.KeyRelease) + + #: A mapping from keysym to special key + _SPECIAL_KEYS = { + key.value.vk: key + for key in Key} + + #: A mapping from numeric keypad keys to keys + _KEYPAD_KEYS = { + KEYPAD_KEYS['KP_0']: KeyCode.from_char('0'), + KEYPAD_KEYS['KP_1']: KeyCode.from_char('1'), + KEYPAD_KEYS['KP_2']: KeyCode.from_char('2'), + KEYPAD_KEYS['KP_3']: KeyCode.from_char('3'), + KEYPAD_KEYS['KP_4']: KeyCode.from_char('4'), + KEYPAD_KEYS['KP_5']: KeyCode.from_char('5'), + KEYPAD_KEYS['KP_6']: KeyCode.from_char('6'), + KEYPAD_KEYS['KP_7']: KeyCode.from_char('7'), + KEYPAD_KEYS['KP_8']: KeyCode.from_char('8'), + KEYPAD_KEYS['KP_9']: KeyCode.from_char('9'), + KEYPAD_KEYS['KP_Add']: KeyCode.from_char('+'), + KEYPAD_KEYS['KP_Decimal']: KeyCode.from_char(','), + KEYPAD_KEYS['KP_Delete']: Key.delete, + KEYPAD_KEYS['KP_Divide']: KeyCode.from_char('/'), + KEYPAD_KEYS['KP_Down']: Key.down, + KEYPAD_KEYS['KP_End']: Key.end, + KEYPAD_KEYS['KP_Enter']: Key.enter, + KEYPAD_KEYS['KP_Equal']: KeyCode.from_char('='), + KEYPAD_KEYS['KP_F1']: Key.f1, + KEYPAD_KEYS['KP_F2']: Key.f2, + KEYPAD_KEYS['KP_F3']: Key.f3, + KEYPAD_KEYS['KP_F4']: Key.f4, + KEYPAD_KEYS['KP_Home']: Key.home, + KEYPAD_KEYS['KP_Insert']: Key.insert, + KEYPAD_KEYS['KP_Left']: Key.left, + KEYPAD_KEYS['KP_Multiply']: KeyCode.from_char('*'), + KEYPAD_KEYS['KP_Page_Down']: Key.page_down, + KEYPAD_KEYS['KP_Page_Up']: Key.page_up, + KEYPAD_KEYS['KP_Right']: Key.right, + KEYPAD_KEYS['KP_Space']: Key.space, + KEYPAD_KEYS['KP_Subtract']: KeyCode.from_char('-'), + KEYPAD_KEYS['KP_Tab']: Key.tab, + KEYPAD_KEYS['KP_Up']: Key.up} + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._keyboard_mapping = None + + def _run(self): + with self._receive(): + super(Listener, self)._run() + + def _initialize(self, display): + # Get the keyboard mapping to be able to translate event details to + # key codes + min_keycode = display.display.info.min_keycode + keycode_count = display.display.info.max_keycode - min_keycode + 1 + self._keyboard_mapping = display.get_keyboard_mapping( + min_keycode, keycode_count) + + def _handle_message(self, display, event, injected): + # Convert the event to a KeyCode; this may fail, and in that case we + # pass None + try: + key = self._event_to_key(display, event) + except IndexError: + key = None + + if event.type == Xlib.X.KeyPress: + self.on_press(key, injected) + + elif event.type == Xlib.X.KeyRelease: + self.on_release(key, injected) + + def _suppress_start(self, display): + display.screen().root.grab_keyboard( + self._event_mask, Xlib.X.GrabModeAsync, Xlib.X.GrabModeAsync, + Xlib.X.CurrentTime) + + def _suppress_stop(self, display): + display.ungrab_keyboard(Xlib.X.CurrentTime) + + def _on_fake_event(self, key, is_press): + """The handler for fake press events sent by the controllers. + + :param KeyCode key: The key pressed. + + :param bool is_press: Whether this is a press event. + """ + (self.on_press if is_press else self.on_release)( + self._SPECIAL_KEYS.get(key.vk, key), True) + + def _keycode_to_keysym(self, display, keycode, index): + """Converts a keycode and shift state index to a keysym. + + This method uses a simplified version of the *X* convention to locate + the correct keysym in the display table: since this method is only used + to locate special keys, alphanumeric keys are not treated specially. + + :param display: The current *X* display. + + :param keycode: The keycode. + + :param index: The shift state index. + + :return: a keysym + """ + keysym = display.keycode_to_keysym(keycode, index) + if keysym: + return keysym + elif index & 0x2: + return self._keycode_to_keysym(display, keycode, index & ~0x2) + elif index & 0x1: + return self._keycode_to_keysym(display, keycode, index & ~0x1) + else: + return 0 + + def _event_to_key(self, display, event): + """Converts an *X* event to a :class:`KeyCode`. + + :param display: The current *X* display. + + :param event: The event to convert. + + :return: a :class:`pynput.keyboard.KeyCode` + + :raises IndexError: if the key code is invalid + """ + keycode = event.detail + index = shift_to_index(display, event.state) + + # First try special keys... + keysym = self._keycode_to_keysym(display, keycode, index) + if keysym in self._SPECIAL_KEYS: + return self._SPECIAL_KEYS[keysym] + elif keysym in self._KEYPAD_KEYS: + # We must recalculate the index if numlock is active; index 1 is the + # one to use + try: + return self._KEYPAD_KEYS[ + self._keycode_to_keysym( + display, + keycode, + bool(event.state & numlock_mask(display)))] + except KeyError: + # Since we recalculated the key, this may happen + pass + + # ...then try characters... + name = KEYSYMS.get(keysym, None) + if name is not None and name in SYMBOLS: + char = SYMBOLS[name][1].upper() if index & 1 else SYMBOLS[name][1] + if char in DEAD_KEYS: + return KeyCode.from_dead(DEAD_KEYS[char], vk=keysym) + else: + return KeyCode.from_char(char, vk=keysym) + + # ...and fall back on a virtual key code + return KeyCode.from_vk(keysym) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__init__.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__init__.py new file mode 100644 index 0000000..3456629 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__init__.py @@ -0,0 +1,107 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The module containing mouse classes. + +See the documentation for more information. +""" + +# pylint: disable=C0103 +# Button, Controller and Listener are not constants + +from pynput._util import backend, Events + + +backend = backend(__name__) +Button = backend.Button +Controller = backend.Controller +Listener = backend.Listener +del backend + + +class Events(Events): + """A mouse event listener supporting synchronous iteration over the events. + + Possible events are: + + :class:`Events.Move` + The mouse was moved. + + :class:`Events.Click` + A mouse button was pressed or released. + + :class:`Events.Scroll` + The device was scrolled. + """ + _Listener = Listener + + class Move(Events.Event): + """A move event. + """ + def __init__(self, x, y, injected): + #: The X screen coordinate. + self.x = x + + #: The Y screen coordinate. + self.y = y + + #: Whether this event is synthetic. + self.injected = injected + + class Click(Events.Event): + """A click event. + """ + def __init__(self, x, y, button, pressed, injected): + #: The X screen coordinate. + self.x = x + + #: The Y screen coordinate. + self.y = y + + #: The button. + self.button = button + + #: Whether the button was pressed. + self.pressed = pressed + + #: Whether this event is synthetic. + self.injected = injected + + class Scroll(Events.Event): + """A scroll event. + """ + def __init__(self, x, y, dx, dy, injected): + #: The X screen coordinate. + self.x = x + + #: The Y screen coordinate. + self.y = y + + #: The number of horisontal steps. + self.dx = dx + + #: The number of vertical steps. + self.dy = dy + + #: Whether this event is synthetic. + self.injected = injected + + def __init__(self): + super(Events, self).__init__( + on_move=self.Move, + on_click=self.Click, + on_scroll=self.Scroll) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/__init__.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b96e4779e000c3de71d5ebbb27001c51c40a2a7f GIT binary patch literal 2812 zcmd5;&2JM|5P!SgU9Z3RNE3&U09!&(w=H%{D^)^O)s(bRN{A{2wbJ&mINlesWWDRY zUAs8)!3U%o2?RM*{s($N^e<^os0XYShe|#57V01nr_Q|HbsQ9g%BfHC?7Vq1@6F6_ z<~{#jC}atY`ai#Ie2^pLFPtPpj+sFhm>#i+K`g-%9ib)~Vl8E)1R@eDQt5#ZX&NFG zuk-zqEn>M0^89`o&I|?QhYpaZzZXTaNUYRNVo5ahAQkBtsg|rOTdUbC8&s=#R>PrM z)pLW2?b_}&kTiS{I2GTgekq$>rBn+*)AFi~8U?k$_FQeBou>4mGJ2Z}^hgMaQmg?%5^IuQh@IFht`zqkyxe0i29Fv;zFWTdh`^ z=Qw+Np$`^q+SSMjpD&{^I=Bz-xU9*b2ua+Jwgo5~QY)oPFLEQ1ZWYnfW}KF2OTI0_ zkPHzRtmr`rNRPCIHZhYm(iUNs98B6Nn4vx&EplI2(Nm#tBNSSpYP;8IHK3L*g_2L5 zb%w3SpooG%8NKk~U4~XVYYd z!RS6=N8rQo4hbbJHI@eUWBB=)f}7-tC}i>jNzKefnv)=X1B~-=Y`iSDCg&cko852`~6R3~8R4WKH-F+^>@b!=XXI{g0umT27wMXU7+j80>oW|6!a zqvF2!h9G?hR<8zWatg3n1Z;-PYe7&-!i)*V@b|$qeRNyvjP%CgIPb~Lb`2E# z_kld`kjHA__WC{Rp?ao2eyq2&z0{wW>KWTczj(a2xxKlQCYiaXB$b)v`O^z*4D8rj zNXC&&014IQ_)P{k5|(=$%KYe;eCBb4h1laNbsW>w1@j=i$WBTSgeRvZL3%bu1pSFZa%1=2`6D~sN%u2H?w-7LvZM41tpp1TePTSEWt&}2ySJ4xUyuXvE;bA+Pz!e&XFta z?Ota0NZx@m7*{|fK&fQJsT91tKSs9Q`cJGQ5rwySwlOquj_GAfcU|Uc0BNv_X){BcVw{a=6Ln7j?S$8h zd6rYwJ;KyD2nR;Sk}pIuLcyJ6{pYS1ZEDT<;X~r8f#PPgX zfyY4cXGH&JqDOi%KAdi)i$zxq6uvja}&B-b6ma+_(%9pQ?R&8(e2sfwM{?XGWcWS10Qm@-(ATxUS1e==EP{N;Y~UAf&6p(M_sULUrjHc(Uv~Zo{`3#bAH$z){|}Gy!QiV7MIau~v-~caZbi7D6cQ|H z#4jkf#Uw>3q*&@<+s#Ns=g`J1q>U8XjDf9J=rz)4*BI-J%mua3XY}G%)>wnK-{?a- zU}VwejDEChjRCalj2znajkUw;TfK*|2f1Tej5iM*5<61<5*h|68>T&}O`BY7LAmQ7 zcH6_Ib;K5P8`u_AsQ~3b_lYEuKK)z%HkxaS7rvWQ&IYW(o8YV~bQ zITgVs$-0^&teC&8<<^E#!vEOJnpcPQ(@Ld1vm;t#xKtX^blcEe=6NIp)6-^5%Yuc% z&ZX%gFoHu5EK;@@EL@yq9^V2yJNOg4?ch%^_#K+P9?iV6*r((MKN;9@XJE&|z^;$d zyCj1`$zW0_->30oH3rS8fm~Ikq43R^+KDBoyA|VGG2V&;50_TZq%`>s^dE}oVZ3m2 zXy%oFPxpP29=ekrx_;npdb`AuFbkdpIzo(l&{-YJx!7%=HsGla$Mipjv`<0(UCk}i zjv!+Pt&d1%)+m}W{<^<4~^f78Yf(-;xffX(XUo;3%~)v0vg zKjDCaHc8{cH%e-6#iev(#%wEQG+Yt}D3<#*CFeBPMs}+ldI{6~y}Gzb$z-qeUFy5~ z>h*PZ(_5Z|Dni7~+R-Y>MfZK52Dk3IQqGz#UdHW!wl%y*q`zRnv(@2sg zwxo(;Fwpsw?{_0=-%5%Z&0K^hV&pYqiPZYVUSi3bOKYwkyPJOMNioFhVhCpzqo_=% z{u5$}53`dg>7qZ(^F(8m89n}+=DG+w{INH>8Irw}y;`}O-n!BZq%l>Pfxkj0>WmEa zg5uE|@xaQH!RUJC)VWwCG!REZj~$q{4wn@hj_WxXk5^!(rCIMV{ZKc%UY$U!276F5 zXPJdyjytd;P(@$e!mSk;=9OxK8I3e^Mf2&?oRps*91boOZ;xlUCN8)b1iV!`P|5i&iqiXYI=HMh^_1PMK zp}8}nIOIF?2Pp@z+!ylU92;1;6vX|H^4odkU$>sPx%R#CjUDe-?rc5rg-gi3z2O@a ziL{c!N4MflvnJdVC%4jR(-O2ubD(S0GR^xYntA2HMrHFhK>m68SG)gd-#_mAVCM%D zA8cC4zx?sm6APP8ARNiARNxdo6$*SE9pcvW%K3PNSFu1Dk0@{M1|Ji1@w1^?;}idh z`eV!pGQ{9D{zhk9embFKC^y7^QUAD0c@AO4OiWeIKz8IYXX9s-88WJ0blH%yWtPu9 zwgsUG3Z77}TV7W#h%ktpv5vpo#KxlCBkVPWNWMK-)kijQ_B_=igJP^PD2lTy4ZRE~6yRF0xtJ%iyF z*(9ayQDI1~MA&%T7C~wt&9N%;rp8KQTB%F6BVs0JUY*;>fDw?8cs*1KLQ6qjUc)`snN_Bpk- z%sEBNE23;|E(MK?!2Cs>jw7KJG_ZA4a zE))pOxIkz)Aw#Y-n=Kc;Mh)4s;A$&Fg$y=<6j&Iww$>qUVzUp)o8;gnpx{zw417}v zJS4WH9>GH%TVT5pov3>a5~R0PBuI7QZf8kG3L13=BsuVjRMr^NJ&%u-0^ipu9hodW zv~tr4xGkewYHR(t;~fu5OUw}AZnxC92GpCIqVft*pj7H_@OC+i2KKvG8Q8hd|M0Bn z_vQqpdw(EK@DsqF??w~#m3$WlRv{e7{FJ^S!?V&SJsz#j>QeXjsEqhan%v|ayYY9B zx1@4~U*^vcnb9b+DA#?jlRzRWcpi^H`zs0b&C-*kuRBoY`+#&u9wifvzsGPyd|#is z+E-E+nAj&OzZLXRq}Wjm2y%vh=%5fe7N=l;c#xBC<9*c7zUBSYY(vvZ*HAD-D%}tv zTq`BF9N$Y5Lf6d?($5#EIYP~GYBXwSzX)v-Jm-X%^aG*{NOdUwji7lR9k-5#%7|(* zy_8UsBQT<=eyS?&UXG);NIldSQ~f_G{;){XG#cNqNWG<0UvlfxmSl3vQhzeJZK;1v z@}#;v)R)}5v?Y@qT-q2ZP4Gs$Kh&qyDXzMa_6#O53g;b zlq@~DjzPpjY!;<=-9}}Wqh>7*2{4`gpl-r*!I=v8?N=NtD91Q6R7EK}1{)ibHF9!h z0YZ7K%e_6rq0{$xV=Vm9F>^*YqZ8@fjOk4k0Rd%AD)~gfphSa!V>M8&=hQG+tRpB8 zsmaAR>QS^kmTD)@wC~Q&9pHCwwDdNwWdA9QP}L(AU6A z8ak^wc8NluQt33WvrC=j8Jf#8VFPw4!mZi^4SDc0y%#7D<3oe@U* z1XYx591Bb{8EJ=jf+p%qdZc>MEI-QEoHEkoh_eW|1I?n(5G9fzMQ9lk5ENHOAeFPM z3E)NAt8>)^b)Eaax0Kvx5|iG{i9T6 z1Pqc;OOZSTIjrp`I!p^h_@X%XgP2Ms5i~GEY9TZ<)GeRnsB-ypg>HSdPKL_gp^G7% zkE4@qo9ioQ+jjg8N*OK<8bc%ge@`i8y!a@slvYa43yJd2%YHw5W#CN6Xmr}GaD|Bd zdJJWhhHH<6*tT*ZG>N`84f_Za@_1%$rAme19@otMzfq|P$HDm!OefW^#!<)8hD;3?wcL*@!Y3qW)@C0w2K9KOnlh+~3Ls3iR~Szp>?Seedns2_p~4sykS z@1f7lz;y!0Lv{n!-`+>@oS}0gykHQyIUxfH5xvp91b51*TSjnYfcy#2#I=d2UkoNxDlvQsXbF#ZyoHDrUAK<@bdQngca*(Yj02 zRd88?0zce{G0(M?K;r*B-1_jEd4D-5;c-Oh2+hAwwYg&^v*4A&u%yj6!$GKz?cPCz zU)BrPm&HDb3WXj1K7in)0wQ)WaGxZE5lCBnQLLC2sv}=tc2##0_EY!tw#>j!j0)z4 zixK&RX>jgW#STSIA`jw8hddo0Amnw*rjR3z;J2oCfGE9k>g35k`|fv7oI3sLYlly3 z2d6x*=8lby;);u#ubMbfcAbisFFVyyX78Jv7==a~&WuZc59}Y+YbNzj>g1!gyU*|L ztGbpoaF_V~_4hU2RWzJqlgNc-^;!!D6JRZRl z&njR0<&yKMx#U?|x9hp>|30Ez>A8|F$4#XidlQE|Z{WN0J?GPNJ!h%((DlrvZu_-U zJ}}qg;nYh$?QugHQs&Y>iCumsp_Jq2)8~6|#2Di0(G?c)MDhPI$`_!5Di2-HT;%j- zl^HQ3Jl1WPwiT1bVOv{ z%AhAhj8;0(m*GBf$A=H$EB+KU1fRc#rj-;o+*-XNr*|o*YsFC#z+E5T*N zB#Sd#uMPLgbCZQE9!$Z-Ctrp&JO>p<6hC_%%_{Sy*GPv@R!?eZClv%?TcBIezt$}ed}k| z-`Srhc;~ki%BJ$dpCadm4)2Sk8-;{>f3#T-RaxA z9LMyFiObmsX(iKtdFp!NPWtJ4gPX3s{LahQXKtzsgU{aEu=!fyox+Xu%^eFHM(%AK zx_0)Rvo|*1JhZSee{aLqMU-})`HhmuZ2w|817I$l>wK7b_HZHvv5k)(8&0iWGt2t7 zugc7_ibWLJNL1o#(Vt4@kgSBjeoZgvLeFoh=Jh&?UW>Ju@+XJYdqdklkM||F-&fGc z(iD9J*;8q*m0&nyYxT){dHG`9Gc8V)DxnIvbSduZ$*W+AqnIkL>9tbM1SRsa;wEqq zM>1h4?#uK+dE@W}eh$EBkweP=`=l)F@dXQSH_Fp`G<;}jg%?yDOgDD?NiT%4)u_Kya(|3;yXAmM)jz}Ln6 literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_darwin.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_darwin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be6d0429780f703b830a0b70deaaa27fd161dd1c GIT binary patch literal 8631 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 W$#yecg_#BEm)W0YzasEKhyEW+@gb4` literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_dummy.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_dummy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e8aba44bc2e1392baedce42277b5456f1950832 GIT binary patch literal 403 zcmXv~Jx{|h5VeyON}vlfgV#zBLs=06uvDs;I-o3(lbjku{2|*Zgg?S>;IF{On3ahQ z=z!D-hmRYc-rYUj-Mi<}C`LZ?=TmhZBJ|oP{}KF=)t)C0s6;6$aT(ND1Zg0`G!#)9 zVbq4>=-$Nhid!O7+0;M^B^~3^5=P2Kh?a1nYY^b8jw_kO@zjxmNvRykfixD%eUdk> z*D2$;ToCTaEw5|ROAO-{2$L;=y8?7S!Y1(>_GgX5ZsV+RPRTAl_gjssYcSn##;pSh z=5jpfHnXf$MV57gEN2#s_lZo@!@$EMT6sk4D=MU;7ltokLg(Bl&E1SOvZ%n&^VyUx zK`v>{bE;ccDS4b6O{nD#4m2xn*aEC?NZmLpls81PALof~*Ta+Fx15@7zo@_3?s|9+ UF~%Px!qL|b!iO)2nk`@c23v@DdjJ3c literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_win32.cpython-312.pyc b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/__pycache__/_win32.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b11ac737126ed21280ab15f4475e619f68e21a6d GIT binary patch literal 9508 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 bx$gA#KIi?^EA{RdKdsx|+a-S5h57#hM~x6h literal 0 HcmV?d00001 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_base.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_base.py new file mode 100644 index 0000000..186a7d7 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_base.py @@ -0,0 +1,281 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +This module contains the base implementation. + +The actual interface to mouse classes is defined here, but the implementation +is located in a platform dependent module. +""" + +# pylint: disable=R0903 +# We implement stubs + +import enum + +from pynput._util import AbstractListener, prefix +from pynput import _logger + + +class Button(enum.Enum): + """The various buttons. + + The actual values for these items differ between platforms. Some + platforms may have additional buttons, but these are guaranteed to be + present everywhere. + """ + #: An unknown button was pressed + unknown = 0 + + #: The left button + left = 1 + + #: The middle button + middle = 2 + + #: The right button + right = 3 + + +class Controller(object): + """A controller for sending virtual mouse events to the system. + """ + def __init__(self): + self._log = _logger(self.__class__) + + @property + def position(self): + """The current position of the mouse pointer. + + This is the tuple ``(x, y)``, and setting it will move the pointer. + """ + return self._position_get() + + @position.setter + def position(self, pos): + self._position_set(pos) + + def scroll(self, dx, dy): + """Sends scroll events. + + :param int dx: The horizontal scroll. The units of scrolling is + undefined. + + :param int dy: The vertical scroll. The units of scrolling is + undefined. + + :raises ValueError: if the values are invalid, for example out of + bounds + """ + self._scroll(dx, dy) + + def press(self, button): + """Emits a button press event at the current position. + + :param Button button: The button to press. + """ + self._press(button) + + def release(self, button): + """Emits a button release event at the current position. + + :param Button button: The button to release. + """ + self._release(button) + + def move(self, dx, dy): + """Moves the mouse pointer a number of pixels from its current + position. + + :param int dx: The horizontal offset. + + :param int dy: The vertical offset. + + :raises ValueError: if the values are invalid, for example out of + bounds + """ + self.position = tuple(sum(i) for i in zip(self.position, (dx, dy))) + + def click(self, button, count=1): + """Emits a button click event at the current position. + + The default implementation sends a series of press and release events. + + :param Button button: The button to click. + + :param int count: The number of clicks to send. + """ + with self as controller: + for _ in range(count): + controller.press(button) + controller.release(button) + + def __enter__(self): + """Begins a series of clicks. + + In the default :meth:`click` implementation, the return value of this + method is used for the calls to :meth:`press` and :meth:`release` + instead of ``self``. + + The default implementation is a no-op. + """ + return self + + def __exit__(self, exc_type, value, traceback): + """Ends a series of clicks. + """ + pass + + def _position_get(self): + """The implementation of the getter for :attr:`position`. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _position_set(self, pos): + """The implementation of the setter for :attr:`position`. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _scroll(self, dx, dy): + """The implementation of the :meth:`scroll` method. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _press(self, button): + """The implementation of the :meth:`press` method. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + def _release(self, button): + """The implementation of the :meth:`release` method. + + This is a platform dependent implementation. + """ + raise NotImplementedError() + + +# pylint: disable=W0223; This is also an abstract class +class Listener(AbstractListener): + """A listener for mouse events. + + Instances of this class can be used as context managers. This is equivalent + to the following code:: + + listener.start() + try: + listener.wait() + with_statements() + finally: + listener.stop() + + This class inherits from :class:`threading.Thread` and supports all its + methods. It will set :attr:`daemon` to ``True`` when created. + + All callback arguments are optional; a callback may take less arguments + than actually passed, but not more, unless they are optional. + + :param callable on_move: The callback to call when mouse move events occur. + + It will be called with the arguments ``(x, y, injected)``, where ``(x, + y)`` is the new pointer position and ``injected`` whether the event was + injected and thus not generated by an actual input device. If this + callback raises :class:`StopException` or returns ``False``, the + listener is stopped. + + Please note that not all backends support ``injected`` and will always + set it to ``False``. + + :param callable on_click: The callback to call when a mouse button is + clicked. + + It will be called with the arguments ``(x, y, button, pressed, + injected)``, where ``(x, y)`` is the new pointer position, ``button`` + is one of the :class:`Button`, ``pressed`` is whether the button was + pressed and ``injected`` whether the event was injected and thus not + generated by an actual input device. + + If this callback raises :class:`StopException` or returns ``False``, + the listener is stopped. + + Please note that not all backends support ``injected`` and will always + set it to ``False``. + + :param callable on_scroll: The callback to call when mouse scroll + events occur. + + It will be called with the arguments ``(x, y, dx, dy, injected)``, + where ``(x, y)`` is the new pointer position, and ``(dx, dy)`` is the + scroll vector and ``injected`` whether the event was injected and thus + not generated by an actual input device. + + If this callback raises :class:`StopException` or returns ``False``, + the listener is stopped. + + Please note that not all backends support ``injected`` and will always + set it to ``False``. + + :param bool suppress: Whether to suppress events. Setting this to ``True`` + will prevent the input events from being passed to the rest of the + system. + + :param kwargs: Any non-standard platform dependent options. These should be + prefixed with the platform name thus: ``darwin_``, ``xorg_`` or + ``win32_``. + + Supported values are: + + ``darwin_intercept`` + A callable taking the arguments ``(event_type, event)``, where + ``event_type`` is any mouse related event type constant, and + ``event`` is a ``CGEventRef``. + + This callable can freely modify the event using functions like + ``Quartz.CGEventSetIntegerValueField``. If this callable does not + return the event, the event is suppressed system wide. + + ``win32_event_filter`` + A callable taking the arguments ``(msg, data)``, where ``msg`` is + the current message, and ``data`` associated data as a + `MSLLHOOKSTRUCT `_. + + If this callback returns ``False``, the event will not + be propagated to the listener callback. + + If ``self.suppress_event()`` is called, the event is suppressed + system wide. + """ + def __init__(self, on_move=None, on_click=None, on_scroll=None, + suppress=False, **kwargs): + self._log = _logger(self.__class__) + option_prefix = prefix(Listener, self.__class__) + self._options = { + key[len(option_prefix):]: value + for key, value in kwargs.items() + if key.startswith(option_prefix)} + super(Listener, self).__init__( + on_move=self._wrap(on_move, 3), + on_click=self._wrap(on_click, 5), + on_scroll=self._wrap(on_scroll, 5), + suppress=suppress) +# pylint: enable=W0223 diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_darwin.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_darwin.py new file mode 100644 index 0000000..b5dbe3c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_darwin.py @@ -0,0 +1,212 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The mouse implementation for *macOS*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +import enum +import Quartz + +from AppKit import NSEvent + +from pynput._util.darwin import ( + ListenerMixin) +from . import _base + + +def _button_value(base_name, mouse_button): + """Generates the value tuple for a :class:`Button` value. + + :param str base_name: The base name for the button. This should be a string + like ``'kCGEventLeftMouse'``. + + :param int mouse_button: The mouse button ID. + + :return: a value tuple + """ + return ( + tuple( + getattr(Quartz, '%sMouse%s' % (base_name, name)) + for name in ('Down', 'Up', 'Dragged')), + mouse_button) + + +class Button(enum.Enum): + """The various buttons. + """ + unknown = None + left = _button_value('kCGEventLeft', 0) + middle = _button_value('kCGEventOther', 2) + right = _button_value('kCGEventRight', 1) + + +class Controller(_base.Controller): + #: The scroll speed + _SCROLL_SPEED = 10 + + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + self._click = None + self._drag_button = None + + def _position_get(self): + pos = NSEvent.mouseLocation() + + return pos.x, Quartz.CGDisplayPixelsHigh(0) - pos.y + + def _position_set(self, pos): + try: + (_, _, mouse_type), mouse_button = self._drag_button.value + except AttributeError: + mouse_type = Quartz.kCGEventMouseMoved + mouse_button = 0 + + Quartz.CGEventPost( + Quartz.kCGHIDEventTap, + Quartz.CGEventCreateMouseEvent( + None, + mouse_type, + pos, + mouse_button)) + + def _scroll(self, dx, dy): + dx = int(dx) + dy = int(dy) + + Quartz.CGEventPost( + Quartz.kCGHIDEventTap, + Quartz.CGEventCreateScrollWheelEvent( + None, + Quartz.kCGScrollEventUnitPixel, + 2, + dy * self._SCROLL_SPEED, + dx * self._SCROLL_SPEED)) + + def _press(self, button): + (press, _, _), mouse_button = button.value + event = Quartz.CGEventCreateMouseEvent( + None, + press, + self.position, + mouse_button) + + # If we are performing a click, we need to set this state flag + if self._click is not None: + self._click += 1 + Quartz.CGEventSetIntegerValueField( + event, + Quartz.kCGMouseEventClickState, + self._click) + + Quartz.CGEventPost(Quartz.kCGHIDEventTap, event) + + # Store the button to enable dragging + self._drag_button = button + + def _release(self, button): + (_, release, _), mouse_button = button.value + event = Quartz.CGEventCreateMouseEvent( + None, + release, + self.position, + mouse_button) + + # If we are performing a click, we need to set this state flag + if self._click is not None: + Quartz.CGEventSetIntegerValueField( + event, + Quartz.kCGMouseEventClickState, + self._click) + + Quartz.CGEventPost(Quartz.kCGHIDEventTap, event) + + if button == self._drag_button: + self._drag_button = None + + def __enter__(self): + self._click = 0 + return self + + def __exit__(self, exc_type, value, traceback): + self._click = None + + +class Listener(ListenerMixin, _base.Listener): + #: The events that we listen to + _EVENTS = ( + Quartz.CGEventMaskBit(Quartz.kCGEventMouseMoved) | + Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDragged) | + Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventRightMouseDragged) | + Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventOtherMouseDragged) | + Quartz.CGEventMaskBit(Quartz.kCGEventScrollWheel)) + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._intercept = self._options.get( + 'intercept', + None) + + def _handle_message(self, _proxy, event_type, event, _refcon, injected): + """The callback registered with *macOS* for mouse events. + + This method will call the callbacks registered on initialisation. + """ + try: + (px, py) = Quartz.CGEventGetLocation(event) + except AttributeError: + # This happens during teardown of the virtual machine + return + + # Quickly detect the most common event type + if event_type == Quartz.kCGEventMouseMoved: + self.on_move(px, py, injected) + + elif event_type == Quartz.kCGEventScrollWheel: + dx = Quartz.CGEventGetIntegerValueField( + event, + Quartz.kCGScrollWheelEventDeltaAxis2) + dy = Quartz.CGEventGetIntegerValueField( + event, + Quartz.kCGScrollWheelEventDeltaAxis1) + self.on_scroll(px, py, dx, dy, injected) + + else: + for button in Button: + try: + (press, release, drag), _ = button.value + except TypeError: + # Button.unknown cannot be enumerated + continue + + # Press and release generate click events, and drag + # generates move events + if event_type in (press, release): + self.on_click(px, py, button, event_type == press, injected) + elif event_type == drag: + self.on_move(px, py, injected) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_dummy.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_dummy.py new file mode 100644 index 0000000..c0a8a74 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_dummy.py @@ -0,0 +1,22 @@ +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +This module contains a dummy implementation. + +It cannot be used, but importing it will not raise any exceptions. +""" + +from ._base import Button, Controller, Listener diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_win32.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_win32.py new file mode 100644 index 0000000..1c0dbb5 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_win32.py @@ -0,0 +1,226 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The mouse implementation for *Windows*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + +# pylint: disable=R0903 +# We implement stubs + +import ctypes +import enum + +from ctypes import ( + windll, + wintypes) + +from pynput._util import NotifierMixin +from pynput._util.win32 import ( + INPUT, + INPUT_union, + ListenerMixin, + MOUSEINPUT, + SendInput, + SystemHook) +from . import _base + +#: A constant used as a factor when constructing mouse scroll data. +WHEEL_DELTA = 120 + + +class Button(enum.Enum): + """The various buttons. + """ + unknown = None + left = (MOUSEINPUT.LEFTUP, MOUSEINPUT.LEFTDOWN, 0) + middle = (MOUSEINPUT.MIDDLEUP, MOUSEINPUT.MIDDLEDOWN, 0) + right = (MOUSEINPUT.RIGHTUP, MOUSEINPUT.RIGHTDOWN, 0) + x1 = (MOUSEINPUT.XUP, MOUSEINPUT.XDOWN, MOUSEINPUT.XBUTTON1) + x2 = (MOUSEINPUT.XUP, MOUSEINPUT.XDOWN, MOUSEINPUT.XBUTTON2) + + +class Controller(NotifierMixin, _base.Controller): + __GetCursorPos = windll.user32.GetCursorPos + __SetCursorPos = windll.user32.SetCursorPos + + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + + def _position_get(self): + point = wintypes.POINT() + if self.__GetCursorPos(ctypes.byref(point)): + return (point.x, point.y) + else: + return None + + def _position_set(self, pos): + pos = int(pos[0]), int(pos[1]) + self.__SetCursorPos(*pos) + self._emit('on_move', *pos, True) + + def _scroll(self, dx, dy): + if dy: + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.MOUSE, + value=INPUT_union( + mi=MOUSEINPUT( + dwFlags=MOUSEINPUT.WHEEL, + mouseData=int(dy * WHEEL_DELTA))))), + ctypes.sizeof(INPUT)) + + if dx: + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.MOUSE, + value=INPUT_union( + mi=MOUSEINPUT( + dwFlags=MOUSEINPUT.HWHEEL, + mouseData=int(dx * WHEEL_DELTA))))), + ctypes.sizeof(INPUT)) + + if dx or dy: + px, py = self._position_get() + self._emit('on_scroll', px, py, dx, dy, True) + + def _press(self, button): + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.MOUSE, + value=INPUT_union( + mi=MOUSEINPUT( + dwFlags=button.value[1], + mouseData=button.value[2])))), + ctypes.sizeof(INPUT)) + + def _release(self, button): + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.MOUSE, + value=INPUT_union( + mi=MOUSEINPUT( + dwFlags=button.value[0], + mouseData=button.value[2])))), + ctypes.sizeof(INPUT)) + + +@Controller._receiver +class Listener(ListenerMixin, _base.Listener): + #: The Windows hook ID for low level mouse events, ``WH_MOUSE_LL`` + _EVENTS = 14 + + WM_LBUTTONDOWN = 0x0201 + WM_LBUTTONUP = 0x0202 + WM_MBUTTONDOWN = 0x0207 + WM_MBUTTONUP = 0x0208 + WM_MOUSEMOVE = 0x0200 + WM_MOUSEWHEEL = 0x020A + WM_MOUSEHWHEEL = 0x020E + WM_RBUTTONDOWN = 0x0204 + WM_RBUTTONUP = 0x0205 + WM_XBUTTONDOWN = 0x20B + WM_XBUTTONUP = 0x20C + + MK_XBUTTON1 = 0x0020 + MK_XBUTTON2 = 0x0040 + + XBUTTON1 = 1 + XBUTTON2 = 2 + + #: A mapping from messages to button events + CLICK_BUTTONS = { + WM_LBUTTONDOWN: (Button.left, True), + WM_LBUTTONUP: (Button.left, False), + WM_MBUTTONDOWN: (Button.middle, True), + WM_MBUTTONUP: (Button.middle, False), + WM_RBUTTONDOWN: (Button.right, True), + WM_RBUTTONUP: (Button.right, False)} + + #: A mapping from message to X button events. + X_BUTTONS = { + WM_XBUTTONDOWN: { + XBUTTON1: (Button.x1, True), + XBUTTON2: (Button.x2, True)}, + WM_XBUTTONUP: { + XBUTTON1: (Button.x1, False), + XBUTTON2: (Button.x2, False)}} + + #: A mapping from messages to scroll vectors + SCROLL_BUTTONS = { + WM_MOUSEWHEEL: (0, 1), + WM_MOUSEHWHEEL: (1, 0)} + + _HANDLED_EXCEPTIONS = ( + SystemHook.SuppressException,) + + class _MSLLHOOKSTRUCT(ctypes.Structure): + """Contains information about a mouse event passed to a ``WH_MOUSE_LL`` + hook procedure, ``MouseProc``. + """ + LLMHF_INJECTED = 0x00000001 + LLMHF_LOWER_IL_INJECTED = 0x00000002 + _fields_ = [ + ('pt', wintypes.POINT), + ('mouseData', wintypes.DWORD), + ('flags', wintypes.DWORD), + ('time', wintypes.DWORD), + ('dwExtraInfo', ctypes.c_void_p)] + + #: A pointer to a :class:`_MSLLHOOKSTRUCT` + _LPMSLLHOOKSTRUCT = ctypes.POINTER(_MSLLHOOKSTRUCT) + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + self._event_filter = self._options.get( + 'event_filter', + lambda msg, data: True) + + def _handle_message(self, code, msg, lpdata): + if code != SystemHook.HC_ACTION: + return + + data = ctypes.cast(lpdata, self._LPMSLLHOOKSTRUCT).contents + injected = data.flags & (0 + | self._MSLLHOOKSTRUCT.LLMHF_INJECTED + | self._MSLLHOOKSTRUCT.LLMHF_LOWER_IL_INJECTED) != 0 + + # Suppress further propagation of the event if it is filtered + if self._event_filter(msg, data) is False: + return + + if msg == self.WM_MOUSEMOVE: + self.on_move(data.pt.x, data.pt.y,injected) + + elif msg in self.CLICK_BUTTONS: + button, pressed = self.CLICK_BUTTONS[msg] + self.on_click(data.pt.x, data.pt.y, button, pressed, injected) + + elif msg in self.X_BUTTONS: + button, pressed = self.X_BUTTONS[msg][data.mouseData >> 16] + self.on_click(data.pt.x, data.pt.y, button, pressed, injected) + + elif msg in self.SCROLL_BUTTONS: + mx, my = self.SCROLL_BUTTONS[msg] + dd = wintypes.SHORT(data.mouseData >> 16).value // WHEEL_DELTA + self.on_scroll(data.pt.x, data.pt.y, dd * mx, dd * my, injected) diff --git a/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_xorg.py b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_xorg.py new file mode 100644 index 0000000..93b0a98 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/pynput/mouse/_xorg.py @@ -0,0 +1,184 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2024 Moses Palmér +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +""" +The keyboard implementation for *Xorg*. +""" + +# pylint: disable=C0111 +# The documentation is extracted from the base classes + + +# pylint: disable=E1101,E1102 +# We dynamically generate the Button class + +# pylint: disable=R0903 +# We implement stubs + +# pylint: disable=W0611 +try: + import pynput._util.xorg +except Exception as e: + raise ImportError('failed to acquire X connection: {}'.format(str(e)), e) +# pylint: enable=W0611 + +import enum +import Xlib.display +import Xlib.ext +import Xlib.ext.xtest +import Xlib.X +import Xlib.protocol + +from pynput._util.xorg import ( + display_manager, + ListenerMixin) +from . import _base + + +# pylint: disable=C0103 +Button = enum.Enum( + 'Button', + module=__name__, + names=[ + ('unknown', None), + ('left', 1), + ('middle', 2), + ('right', 3), + ('scroll_up', 4), + ('scroll_down', 5), + ('scroll_left', 6), + ('scroll_right', 7)] + [ + ('button%d' % i, i) + for i in range(8, 31)]) +# pylint: enable=C0103 + + +class Controller(_base.Controller): + def __init__(self, *args, **kwargs): + super(Controller, self).__init__(*args, **kwargs) + self._display = Xlib.display.Display() + + def __del__(self): + if hasattr(self, '_display'): + self._display.close() + + def _position_get(self): + with display_manager(self._display) as dm: + qp = dm.screen().root.query_pointer() + return (qp.root_x, qp.root_y) + + def _position_set(self, pos): + px, py = self._check_bounds(*pos) + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input(dm, Xlib.X.MotionNotify, x=px, y=py) + + def _scroll(self, dx, dy): + dx, dy = self._check_bounds(dx, dy) + if dy: + self.click( + button=Button.scroll_up if dy > 0 else Button.scroll_down, + count=abs(dy)) + + if dx: + self.click( + button=Button.scroll_right if dx > 0 else Button.scroll_left, + count=abs(dx)) + + def _press(self, button): + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonPress, button.value) + + def _release(self, button): + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonRelease, button.value) + + def _check_bounds(self, *args): + """Checks the arguments and makes sure they are within the bounds of a + short integer. + + :param args: The values to verify. + """ + if not all( + (-0x7fff - 1) <= number <= 0x7fff + for number in args): + raise ValueError(args) + else: + return tuple(int(p) for p in args) + + +class Listener(ListenerMixin, _base.Listener): + #: A mapping from button values to scroll directions + _SCROLL_BUTTONS = { + Button.scroll_up.value: (0, 1), + Button.scroll_down.value: (0, -1), + Button.scroll_right.value: (1, 0), + Button.scroll_left.value: (-1, 0)} + + _EVENTS = ( + Xlib.X.ButtonPressMask, + Xlib.X.ButtonReleaseMask) + + def __init__(self, *args, **kwargs): + super(Listener, self).__init__(*args, **kwargs) + + def _handle_message(self, dummy_display, event, injected): + px = event.root_x + py = event.root_y + + if event.type == Xlib.X.ButtonPress: + # Scroll events are sent as button presses with the scroll + # button codes + scroll = self._SCROLL_BUTTONS.get(event.detail, None) + if scroll: + self.on_scroll( + px, py, scroll[0], scroll[1], injected) + else: + self.on_click( + px, py, self._button(event.detail), True, injected) + + elif event.type == Xlib.X.ButtonRelease: + # Send an event only if this was not a scroll event + if event.detail not in self._SCROLL_BUTTONS: + self.on_click( + px, py, self._button(event.detail), False, injected) + + else: + self.on_move(px, py, injected) + + + def _suppress_start(self, display): + display.screen().root.grab_pointer( + True, self._event_mask, Xlib.X.GrabModeAsync, Xlib.X.GrabModeAsync, + 0, 0, Xlib.X.CurrentTime) + + def _suppress_stop(self, display): + display.ungrab_pointer(Xlib.X.CurrentTime) + + # pylint: disable=R0201 + def _button(self, detail): + """Creates a mouse button from an event detail. + + If the button is unknown, :attr:`Button.unknown` is returned. + + :param detail: The event detail. + + :return: a button + """ + try: + return Button(detail) + except ValueError: + return Button.unknown + # pylint: enable=R0201 diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/LICENSE b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/LICENSE new file mode 100644 index 0000000..20b7285 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + {signature of Ty Coon}, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/METADATA new file mode 100644 index 0000000..1521f50 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/METADATA @@ -0,0 +1,158 @@ +Metadata-Version: 2.1 +Name: python-xlib +Version: 0.33 +Summary: Python X Library +Home-page: https://github.com/python-xlib/python-xlib +Author: Peter Liljenberg +Author-email: petli@ctrl-c.liu.se +License: LGPLv2+ +Download-URL: https://github.com/python-xlib/python-xlib/releases +Keywords: windows,x,x11,xlib +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: X11 Applications +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: User Interfaces +Requires-Dist: six (>=1.10.0) + +The Python X Library +==================== + +|Build Status| |codecov.io| |Code Health| + +`Homepage`_ | `Releases`_ | `Changelog`_ + +Copyright +~~~~~~~~~ + +The main part of the code is + +:: + + Copyright (C) 2000-2002 Peter Liljenberg + +Some contributed code is copyrighted by `the contributors `_, +in these cases that is indicated in the source files in question. + +The Python X Library is released under LGPL v2.1 or later (since 2016), +see the file LICENSE for details. 0.15rc1 and before were released under +GPL v2. + +Requirements +~~~~~~~~~~~~ + +The Python X Library requires Python 2.7 or newer. It has been tested to +various extents with Python 2.7 and 3.3 through 3.6. + +The Python X Library will only work on systems that have an X server installed, +such as most Linux distros, but will not work on Windows or MacOS. + +Installation +~~~~~~~~~~~~ + +The Python Xlib uses the standard setuptools package, to install run +this command: + +:: + + python setup.py install + +See the command help for details: ``python setup.py install -h``. + +Alternatively, you can run programs from the distribution directory, or +change the module path in programs. + +There's a simple example program, implemented twice using both the +high-level interface and the low-level protocol. + +Introduction +~~~~~~~~~~~~ + +The Python X Library is intended to be a fully functional X client +library for Python programs. It is written entirely in Python, in +contrast to earlier X libraries for Python (the ancient X extension and +the newer plxlib) which were interfaces to the C Xlib. + +This is possible to do since X client programs communicate with the X +server via the X protocol. The communication takes place over TCP/IP, +Unix sockets, DECnet or any other streaming network protocol. The C Xlib +is merely an interface to this protocol, providing functions suitable +for a C environment. + +There are three advantages of implementing a pure Python library: + +- Integration: The library can make use of the wonderful object system + in Python, providing an easy-to-use class hierarchy. + +- Portability: The library will be usable on (almost) any computer + which have Python installed. A C interface could be problematic to + port to non-Unix systems, such as MS Windows or OpenVMS. + +- Maintainability: It is much easier to develop and debug native Python + modules than modules written in C. + +Documentation +~~~~~~~~~~~~~ + +The reference manual is not finished by far, but is probably still useful. It +can be `browsed online `__. + +There are also some `example programs `_ and, of course, +`the standard X11 documentation `__ applies. + + +Project status +~~~~~~~~~~~~~~ + +The low-level protocol is complete, implementing client-side X11R6. The +high-level object oriented interface is also fully functional. It is +possible to write client applications with the library. Currently, the +only real application using Python Xlib is the window manager PLWM, +starting with version 2.0. + +There is a resource database implementation, ICCCM support and a +framework for adding X extension code. Several extensions have been +implemented (RECORD, SHAPE, Xinerama, Composite, RANDR, DAMAGE, +Generic Event, SECURITY, XFIXES, XInput, XTEST, NV-CONTROL, DPMS and XRes); +patches for additions are very welcome. + +There are most likely still bugs, but the library is at least stable +enough to run PLWM. A continuously bigger part of the library is covered +by regression tests, improving stability. + +The documentation is still quite rudimentary, but should be of some help +for people programming with the Xlib. X beginners should first find some +general texts on X. A very good starting point is +http://www.rahul.net/kenton/xsites.html + +See the file TODO for a detailed list of what is missing, approximately +ordered by importance. + +.. _Homepage: https://github.com/python-xlib/python-xlib +.. _Releases: https://github.com/python-xlib/python-xlib/releases +.. _Changelog: https://github.com/python-xlib/python-xlib/tree/master/CHANGELOG.md +.. _Contributors: https://github.com/python-xlib/python-xlib/graphs/contributors +.. _Examples: https://github.com/python-xlib/python-xlib/tree/master/examples + +.. |Build Status| image:: https://travis-ci.org/python-xlib/python-xlib.svg?branch=master + :target: https://travis-ci.org/python-xlib/python-xlib +.. |codecov.io| image:: https://codecov.io/github/python-xlib/python-xlib/coverage.svg?branch=master + :target: https://codecov.io/github/python-xlib/python-xlib?branch=master +.. |Code Health| image:: https://landscape.io/github/python-xlib/python-xlib/master/landscape.svg?style=flat + :target: https://landscape.io/github/python-xlib/python-xlib/master + + diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/RECORD new file mode 100644 index 0000000..519ddae --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/RECORD @@ -0,0 +1,136 @@ +Xlib/X.py,sha256=hKIUvoQzliEgTA8CXcfhWDEvxKmY6CvhtBOsaAQjHAs,10687 +Xlib/XK.py,sha256=1kme6XPruQ5X-_rl6t76oTUOfjXNw7vGDZ5XXIlarVs,3299 +Xlib/Xatom.py,sha256=VRI0u8KV-L-DSuUHSexoFh8EBb0In2A_krkomOYCtoA,2047 +Xlib/Xcursorfont.py,sha256=n-AMIqTBZhuNVSlU4FF79e7pgwYW_nX9qQ4JFjzfVrw,2128 +Xlib/Xutil.py,sha256=65DIrIENhiSz_Vfuo12Hf7dBWJNKjtW9wdBXu4fwcsk,2298 +Xlib/__init__.py,sha256=9YXlGXmObCiLlfRLRA4U2HsaMgpptWf1YyLsc3mCOLg,1223 +Xlib/__pycache__/X.cpython-312.pyc,, +Xlib/__pycache__/XK.cpython-312.pyc,, +Xlib/__pycache__/Xatom.cpython-312.pyc,, +Xlib/__pycache__/Xcursorfont.cpython-312.pyc,, +Xlib/__pycache__/Xutil.cpython-312.pyc,, +Xlib/__pycache__/__init__.cpython-312.pyc,, +Xlib/__pycache__/display.cpython-312.pyc,, +Xlib/__pycache__/error.cpython-312.pyc,, +Xlib/__pycache__/rdb.cpython-312.pyc,, +Xlib/__pycache__/threaded.cpython-312.pyc,, +Xlib/__pycache__/xauth.cpython-312.pyc,, +Xlib/display.py,sha256=Nighif4Hj5pncOZ9U_dMi5Ij-VZ-etqkDbmV9vR2DUs,38048 +Xlib/error.py,sha256=i0lByUYdgXfvuisx-2hqjec2_O3jwanqklzOhOCZ_Ms,4911 +Xlib/ext/__init__.py,sha256=mIuX-L5zxbgGjgdnNldxEtOMG76O1zWkExwQq7jDx4U,1679 +Xlib/ext/__pycache__/__init__.cpython-312.pyc,, +Xlib/ext/__pycache__/composite.cpython-312.pyc,, +Xlib/ext/__pycache__/damage.cpython-312.pyc,, +Xlib/ext/__pycache__/dpms.cpython-312.pyc,, +Xlib/ext/__pycache__/ge.cpython-312.pyc,, +Xlib/ext/__pycache__/nvcontrol.cpython-312.pyc,, +Xlib/ext/__pycache__/randr.cpython-312.pyc,, +Xlib/ext/__pycache__/record.cpython-312.pyc,, +Xlib/ext/__pycache__/res.cpython-312.pyc,, +Xlib/ext/__pycache__/screensaver.cpython-312.pyc,, +Xlib/ext/__pycache__/security.cpython-312.pyc,, +Xlib/ext/__pycache__/shape.cpython-312.pyc,, +Xlib/ext/__pycache__/xfixes.cpython-312.pyc,, +Xlib/ext/__pycache__/xinerama.cpython-312.pyc,, +Xlib/ext/__pycache__/xinput.cpython-312.pyc,, +Xlib/ext/__pycache__/xtest.cpython-312.pyc,, +Xlib/ext/composite.py,sha256=s1mbl2gtc5nrgI_yhOW_0Y7St8TAUcUesZT62huYqUs,8861 +Xlib/ext/damage.py,sha256=bLq-S6izGvcHm9sl3Bkb1MuQINDC0DNZWT2AQov5Fm4,5898 +Xlib/ext/dpms.py,sha256=oSTu-B1Sk0VRFSJUyUNm4Tdra4DiPND2MCGnddI-gvg,6948 +Xlib/ext/ge.py,sha256=_8mYdzZyaJAeTV5LKxtZQSO-1AHzhOJqqmzRcrWmzWA,3481 +Xlib/ext/nvcontrol.py,sha256=uyhYMr2JsGEb-1v4dNDA63LGEqL9Ck9wq-al-mux7Us,191917 +Xlib/ext/randr.py,sha256=HM1dCEwUQ1aXtVSpRDAvT4dAzFTx_POxGZJd36KF_T0,38563 +Xlib/ext/record.py,sha256=7qR9VR6kNKNR_co0ltGHk7iKOQW75L5nyNq6DnABGPQ,9664 +Xlib/ext/res.py,sha256=NGTIbq_IZk_Xa0Ow6AchuJdP6oogOFJHWyafCl5HCpQ,9244 +Xlib/ext/screensaver.py,sha256=A-7IdrmPY5Wj-zm6P-DnTk7oix9C0BrnR7KPyexjxJs,6451 +Xlib/ext/security.py,sha256=kdyWhdyd5Kg8RJhr7RaAvlE7Ml-0sFwBWqvKZ7QzW2g,5180 +Xlib/ext/shape.py,sha256=4XhB7wZbdBrtVUbW1NpTp49uJRtF-txwd-jMpW5ESbE,8147 +Xlib/ext/xfixes.py,sha256=DnXGk3RNGqRwgRC0Rr41T8-vT6URmm3iJ5eR-3Nmgeo,7673 +Xlib/ext/xinerama.py,sha256=qf2D7mGOCCN7TXhW6mCIIZm25MiqkT29xBudIxc6yGU,7134 +Xlib/ext/xinput.py,sha256=8P2ELKK0w92QVV6SFXi-yiYyHVfG50asFA0NnNP6cQY,21369 +Xlib/ext/xtest.py,sha256=dr-mSbd6Pd4Z8eWe506BonkuMqkd2KzZr-_EwUzwhhE,4686 +Xlib/keysymdef/__init__.py,sha256=v6-37-D4AOWUFMVoV5qaGYLJ2PGsZuca61cgp9ZLCPY,1171 +Xlib/keysymdef/__pycache__/__init__.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/apl.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/arabic.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/cyrillic.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/greek.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/hebrew.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/katakana.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/korean.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/latin1.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/latin2.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/latin3.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/latin4.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/miscellany.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/publishing.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/special.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/technical.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/thai.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/xf86.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/xk3270.cpython-312.pyc,, +Xlib/keysymdef/__pycache__/xkb.cpython-312.pyc,, +Xlib/keysymdef/apl.py,sha256=YnXHuO_cuiskmvzmJVvAavqu9rzkln1cqhT2e4GaPdA,388 +Xlib/keysymdef/arabic.py,sha256=BvtYlu66CnM0_TtmGqQ-2oyEgcljocRwRqnLyZpSusw,1271 +Xlib/keysymdef/cyrillic.py,sha256=d0jbvIq5khW9_jXTymLfOjeyuntlArr2nFhnBe69Us8,2647 +Xlib/keysymdef/greek.py,sha256=8MMrtk3omP6yVOMENTOR6GfU9dDiE9H8nXAr5tqaVW4,1914 +Xlib/keysymdef/hebrew.py,sha256=6ZCcrJ_NPykfq2icxmtc0mDn9Yy7VfSM0qTgkokRjVs,997 +Xlib/keysymdef/katakana.py,sha256=O3Tii7VAwKlbPKKGbbH1p3JsYe6YqXyX5TlKi85TTWw,1467 +Xlib/keysymdef/korean.py,sha256=cmkjs9BDOH64v6j-ThpWLlHhLc3nqs5PoVJ82JoEGlY,2967 +Xlib/keysymdef/latin1.py,sha256=tdsB2tt4A4IGlHqVyl9vbX61Hg8v5KSvTPwhRnE8CmY,3621 +Xlib/keysymdef/latin2.py,sha256=byugoPe9yk3rm3-Xn_vh05AYwsRo_VNIWMX69b4cDDw,1132 +Xlib/keysymdef/latin3.py,sha256=dAbFBTKV4UdKVA_XQEmJygjMR_j08uL7twEJAMsIJuM,487 +Xlib/keysymdef/latin4.py,sha256=c7UOJkBlSX7Uq4I3oXSBS5jZ3Ae7xyVEyk5XvafcV1U,714 +Xlib/keysymdef/miscellany.py,sha256=9J6QpQaCWHFEqzymFXQ8cjqiv-egvp22U2hW2GjKtZo,3302 +Xlib/keysymdef/publishing.py,sha256=NbJoa_50kpVIq3FcKt2dX-mqCWf7HB7xasJsAh2TUgM,2060 +Xlib/keysymdef/special.py,sha256=FzeeTfs8p9GAmALjjnCREa3jxLZGaLu83rnRMKLBpJE,514 +Xlib/keysymdef/technical.py,sha256=qLOeqtfRJc5T8TkU079fiMz5WlrCtcw2GAFJ8xIyvaY,1252 +Xlib/keysymdef/thai.py,sha256=BpbxEZRUb2Z3mKONqUzOf1EDjRizSFTJMeCFrsKEKhw,2088 +Xlib/keysymdef/xf86.py,sha256=nuHUmUggywSlTDH842p-983vC_wJ8OKkCYzD0jTozro,7051 +Xlib/keysymdef/xk3270.py,sha256=qBs78MPixilvU33hsTU9IWcCSwCqYZM5hK2xWJewsQA,768 +Xlib/keysymdef/xkb.py,sha256=QXj1RlwNMHhDnlQYfmnKwkdQqPx4M123AyvMuYLGEnc,3022 +Xlib/protocol/__init__.py,sha256=ofD15n8WA_iSRWhs3riBFES_YH4_3MrgP7tBOyqjHv8,979 +Xlib/protocol/__pycache__/__init__.cpython-312.pyc,, +Xlib/protocol/__pycache__/display.cpython-312.pyc,, +Xlib/protocol/__pycache__/event.cpython-312.pyc,, +Xlib/protocol/__pycache__/request.cpython-312.pyc,, +Xlib/protocol/__pycache__/rq.cpython-312.pyc,, +Xlib/protocol/__pycache__/structs.cpython-312.pyc,, +Xlib/protocol/display.py,sha256=vb1QPx9SPNoSRL6tHCDFpL_oJmaeHh7kH9HzyNMr2xM,37415 +Xlib/protocol/event.py,sha256=lSPPv-PTtNY1ygTlQUcD7JR75uehTce4jwrPlSrM2d4,15816 +Xlib/protocol/request.py,sha256=47OcW2F4Aakvwce_g4tkwyrPE0F1T9QYCxZdpvMIzgg,49468 +Xlib/protocol/rq.py,sha256=UNwDN6GM6mfI9d6YJ8h-Iw19A35d44aH_E_wU2WrT1E,45036 +Xlib/protocol/structs.py,sha256=V0xfHOEB_ZY75DPEzEFD7zOD2285yFIbjDYUp2BQdTY,5489 +Xlib/rdb.py,sha256=WjT8Kem-WXqXPv1oHz0D6lVAnpu_MsB_xxF4Fo9tuks,20673 +Xlib/support/__init__.py,sha256=xPe4wHamik3vA3qopzosJSTLaqf9joOzlBmIVv0SZQM,986 +Xlib/support/__pycache__/__init__.cpython-312.pyc,, +Xlib/support/__pycache__/connect.cpython-312.pyc,, +Xlib/support/__pycache__/lock.cpython-312.pyc,, +Xlib/support/__pycache__/unix_connect.cpython-312.pyc,, +Xlib/support/__pycache__/vms_connect.cpython-312.pyc,, +Xlib/support/connect.py,sha256=AX5KJNiCCYtBjsgNwN6ZzIF-sDTAtDAcuUdbdJYq-zE,3194 +Xlib/support/lock.py,sha256=VGzvzPJUS-dt_WwWI4sZqdMTMRucRQ__ttHZGnOeM_Y,1591 +Xlib/support/unix_connect.py,sha256=NTomjognC9rAfphiQqXUiUe6gb03cTJZwzGb4c_yM5c,7357 +Xlib/support/vms_connect.py,sha256=go5lxSTjjpHh2fSi-ys8j3Z-VHRKTkRuQk80TYQzoWY,2161 +Xlib/threaded.py,sha256=D5gC7xcYJ6Khr5OKcMZdeWnD9d2hBNR13lRgWiJFwV4,1124 +Xlib/xauth.py,sha256=OoHZIaJMcTP1VJ3h2j2ryh-LIOqNOp5Wc6jE3eYl0uI,4483 +Xlib/xobject/__init__.py,sha256=klyPCdKFavDcq4Lr9-Hhrnforg38Hs8C4ZBWFjmD9hM,1001 +Xlib/xobject/__pycache__/__init__.cpython-312.pyc,, +Xlib/xobject/__pycache__/colormap.cpython-312.pyc,, +Xlib/xobject/__pycache__/cursor.cpython-312.pyc,, +Xlib/xobject/__pycache__/drawable.cpython-312.pyc,, +Xlib/xobject/__pycache__/fontable.cpython-312.pyc,, +Xlib/xobject/__pycache__/icccm.cpython-312.pyc,, +Xlib/xobject/__pycache__/resource.cpython-312.pyc,, +Xlib/xobject/colormap.py,sha256=tuOdt5pImB_rD428kp63nsDWeX-5HuN1S4UGmMGIMUA,5866 +Xlib/xobject/cursor.py,sha256=WF8-ssyDdbej5qU6NlrRAFkYr-GYQbvHTi6gomlWcL4,1896 +Xlib/xobject/drawable.py,sha256=3rBrHPl-fbZq_Oz2Ibo3U4pFk-19QQawojKivfwoErQ,35256 +Xlib/xobject/fontable.py,sha256=54w1rMYIkacTev8_Cw-effrnUI2WAziu9Qj5EI_J4DY,4349 +Xlib/xobject/icccm.py,sha256=RozK-gRBsTiTbHTMVbufNdZbpfAk2UtCZnislFGZ__U,3441 +Xlib/xobject/resource.py,sha256=ciFnK_zPttUbmDktJJIUFDte0Jev6PcS5KSseWOjkAc,1791 +python_xlib-0.33.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +python_xlib-0.33.dist-info/LICENSE,sha256=O7b2vslLmeKSeoiAv0nEAfXo9Iog3eqWMQhgJkyuILA,26965 +python_xlib-0.33.dist-info/METADATA,sha256=4YBseoNGoVlht9F-9eAxN9e5OLRnE5x6yDKqRNn3r5k,6249 +python_xlib-0.33.dist-info/RECORD,, +python_xlib-0.33.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110 +python_xlib-0.33.dist-info/top_level.txt,sha256=KYaqxIvc7od8tCuJgS1v_nr9T4OjWVfsI4lGa38I5uU,5 diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/WHEEL new file mode 100644 index 0000000..0b18a28 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/top_level.txt new file mode 100644 index 0000000..7997334 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/python_xlib-0.33.dist-info/top_level.txt @@ -0,0 +1 @@ +Xlib diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/INSTALLER b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/LICENSE b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/LICENSE new file mode 100644 index 0000000..1cc22a5 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2010-2024 Benjamin Peterson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/METADATA b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/METADATA new file mode 100644 index 0000000..cfde03c --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/METADATA @@ -0,0 +1,43 @@ +Metadata-Version: 2.1 +Name: six +Version: 1.17.0 +Summary: Python 2 and 3 compatibility utilities +Home-page: https://github.com/benjaminp/six +Author: Benjamin Peterson +Author-email: benjamin@python.org +License: MIT +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* +License-File: LICENSE + +.. image:: https://img.shields.io/pypi/v/six.svg + :target: https://pypi.org/project/six/ + :alt: six on PyPI + +.. image:: https://readthedocs.org/projects/six/badge/?version=latest + :target: https://six.readthedocs.io/ + :alt: six's documentation on Read the Docs + +.. image:: https://img.shields.io/badge/license-MIT-green.svg + :target: https://github.com/benjaminp/six/blob/master/LICENSE + :alt: MIT License badge + +Six is a Python 2 and 3 compatibility library. It provides utility functions +for smoothing over the differences between the Python versions with the goal of +writing Python code that is compatible on both Python versions. See the +documentation for more information on what is provided. + +Six supports Python 2.7 and 3.3+. It is contained in only one Python +file, so it can be easily copied into your project. (The copyright and license +notice must be retained.) + +Online documentation is at https://six.readthedocs.io/. + +Bugs can be reported to https://github.com/benjaminp/six. The code can also +be found there. diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/RECORD b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/RECORD new file mode 100644 index 0000000..bb90c1a --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/six.cpython-312.pyc,, +six-1.17.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +six-1.17.0.dist-info/LICENSE,sha256=Q3W6IOK5xsTnytKUCmKP2Q6VzD1Q7pKq51VxXYuh-9A,1066 +six-1.17.0.dist-info/METADATA,sha256=ViBCB4wnUlSfbYp8htvF3XCAiKe-bYBnLsewcQC3JGg,1658 +six-1.17.0.dist-info/RECORD,, +six-1.17.0.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109 +six-1.17.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 +six.py,sha256=xRyR9wPT1LNpbJI8tf7CE-BeddkhU5O--sfy-mo5BN8,34703 diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/WHEEL b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/WHEEL new file mode 100644 index 0000000..104f387 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.6.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/top_level.txt b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/top_level.txt new file mode 100644 index 0000000..ffe2fce --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six-1.17.0.dist-info/top_level.txt @@ -0,0 +1 @@ +six diff --git a/CLI/venv/lib/python3.12/site-packages/six.py b/CLI/venv/lib/python3.12/site-packages/six.py new file mode 100644 index 0000000..3de5969 --- /dev/null +++ b/CLI/venv/lib/python3.12/site-packages/six.py @@ -0,0 +1,1003 @@ +# Copyright (c) 2010-2024 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.17.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections", "IterableUserDict", "UserDict"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +if sys.version_info[:2] < (3, 14): + _urllib_request_moved_attributes.extend( + [ + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + ] + ) +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""") + + +if sys.version_info[:2] > (3,): + exec_("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper(wrapper, wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + return functools.partial(_update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + if hasattr(cls, '__qualname__'): + orig_vars['__qualname__'] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, binary_type): + return s + if isinstance(s, text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + # Optimization: Fast return for the common case. + if type(s) is str: + return s + if PY2 and isinstance(s, text_type): + return s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer)