diff --git a/Xlib/ChangeLog b/Xlib/ChangeLog new file mode 100644 index 0000000..52bfb93 --- /dev/null +++ b/Xlib/ChangeLog @@ -0,0 +1,123 @@ +2007-06-10 Mike Grant + + * (many files): (mgg) Converted tabs to spaces throughout the + codebase, using reindent.py (SF id: 1559082) + +2007-03-18 Mike Grant + + * Xlib/display.py: (mgg) Added a get_atom alias that uses the + internal cache + * Xlib/xobject/drawable.py: (mgg) Added a raise_window() alias + to the Window class + +2007-02-15 Mike Grant + + * Xlib/xauth.py: (mgg) Python 2.5 didn't like the way the buffer + type was used, resulting in X authorisation failure, so + reverted to using slices + +2006-11-22 Mike Grant + + * Xlib/ext/record.py: Addition of RECORD extension by Alex Badea + , SF patch id #1538663 (demo + program in python-xlib/examples/record_demo.py) + +2006-09-20 Mike Meyer + + * Xlib/ext/xinerama.py: (mwm) Addition of Xinerama extension + +2006-07-22 Mike Grant + + Various typo fixes, general updates. + + Changelog hasn't been maintained since 2002, but some of the more + significant comments from cvs logs follow: + + * Xlib/display.py: (petli) Fix bug in refresh_keyboard_mapping: + ignore modifier and pointer remappings. Plays nice with pydoc. + Copied some text from the docs to __doc__ strings in + Xlib/display.py so that they appear when you use pydoc. + Completed documentation for Display objects. + * Xlib/XK.py: (calroc99) Minor doc string changes. Called + load_keysym_group() for miscellany and latin1 keysyms, rather + than importing the modules. + * Xlib/keysymdef/*: (calroc99) Small change to keysym loading. + Works the same way. + * Xlib/support/*, Xlib/xauth.py, Xlib/error.py: (petli) Added + ~/.Xauthority parsing by Python code instead of relying on + /usr/X11R6/bin/xauth. Not activated yet in all cases yet? + Activated in unix_support.py. + * Xlib/xobject/drawable.py: (petli) Fix bugs in definition and + method of GrabButton/Pointer + * Xlib/xobject/icccm.py: (petli) Add WithdrawnState to WMHints + * doc/*: (petli) documentation updates, typos and completing + documentation for Display objects + + +2002-03-30 Peter Liljenberg + + * support/unix_connect.py: Handle fcntl/FCNTL changes in Python + 2.2. + +2002-03-11 Peter Liljenberg + + * xobject/drawable.py (Drawable.fill_arc): This should be a + PolyFillArc. + +Fri Jan 19 17:49:45 2001 Peter Liljenberg + + * XK.py: Moved all keysyms into separate modules, based on their + category. By default only the miscellany and latin1 keysyms are + loaded, and other have to be loaded by importing the + Xlib.keysymdef. module, or calling + load_keysym_group('category'). + + * display.py (Display.lookup_string): + (Display.rebind_string): + + Functions to translate keysyms to strings, and binding keysyms to + new strings. + + +2001-01-16 + + * xobject/drawable.py (Window.send_event): + * display.py (Display.send_event): Changed the order of the + event_mask and propagate arguments. + +2001-01-10 + + * display.py (Display._update_keymap): The first half of the + update algorithm operated on an earlier type of code->sym map than + the second half. Stupid, stupid. It would have been nice with a + type-checker now. + +Tue Jan 9 13:03:19 2001 Peter Liljenberg + + * display.py (Display._update_keymap): Fixed call to append with + 1.5.2 semantics, broke in newer Pythons. + +2000-12-22 + + * display.py (Display.keycode_to_keysym): + (Display.keysym_to_keycode): + (Display.keysym_to_keycodes): + (Display.refresh_keyboard_mapping): + (Display._update_keymap): + Added keymap cache implementation. + +2000-12-21 + + * xobject/colormap.py (Colormap.alloc_named_color): Extended to + handle #000000 style color specifications. + + * xobject/drawable.py (Window.reparent): Renamed from + reparent_window. + + * display.py (Display.set_error_handler): Added. + +2000-12-20 + + * display.py (_BaseDisplay): + Implement a cache of atom names. + diff --git a/Xlib/X.py b/Xlib/X.py new file mode 100644 index 0000000..1a09e39 --- /dev/null +++ b/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/Xlib/XK.py b/Xlib/XK.py new file mode 100644 index 0000000..7603ccd --- /dev/null +++ b/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/Xlib/Xatom.py b/Xlib/Xatom.py new file mode 100644 index 0000000..b013777 --- /dev/null +++ b/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/Xlib/Xcursorfont.py b/Xlib/Xcursorfont.py new file mode 100644 index 0000000..1991943 --- /dev/null +++ b/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/Xlib/Xutil.py b/Xlib/Xutil.py new file mode 100644 index 0000000..768c5e2 --- /dev/null +++ b/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/Xlib/__init__.py b/Xlib/__init__.py new file mode 100644 index 0000000..8947373 --- /dev/null +++ b/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, 31) + +__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/Xlib/__pycache__/X.cpython-38.pyc b/Xlib/__pycache__/X.cpython-38.pyc new file mode 100644 index 0000000..4e06ad0 Binary files /dev/null and b/Xlib/__pycache__/X.cpython-38.pyc differ diff --git a/Xlib/__pycache__/XK.cpython-38.pyc b/Xlib/__pycache__/XK.cpython-38.pyc new file mode 100644 index 0000000..4466e19 Binary files /dev/null and b/Xlib/__pycache__/XK.cpython-38.pyc differ diff --git a/Xlib/__pycache__/Xatom.cpython-38.pyc b/Xlib/__pycache__/Xatom.cpython-38.pyc new file mode 100644 index 0000000..4367d0e Binary files /dev/null and b/Xlib/__pycache__/Xatom.cpython-38.pyc differ diff --git a/Xlib/__pycache__/Xutil.cpython-38.pyc b/Xlib/__pycache__/Xutil.cpython-38.pyc new file mode 100644 index 0000000..8ed50dd Binary files /dev/null and b/Xlib/__pycache__/Xutil.cpython-38.pyc differ diff --git a/Xlib/__pycache__/__init__.cpython-38.pyc b/Xlib/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..69b10b1 Binary files /dev/null and b/Xlib/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/__pycache__/display.cpython-38.pyc b/Xlib/__pycache__/display.cpython-38.pyc new file mode 100644 index 0000000..97f9730 Binary files /dev/null and b/Xlib/__pycache__/display.cpython-38.pyc differ diff --git a/Xlib/__pycache__/error.cpython-38.pyc b/Xlib/__pycache__/error.cpython-38.pyc new file mode 100644 index 0000000..a172911 Binary files /dev/null and b/Xlib/__pycache__/error.cpython-38.pyc differ diff --git a/Xlib/__pycache__/threaded.cpython-38.pyc b/Xlib/__pycache__/threaded.cpython-38.pyc new file mode 100644 index 0000000..8d931fe Binary files /dev/null and b/Xlib/__pycache__/threaded.cpython-38.pyc differ diff --git a/Xlib/__pycache__/xauth.cpython-38.pyc b/Xlib/__pycache__/xauth.cpython-38.pyc new file mode 100644 index 0000000..86d1f69 Binary files /dev/null and b/Xlib/__pycache__/xauth.cpython-38.pyc differ diff --git a/Xlib/display.py b/Xlib/display.py new file mode 100644 index 0000000..ead0185 --- /dev/null +++ b/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=0): + 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 add_extension_error(self, code, err): + """add_extension_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 = 0): + """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 = 0): + """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 = 0, + 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/Xlib/error.py b/Xlib/error.py new file mode 100644 index 0000000..cb6d0d0 --- /dev/null +++ b/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, data = self._fields.parse_binary(data, display, rawdict = 1) + + 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/Xlib/ext/__init__.py b/Xlib/ext/__init__.py new file mode 100644 index 0000000..37229ba --- /dev/null +++ b/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/Xlib/ext/__pycache__/__init__.cpython-38.pyc b/Xlib/ext/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..9e1978d Binary files /dev/null and b/Xlib/ext/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/composite.cpython-38.pyc b/Xlib/ext/__pycache__/composite.cpython-38.pyc new file mode 100644 index 0000000..3b10f05 Binary files /dev/null and b/Xlib/ext/__pycache__/composite.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/damage.cpython-38.pyc b/Xlib/ext/__pycache__/damage.cpython-38.pyc new file mode 100644 index 0000000..25eab34 Binary files /dev/null and b/Xlib/ext/__pycache__/damage.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/dpms.cpython-38.pyc b/Xlib/ext/__pycache__/dpms.cpython-38.pyc new file mode 100644 index 0000000..f1e2772 Binary files /dev/null and b/Xlib/ext/__pycache__/dpms.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/ge.cpython-38.pyc b/Xlib/ext/__pycache__/ge.cpython-38.pyc new file mode 100644 index 0000000..d1332d6 Binary files /dev/null and b/Xlib/ext/__pycache__/ge.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/randr.cpython-38.pyc b/Xlib/ext/__pycache__/randr.cpython-38.pyc new file mode 100644 index 0000000..b2add69 Binary files /dev/null and b/Xlib/ext/__pycache__/randr.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/record.cpython-38.pyc b/Xlib/ext/__pycache__/record.cpython-38.pyc new file mode 100644 index 0000000..df416e3 Binary files /dev/null and b/Xlib/ext/__pycache__/record.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/res.cpython-38.pyc b/Xlib/ext/__pycache__/res.cpython-38.pyc new file mode 100644 index 0000000..6499560 Binary files /dev/null and b/Xlib/ext/__pycache__/res.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/screensaver.cpython-38.pyc b/Xlib/ext/__pycache__/screensaver.cpython-38.pyc new file mode 100644 index 0000000..76327ea Binary files /dev/null and b/Xlib/ext/__pycache__/screensaver.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/security.cpython-38.pyc b/Xlib/ext/__pycache__/security.cpython-38.pyc new file mode 100644 index 0000000..9a80641 Binary files /dev/null and b/Xlib/ext/__pycache__/security.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/shape.cpython-38.pyc b/Xlib/ext/__pycache__/shape.cpython-38.pyc new file mode 100644 index 0000000..0d847ee Binary files /dev/null and b/Xlib/ext/__pycache__/shape.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/xfixes.cpython-38.pyc b/Xlib/ext/__pycache__/xfixes.cpython-38.pyc new file mode 100644 index 0000000..9ed9ff7 Binary files /dev/null and b/Xlib/ext/__pycache__/xfixes.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/xinerama.cpython-38.pyc b/Xlib/ext/__pycache__/xinerama.cpython-38.pyc new file mode 100644 index 0000000..7d81454 Binary files /dev/null and b/Xlib/ext/__pycache__/xinerama.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/xinput.cpython-38.pyc b/Xlib/ext/__pycache__/xinput.cpython-38.pyc new file mode 100644 index 0000000..e559310 Binary files /dev/null and b/Xlib/ext/__pycache__/xinput.cpython-38.pyc differ diff --git a/Xlib/ext/__pycache__/xtest.cpython-38.pyc b/Xlib/ext/__pycache__/xtest.cpython-38.pyc new file mode 100644 index 0000000..032cb76 Binary files /dev/null and b/Xlib/ext/__pycache__/xtest.cpython-38.pyc differ diff --git a/Xlib/ext/composite.py b/Xlib/ext/composite.py new file mode 100644 index 0000000..0e10b63 --- /dev/null +++ b/Xlib/ext/composite.py @@ -0,0 +1,272 @@ +# $Id: xtest.py,v 1.1 2000/08/21 10:03:45 petli Exp $ +# +# Xlib.ext.composite -- Composite extension module +# +# Copyright (C) 2007 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 + +"""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 import X +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/Xlib/ext/damage.py b/Xlib/ext/damage.py new file mode 100644 index 0000000..0cde5ed --- /dev/null +++ b/Xlib/ext/damage.py @@ -0,0 +1,182 @@ +# 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.xobject import resource +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.add_extension_error(code=BadDamageCode, err=BadDamageError) diff --git a/Xlib/ext/dpms.py b/Xlib/ext/dpms.py new file mode 100644 index 0000000..3ff9a24 --- /dev/null +++ b/Xlib/ext/dpms.py @@ -0,0 +1,233 @@ +# 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 import X +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/Xlib/ext/ge.py b/Xlib/ext/ge.py new file mode 100644 index 0000000..291ffa9 --- /dev/null +++ b/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/Xlib/ext/nvcontrol.py b/Xlib/ext/nvcontrol.py new file mode 100644 index 0000000..7a21826 --- /dev/null +++ b/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/Xlib/ext/randr.py b/Xlib/ext/randr.py new file mode 100644 index 0000000..48f4b63 --- /dev/null +++ b/Xlib/ext/randr.py @@ -0,0 +1,1197 @@ +# 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.3 of the XRandR protocol, and may +not be compatible with other versions. + +Version 1.2 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, structs + +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 + + +# 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'), + ) + + +# 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=3, + ) + + +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, + ) + + +# 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) + + 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/Xlib/ext/record.py b/Xlib/ext/record.py new file mode 100644 index 0000000..bb53ec1 --- /dev/null +++ b/Xlib/ext/record.py @@ -0,0 +1,283 @@ +# 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 import X +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/Xlib/ext/res.py b/Xlib/ext/res.py new file mode 100644 index 0000000..f2c4e9f --- /dev/null +++ b/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/Xlib/ext/screensaver.py b/Xlib/ext/screensaver.py new file mode 100644 index 0000000..12f4325 --- /dev/null +++ b/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/Xlib/ext/security.py b/Xlib/ext/security.py new file mode 100644 index 0000000..a821017 --- /dev/null +++ b/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/Xlib/ext/shape.py b/Xlib/ext/shape.py new file mode 100644 index 0000000..05a517a --- /dev/null +++ b/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/Xlib/ext/xfixes.py b/Xlib/ext/xfixes.py new file mode 100644 index 0000000..59f9277 --- /dev/null +++ b/Xlib/ext/xfixes.py @@ -0,0 +1,201 @@ +# 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 import X +from Xlib.protocol import rq, structs + +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/Xlib/ext/xinerama.py b/Xlib/ext/xinerama.py new file mode 100644 index 0000000..f054670 --- /dev/null +++ b/Xlib/ext/xinerama.py @@ -0,0 +1,223 @@ +# 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 import X +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/Xlib/ext/xinput.py b/Xlib/ext/xinput.py new file mode 100644 index 0000000..f921806 --- /dev/null +++ b/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/Xlib/ext/xtest.py b/Xlib/ext/xtest.py new file mode 100644 index 0000000..602df2a --- /dev/null +++ b/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/Xlib/keysymdef/__init__.py b/Xlib/keysymdef/__init__.py new file mode 100644 index 0000000..4ff1441 --- /dev/null +++ b/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/Xlib/keysymdef/__pycache__/__init__.cpython-38.pyc b/Xlib/keysymdef/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..b57c94f Binary files /dev/null and b/Xlib/keysymdef/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/apl.cpython-38.pyc b/Xlib/keysymdef/__pycache__/apl.cpython-38.pyc new file mode 100644 index 0000000..71c2753 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/apl.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/arabic.cpython-38.pyc b/Xlib/keysymdef/__pycache__/arabic.cpython-38.pyc new file mode 100644 index 0000000..b4ae55d Binary files /dev/null and b/Xlib/keysymdef/__pycache__/arabic.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/cyrillic.cpython-38.pyc b/Xlib/keysymdef/__pycache__/cyrillic.cpython-38.pyc new file mode 100644 index 0000000..8276af3 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/cyrillic.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/greek.cpython-38.pyc b/Xlib/keysymdef/__pycache__/greek.cpython-38.pyc new file mode 100644 index 0000000..49c68d8 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/greek.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/hebrew.cpython-38.pyc b/Xlib/keysymdef/__pycache__/hebrew.cpython-38.pyc new file mode 100644 index 0000000..c08b73e Binary files /dev/null and b/Xlib/keysymdef/__pycache__/hebrew.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/katakana.cpython-38.pyc b/Xlib/keysymdef/__pycache__/katakana.cpython-38.pyc new file mode 100644 index 0000000..1082666 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/katakana.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/korean.cpython-38.pyc b/Xlib/keysymdef/__pycache__/korean.cpython-38.pyc new file mode 100644 index 0000000..020cd16 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/korean.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/latin1.cpython-38.pyc b/Xlib/keysymdef/__pycache__/latin1.cpython-38.pyc new file mode 100644 index 0000000..b39dcbc Binary files /dev/null and b/Xlib/keysymdef/__pycache__/latin1.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/latin2.cpython-38.pyc b/Xlib/keysymdef/__pycache__/latin2.cpython-38.pyc new file mode 100644 index 0000000..a8fb20f Binary files /dev/null and b/Xlib/keysymdef/__pycache__/latin2.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/latin3.cpython-38.pyc b/Xlib/keysymdef/__pycache__/latin3.cpython-38.pyc new file mode 100644 index 0000000..f55cd85 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/latin3.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/latin4.cpython-38.pyc b/Xlib/keysymdef/__pycache__/latin4.cpython-38.pyc new file mode 100644 index 0000000..0df510c Binary files /dev/null and b/Xlib/keysymdef/__pycache__/latin4.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/miscellany.cpython-38.pyc b/Xlib/keysymdef/__pycache__/miscellany.cpython-38.pyc new file mode 100644 index 0000000..95cd3ad Binary files /dev/null and b/Xlib/keysymdef/__pycache__/miscellany.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/publishing.cpython-38.pyc b/Xlib/keysymdef/__pycache__/publishing.cpython-38.pyc new file mode 100644 index 0000000..42edb11 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/publishing.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/special.cpython-38.pyc b/Xlib/keysymdef/__pycache__/special.cpython-38.pyc new file mode 100644 index 0000000..3e90278 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/special.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/technical.cpython-38.pyc b/Xlib/keysymdef/__pycache__/technical.cpython-38.pyc new file mode 100644 index 0000000..1d0837f Binary files /dev/null and b/Xlib/keysymdef/__pycache__/technical.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/thai.cpython-38.pyc b/Xlib/keysymdef/__pycache__/thai.cpython-38.pyc new file mode 100644 index 0000000..d7bfd40 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/thai.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/xf86.cpython-38.pyc b/Xlib/keysymdef/__pycache__/xf86.cpython-38.pyc new file mode 100644 index 0000000..2aede30 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/xf86.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/xk3270.cpython-38.pyc b/Xlib/keysymdef/__pycache__/xk3270.cpython-38.pyc new file mode 100644 index 0000000..25f3f01 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/xk3270.cpython-38.pyc differ diff --git a/Xlib/keysymdef/__pycache__/xkb.cpython-38.pyc b/Xlib/keysymdef/__pycache__/xkb.cpython-38.pyc new file mode 100644 index 0000000..ae314f3 Binary files /dev/null and b/Xlib/keysymdef/__pycache__/xkb.cpython-38.pyc differ diff --git a/Xlib/keysymdef/apl.py b/Xlib/keysymdef/apl.py new file mode 100644 index 0000000..81ed9e0 --- /dev/null +++ b/Xlib/keysymdef/apl.py @@ -0,0 +1,19 @@ +XK_leftcaret = 0xba3 +XK_rightcaret = 0xba6 +XK_downcaret = 0xba8 +XK_upcaret = 0xba9 +XK_overbar = 0xbc0 +XK_downtack = 0xbc2 +XK_upshoe = 0xbc3 +XK_downstile = 0xbc4 +XK_underbar = 0xbc6 +XK_jot = 0xbca +XK_quad = 0xbcc +XK_uptack = 0xbce +XK_circle = 0xbcf +XK_upstile = 0xbd3 +XK_downshoe = 0xbd6 +XK_rightshoe = 0xbd8 +XK_leftshoe = 0xbda +XK_lefttack = 0xbdc +XK_righttack = 0xbfc diff --git a/Xlib/keysymdef/arabic.py b/Xlib/keysymdef/arabic.py new file mode 100644 index 0000000..2b59e90 --- /dev/null +++ b/Xlib/keysymdef/arabic.py @@ -0,0 +1,50 @@ +XK_Arabic_comma = 0x5ac +XK_Arabic_semicolon = 0x5bb +XK_Arabic_question_mark = 0x5bf +XK_Arabic_hamza = 0x5c1 +XK_Arabic_maddaonalef = 0x5c2 +XK_Arabic_hamzaonalef = 0x5c3 +XK_Arabic_hamzaonwaw = 0x5c4 +XK_Arabic_hamzaunderalef = 0x5c5 +XK_Arabic_hamzaonyeh = 0x5c6 +XK_Arabic_alef = 0x5c7 +XK_Arabic_beh = 0x5c8 +XK_Arabic_tehmarbuta = 0x5c9 +XK_Arabic_teh = 0x5ca +XK_Arabic_theh = 0x5cb +XK_Arabic_jeem = 0x5cc +XK_Arabic_hah = 0x5cd +XK_Arabic_khah = 0x5ce +XK_Arabic_dal = 0x5cf +XK_Arabic_thal = 0x5d0 +XK_Arabic_ra = 0x5d1 +XK_Arabic_zain = 0x5d2 +XK_Arabic_seen = 0x5d3 +XK_Arabic_sheen = 0x5d4 +XK_Arabic_sad = 0x5d5 +XK_Arabic_dad = 0x5d6 +XK_Arabic_tah = 0x5d7 +XK_Arabic_zah = 0x5d8 +XK_Arabic_ain = 0x5d9 +XK_Arabic_ghain = 0x5da +XK_Arabic_tatweel = 0x5e0 +XK_Arabic_feh = 0x5e1 +XK_Arabic_qaf = 0x5e2 +XK_Arabic_kaf = 0x5e3 +XK_Arabic_lam = 0x5e4 +XK_Arabic_meem = 0x5e5 +XK_Arabic_noon = 0x5e6 +XK_Arabic_ha = 0x5e7 +XK_Arabic_heh = 0x5e7 +XK_Arabic_waw = 0x5e8 +XK_Arabic_alefmaksura = 0x5e9 +XK_Arabic_yeh = 0x5ea +XK_Arabic_fathatan = 0x5eb +XK_Arabic_dammatan = 0x5ec +XK_Arabic_kasratan = 0x5ed +XK_Arabic_fatha = 0x5ee +XK_Arabic_damma = 0x5ef +XK_Arabic_kasra = 0x5f0 +XK_Arabic_shadda = 0x5f1 +XK_Arabic_sukun = 0x5f2 +XK_Arabic_switch = 0xFF7E diff --git a/Xlib/keysymdef/cyrillic.py b/Xlib/keysymdef/cyrillic.py new file mode 100644 index 0000000..ceecbfb --- /dev/null +++ b/Xlib/keysymdef/cyrillic.py @@ -0,0 +1,107 @@ +XK_Serbian_dje = 0x6a1 +XK_Macedonia_gje = 0x6a2 +XK_Cyrillic_io = 0x6a3 +XK_Ukrainian_ie = 0x6a4 +XK_Ukranian_je = 0x6a4 +XK_Macedonia_dse = 0x6a5 +XK_Ukrainian_i = 0x6a6 +XK_Ukranian_i = 0x6a6 +XK_Ukrainian_yi = 0x6a7 +XK_Ukranian_yi = 0x6a7 +XK_Cyrillic_je = 0x6a8 +XK_Serbian_je = 0x6a8 +XK_Cyrillic_lje = 0x6a9 +XK_Serbian_lje = 0x6a9 +XK_Cyrillic_nje = 0x6aa +XK_Serbian_nje = 0x6aa +XK_Serbian_tshe = 0x6ab +XK_Macedonia_kje = 0x6ac +XK_Byelorussian_shortu = 0x6ae +XK_Cyrillic_dzhe = 0x6af +XK_Serbian_dze = 0x6af +XK_numerosign = 0x6b0 +XK_Serbian_DJE = 0x6b1 +XK_Macedonia_GJE = 0x6b2 +XK_Cyrillic_IO = 0x6b3 +XK_Ukrainian_IE = 0x6b4 +XK_Ukranian_JE = 0x6b4 +XK_Macedonia_DSE = 0x6b5 +XK_Ukrainian_I = 0x6b6 +XK_Ukranian_I = 0x6b6 +XK_Ukrainian_YI = 0x6b7 +XK_Ukranian_YI = 0x6b7 +XK_Cyrillic_JE = 0x6b8 +XK_Serbian_JE = 0x6b8 +XK_Cyrillic_LJE = 0x6b9 +XK_Serbian_LJE = 0x6b9 +XK_Cyrillic_NJE = 0x6ba +XK_Serbian_NJE = 0x6ba +XK_Serbian_TSHE = 0x6bb +XK_Macedonia_KJE = 0x6bc +XK_Byelorussian_SHORTU = 0x6be +XK_Cyrillic_DZHE = 0x6bf +XK_Serbian_DZE = 0x6bf +XK_Cyrillic_yu = 0x6c0 +XK_Cyrillic_a = 0x6c1 +XK_Cyrillic_be = 0x6c2 +XK_Cyrillic_tse = 0x6c3 +XK_Cyrillic_de = 0x6c4 +XK_Cyrillic_ie = 0x6c5 +XK_Cyrillic_ef = 0x6c6 +XK_Cyrillic_ghe = 0x6c7 +XK_Cyrillic_ha = 0x6c8 +XK_Cyrillic_i = 0x6c9 +XK_Cyrillic_shorti = 0x6ca +XK_Cyrillic_ka = 0x6cb +XK_Cyrillic_el = 0x6cc +XK_Cyrillic_em = 0x6cd +XK_Cyrillic_en = 0x6ce +XK_Cyrillic_o = 0x6cf +XK_Cyrillic_pe = 0x6d0 +XK_Cyrillic_ya = 0x6d1 +XK_Cyrillic_er = 0x6d2 +XK_Cyrillic_es = 0x6d3 +XK_Cyrillic_te = 0x6d4 +XK_Cyrillic_u = 0x6d5 +XK_Cyrillic_zhe = 0x6d6 +XK_Cyrillic_ve = 0x6d7 +XK_Cyrillic_softsign = 0x6d8 +XK_Cyrillic_yeru = 0x6d9 +XK_Cyrillic_ze = 0x6da +XK_Cyrillic_sha = 0x6db +XK_Cyrillic_e = 0x6dc +XK_Cyrillic_shcha = 0x6dd +XK_Cyrillic_che = 0x6de +XK_Cyrillic_hardsign = 0x6df +XK_Cyrillic_YU = 0x6e0 +XK_Cyrillic_A = 0x6e1 +XK_Cyrillic_BE = 0x6e2 +XK_Cyrillic_TSE = 0x6e3 +XK_Cyrillic_DE = 0x6e4 +XK_Cyrillic_IE = 0x6e5 +XK_Cyrillic_EF = 0x6e6 +XK_Cyrillic_GHE = 0x6e7 +XK_Cyrillic_HA = 0x6e8 +XK_Cyrillic_I = 0x6e9 +XK_Cyrillic_SHORTI = 0x6ea +XK_Cyrillic_KA = 0x6eb +XK_Cyrillic_EL = 0x6ec +XK_Cyrillic_EM = 0x6ed +XK_Cyrillic_EN = 0x6ee +XK_Cyrillic_O = 0x6ef +XK_Cyrillic_PE = 0x6f0 +XK_Cyrillic_YA = 0x6f1 +XK_Cyrillic_ER = 0x6f2 +XK_Cyrillic_ES = 0x6f3 +XK_Cyrillic_TE = 0x6f4 +XK_Cyrillic_U = 0x6f5 +XK_Cyrillic_ZHE = 0x6f6 +XK_Cyrillic_VE = 0x6f7 +XK_Cyrillic_SOFTSIGN = 0x6f8 +XK_Cyrillic_YERU = 0x6f9 +XK_Cyrillic_ZE = 0x6fa +XK_Cyrillic_SHA = 0x6fb +XK_Cyrillic_E = 0x6fc +XK_Cyrillic_SHCHA = 0x6fd +XK_Cyrillic_CHE = 0x6fe +XK_Cyrillic_HARDSIGN = 0x6ff diff --git a/Xlib/keysymdef/greek.py b/Xlib/keysymdef/greek.py new file mode 100644 index 0000000..4aa4418 --- /dev/null +++ b/Xlib/keysymdef/greek.py @@ -0,0 +1,74 @@ +XK_Greek_ALPHAaccent = 0x7a1 +XK_Greek_EPSILONaccent = 0x7a2 +XK_Greek_ETAaccent = 0x7a3 +XK_Greek_IOTAaccent = 0x7a4 +XK_Greek_IOTAdiaeresis = 0x7a5 +XK_Greek_OMICRONaccent = 0x7a7 +XK_Greek_UPSILONaccent = 0x7a8 +XK_Greek_UPSILONdieresis = 0x7a9 +XK_Greek_OMEGAaccent = 0x7ab +XK_Greek_accentdieresis = 0x7ae +XK_Greek_horizbar = 0x7af +XK_Greek_alphaaccent = 0x7b1 +XK_Greek_epsilonaccent = 0x7b2 +XK_Greek_etaaccent = 0x7b3 +XK_Greek_iotaaccent = 0x7b4 +XK_Greek_iotadieresis = 0x7b5 +XK_Greek_iotaaccentdieresis = 0x7b6 +XK_Greek_omicronaccent = 0x7b7 +XK_Greek_upsilonaccent = 0x7b8 +XK_Greek_upsilondieresis = 0x7b9 +XK_Greek_upsilonaccentdieresis = 0x7ba +XK_Greek_omegaaccent = 0x7bb +XK_Greek_ALPHA = 0x7c1 +XK_Greek_BETA = 0x7c2 +XK_Greek_GAMMA = 0x7c3 +XK_Greek_DELTA = 0x7c4 +XK_Greek_EPSILON = 0x7c5 +XK_Greek_ZETA = 0x7c6 +XK_Greek_ETA = 0x7c7 +XK_Greek_THETA = 0x7c8 +XK_Greek_IOTA = 0x7c9 +XK_Greek_KAPPA = 0x7ca +XK_Greek_LAMDA = 0x7cb +XK_Greek_LAMBDA = 0x7cb +XK_Greek_MU = 0x7cc +XK_Greek_NU = 0x7cd +XK_Greek_XI = 0x7ce +XK_Greek_OMICRON = 0x7cf +XK_Greek_PI = 0x7d0 +XK_Greek_RHO = 0x7d1 +XK_Greek_SIGMA = 0x7d2 +XK_Greek_TAU = 0x7d4 +XK_Greek_UPSILON = 0x7d5 +XK_Greek_PHI = 0x7d6 +XK_Greek_CHI = 0x7d7 +XK_Greek_PSI = 0x7d8 +XK_Greek_OMEGA = 0x7d9 +XK_Greek_alpha = 0x7e1 +XK_Greek_beta = 0x7e2 +XK_Greek_gamma = 0x7e3 +XK_Greek_delta = 0x7e4 +XK_Greek_epsilon = 0x7e5 +XK_Greek_zeta = 0x7e6 +XK_Greek_eta = 0x7e7 +XK_Greek_theta = 0x7e8 +XK_Greek_iota = 0x7e9 +XK_Greek_kappa = 0x7ea +XK_Greek_lamda = 0x7eb +XK_Greek_lambda = 0x7eb +XK_Greek_mu = 0x7ec +XK_Greek_nu = 0x7ed +XK_Greek_xi = 0x7ee +XK_Greek_omicron = 0x7ef +XK_Greek_pi = 0x7f0 +XK_Greek_rho = 0x7f1 +XK_Greek_sigma = 0x7f2 +XK_Greek_finalsmallsigma = 0x7f3 +XK_Greek_tau = 0x7f4 +XK_Greek_upsilon = 0x7f5 +XK_Greek_phi = 0x7f6 +XK_Greek_chi = 0x7f7 +XK_Greek_psi = 0x7f8 +XK_Greek_omega = 0x7f9 +XK_Greek_switch = 0xFF7E diff --git a/Xlib/keysymdef/hebrew.py b/Xlib/keysymdef/hebrew.py new file mode 100644 index 0000000..e00e9e2 --- /dev/null +++ b/Xlib/keysymdef/hebrew.py @@ -0,0 +1,40 @@ +XK_hebrew_doublelowline = 0xcdf +XK_hebrew_aleph = 0xce0 +XK_hebrew_bet = 0xce1 +XK_hebrew_beth = 0xce1 +XK_hebrew_gimel = 0xce2 +XK_hebrew_gimmel = 0xce2 +XK_hebrew_dalet = 0xce3 +XK_hebrew_daleth = 0xce3 +XK_hebrew_he = 0xce4 +XK_hebrew_waw = 0xce5 +XK_hebrew_zain = 0xce6 +XK_hebrew_zayin = 0xce6 +XK_hebrew_chet = 0xce7 +XK_hebrew_het = 0xce7 +XK_hebrew_tet = 0xce8 +XK_hebrew_teth = 0xce8 +XK_hebrew_yod = 0xce9 +XK_hebrew_finalkaph = 0xcea +XK_hebrew_kaph = 0xceb +XK_hebrew_lamed = 0xcec +XK_hebrew_finalmem = 0xced +XK_hebrew_mem = 0xcee +XK_hebrew_finalnun = 0xcef +XK_hebrew_nun = 0xcf0 +XK_hebrew_samech = 0xcf1 +XK_hebrew_samekh = 0xcf1 +XK_hebrew_ayin = 0xcf2 +XK_hebrew_finalpe = 0xcf3 +XK_hebrew_pe = 0xcf4 +XK_hebrew_finalzade = 0xcf5 +XK_hebrew_finalzadi = 0xcf5 +XK_hebrew_zade = 0xcf6 +XK_hebrew_zadi = 0xcf6 +XK_hebrew_qoph = 0xcf7 +XK_hebrew_kuf = 0xcf7 +XK_hebrew_resh = 0xcf8 +XK_hebrew_shin = 0xcf9 +XK_hebrew_taw = 0xcfa +XK_hebrew_taf = 0xcfa +XK_Hebrew_switch = 0xFF7E diff --git a/Xlib/keysymdef/katakana.py b/Xlib/keysymdef/katakana.py new file mode 100644 index 0000000..2d46eed --- /dev/null +++ b/Xlib/keysymdef/katakana.py @@ -0,0 +1,70 @@ +XK_overline = 0x47e +XK_kana_fullstop = 0x4a1 +XK_kana_openingbracket = 0x4a2 +XK_kana_closingbracket = 0x4a3 +XK_kana_comma = 0x4a4 +XK_kana_conjunctive = 0x4a5 +XK_kana_middledot = 0x4a5 +XK_kana_WO = 0x4a6 +XK_kana_a = 0x4a7 +XK_kana_i = 0x4a8 +XK_kana_u = 0x4a9 +XK_kana_e = 0x4aa +XK_kana_o = 0x4ab +XK_kana_ya = 0x4ac +XK_kana_yu = 0x4ad +XK_kana_yo = 0x4ae +XK_kana_tsu = 0x4af +XK_kana_tu = 0x4af +XK_prolongedsound = 0x4b0 +XK_kana_A = 0x4b1 +XK_kana_I = 0x4b2 +XK_kana_U = 0x4b3 +XK_kana_E = 0x4b4 +XK_kana_O = 0x4b5 +XK_kana_KA = 0x4b6 +XK_kana_KI = 0x4b7 +XK_kana_KU = 0x4b8 +XK_kana_KE = 0x4b9 +XK_kana_KO = 0x4ba +XK_kana_SA = 0x4bb +XK_kana_SHI = 0x4bc +XK_kana_SU = 0x4bd +XK_kana_SE = 0x4be +XK_kana_SO = 0x4bf +XK_kana_TA = 0x4c0 +XK_kana_CHI = 0x4c1 +XK_kana_TI = 0x4c1 +XK_kana_TSU = 0x4c2 +XK_kana_TU = 0x4c2 +XK_kana_TE = 0x4c3 +XK_kana_TO = 0x4c4 +XK_kana_NA = 0x4c5 +XK_kana_NI = 0x4c6 +XK_kana_NU = 0x4c7 +XK_kana_NE = 0x4c8 +XK_kana_NO = 0x4c9 +XK_kana_HA = 0x4ca +XK_kana_HI = 0x4cb +XK_kana_FU = 0x4cc +XK_kana_HU = 0x4cc +XK_kana_HE = 0x4cd +XK_kana_HO = 0x4ce +XK_kana_MA = 0x4cf +XK_kana_MI = 0x4d0 +XK_kana_MU = 0x4d1 +XK_kana_ME = 0x4d2 +XK_kana_MO = 0x4d3 +XK_kana_YA = 0x4d4 +XK_kana_YU = 0x4d5 +XK_kana_YO = 0x4d6 +XK_kana_RA = 0x4d7 +XK_kana_RI = 0x4d8 +XK_kana_RU = 0x4d9 +XK_kana_RE = 0x4da +XK_kana_RO = 0x4db +XK_kana_WA = 0x4dc +XK_kana_N = 0x4dd +XK_voicedsound = 0x4de +XK_semivoicedsound = 0x4df +XK_kana_switch = 0xFF7E diff --git a/Xlib/keysymdef/korean.py b/Xlib/keysymdef/korean.py new file mode 100644 index 0000000..1383cde --- /dev/null +++ b/Xlib/keysymdef/korean.py @@ -0,0 +1,107 @@ +XK_Hangul = 0xff31 +XK_Hangul_Start = 0xff32 +XK_Hangul_End = 0xff33 +XK_Hangul_Hanja = 0xff34 +XK_Hangul_Jamo = 0xff35 +XK_Hangul_Romaja = 0xff36 +XK_Hangul_Codeinput = 0xff37 +XK_Hangul_Jeonja = 0xff38 +XK_Hangul_Banja = 0xff39 +XK_Hangul_PreHanja = 0xff3a +XK_Hangul_PostHanja = 0xff3b +XK_Hangul_SingleCandidate = 0xff3c +XK_Hangul_MultipleCandidate = 0xff3d +XK_Hangul_PreviousCandidate = 0xff3e +XK_Hangul_Special = 0xff3f +XK_Hangul_switch = 0xFF7E +XK_Hangul_Kiyeog = 0xea1 +XK_Hangul_SsangKiyeog = 0xea2 +XK_Hangul_KiyeogSios = 0xea3 +XK_Hangul_Nieun = 0xea4 +XK_Hangul_NieunJieuj = 0xea5 +XK_Hangul_NieunHieuh = 0xea6 +XK_Hangul_Dikeud = 0xea7 +XK_Hangul_SsangDikeud = 0xea8 +XK_Hangul_Rieul = 0xea9 +XK_Hangul_RieulKiyeog = 0xeaa +XK_Hangul_RieulMieum = 0xeab +XK_Hangul_RieulPieub = 0xeac +XK_Hangul_RieulSios = 0xead +XK_Hangul_RieulTieut = 0xeae +XK_Hangul_RieulPhieuf = 0xeaf +XK_Hangul_RieulHieuh = 0xeb0 +XK_Hangul_Mieum = 0xeb1 +XK_Hangul_Pieub = 0xeb2 +XK_Hangul_SsangPieub = 0xeb3 +XK_Hangul_PieubSios = 0xeb4 +XK_Hangul_Sios = 0xeb5 +XK_Hangul_SsangSios = 0xeb6 +XK_Hangul_Ieung = 0xeb7 +XK_Hangul_Jieuj = 0xeb8 +XK_Hangul_SsangJieuj = 0xeb9 +XK_Hangul_Cieuc = 0xeba +XK_Hangul_Khieuq = 0xebb +XK_Hangul_Tieut = 0xebc +XK_Hangul_Phieuf = 0xebd +XK_Hangul_Hieuh = 0xebe +XK_Hangul_A = 0xebf +XK_Hangul_AE = 0xec0 +XK_Hangul_YA = 0xec1 +XK_Hangul_YAE = 0xec2 +XK_Hangul_EO = 0xec3 +XK_Hangul_E = 0xec4 +XK_Hangul_YEO = 0xec5 +XK_Hangul_YE = 0xec6 +XK_Hangul_O = 0xec7 +XK_Hangul_WA = 0xec8 +XK_Hangul_WAE = 0xec9 +XK_Hangul_OE = 0xeca +XK_Hangul_YO = 0xecb +XK_Hangul_U = 0xecc +XK_Hangul_WEO = 0xecd +XK_Hangul_WE = 0xece +XK_Hangul_WI = 0xecf +XK_Hangul_YU = 0xed0 +XK_Hangul_EU = 0xed1 +XK_Hangul_YI = 0xed2 +XK_Hangul_I = 0xed3 +XK_Hangul_J_Kiyeog = 0xed4 +XK_Hangul_J_SsangKiyeog = 0xed5 +XK_Hangul_J_KiyeogSios = 0xed6 +XK_Hangul_J_Nieun = 0xed7 +XK_Hangul_J_NieunJieuj = 0xed8 +XK_Hangul_J_NieunHieuh = 0xed9 +XK_Hangul_J_Dikeud = 0xeda +XK_Hangul_J_Rieul = 0xedb +XK_Hangul_J_RieulKiyeog = 0xedc +XK_Hangul_J_RieulMieum = 0xedd +XK_Hangul_J_RieulPieub = 0xede +XK_Hangul_J_RieulSios = 0xedf +XK_Hangul_J_RieulTieut = 0xee0 +XK_Hangul_J_RieulPhieuf = 0xee1 +XK_Hangul_J_RieulHieuh = 0xee2 +XK_Hangul_J_Mieum = 0xee3 +XK_Hangul_J_Pieub = 0xee4 +XK_Hangul_J_PieubSios = 0xee5 +XK_Hangul_J_Sios = 0xee6 +XK_Hangul_J_SsangSios = 0xee7 +XK_Hangul_J_Ieung = 0xee8 +XK_Hangul_J_Jieuj = 0xee9 +XK_Hangul_J_Cieuc = 0xeea +XK_Hangul_J_Khieuq = 0xeeb +XK_Hangul_J_Tieut = 0xeec +XK_Hangul_J_Phieuf = 0xeed +XK_Hangul_J_Hieuh = 0xeee +XK_Hangul_RieulYeorinHieuh = 0xeef +XK_Hangul_SunkyeongeumMieum = 0xef0 +XK_Hangul_SunkyeongeumPieub = 0xef1 +XK_Hangul_PanSios = 0xef2 +XK_Hangul_KkogjiDalrinIeung = 0xef3 +XK_Hangul_SunkyeongeumPhieuf = 0xef4 +XK_Hangul_YeorinHieuh = 0xef5 +XK_Hangul_AraeA = 0xef6 +XK_Hangul_AraeAE = 0xef7 +XK_Hangul_J_PanSios = 0xef8 +XK_Hangul_J_KkogjiDalrinIeung = 0xef9 +XK_Hangul_J_YeorinHieuh = 0xefa +XK_Korean_Won = 0xeff diff --git a/Xlib/keysymdef/latin1.py b/Xlib/keysymdef/latin1.py new file mode 100644 index 0000000..92af9b1 --- /dev/null +++ b/Xlib/keysymdef/latin1.py @@ -0,0 +1,195 @@ +XK_space = 0x020 +XK_exclam = 0x021 +XK_quotedbl = 0x022 +XK_numbersign = 0x023 +XK_dollar = 0x024 +XK_percent = 0x025 +XK_ampersand = 0x026 +XK_apostrophe = 0x027 +XK_quoteright = 0x027 +XK_parenleft = 0x028 +XK_parenright = 0x029 +XK_asterisk = 0x02a +XK_plus = 0x02b +XK_comma = 0x02c +XK_minus = 0x02d +XK_period = 0x02e +XK_slash = 0x02f +XK_0 = 0x030 +XK_1 = 0x031 +XK_2 = 0x032 +XK_3 = 0x033 +XK_4 = 0x034 +XK_5 = 0x035 +XK_6 = 0x036 +XK_7 = 0x037 +XK_8 = 0x038 +XK_9 = 0x039 +XK_colon = 0x03a +XK_semicolon = 0x03b +XK_less = 0x03c +XK_equal = 0x03d +XK_greater = 0x03e +XK_question = 0x03f +XK_at = 0x040 +XK_A = 0x041 +XK_B = 0x042 +XK_C = 0x043 +XK_D = 0x044 +XK_E = 0x045 +XK_F = 0x046 +XK_G = 0x047 +XK_H = 0x048 +XK_I = 0x049 +XK_J = 0x04a +XK_K = 0x04b +XK_L = 0x04c +XK_M = 0x04d +XK_N = 0x04e +XK_O = 0x04f +XK_P = 0x050 +XK_Q = 0x051 +XK_R = 0x052 +XK_S = 0x053 +XK_T = 0x054 +XK_U = 0x055 +XK_V = 0x056 +XK_W = 0x057 +XK_X = 0x058 +XK_Y = 0x059 +XK_Z = 0x05a +XK_bracketleft = 0x05b +XK_backslash = 0x05c +XK_bracketright = 0x05d +XK_asciicircum = 0x05e +XK_underscore = 0x05f +XK_grave = 0x060 +XK_quoteleft = 0x060 +XK_a = 0x061 +XK_b = 0x062 +XK_c = 0x063 +XK_d = 0x064 +XK_e = 0x065 +XK_f = 0x066 +XK_g = 0x067 +XK_h = 0x068 +XK_i = 0x069 +XK_j = 0x06a +XK_k = 0x06b +XK_l = 0x06c +XK_m = 0x06d +XK_n = 0x06e +XK_o = 0x06f +XK_p = 0x070 +XK_q = 0x071 +XK_r = 0x072 +XK_s = 0x073 +XK_t = 0x074 +XK_u = 0x075 +XK_v = 0x076 +XK_w = 0x077 +XK_x = 0x078 +XK_y = 0x079 +XK_z = 0x07a +XK_braceleft = 0x07b +XK_bar = 0x07c +XK_braceright = 0x07d +XK_asciitilde = 0x07e +XK_nobreakspace = 0x0a0 +XK_exclamdown = 0x0a1 +XK_cent = 0x0a2 +XK_sterling = 0x0a3 +XK_currency = 0x0a4 +XK_yen = 0x0a5 +XK_brokenbar = 0x0a6 +XK_section = 0x0a7 +XK_diaeresis = 0x0a8 +XK_copyright = 0x0a9 +XK_ordfeminine = 0x0aa +XK_guillemotleft = 0x0ab +XK_notsign = 0x0ac +XK_hyphen = 0x0ad +XK_registered = 0x0ae +XK_macron = 0x0af +XK_degree = 0x0b0 +XK_plusminus = 0x0b1 +XK_twosuperior = 0x0b2 +XK_threesuperior = 0x0b3 +XK_acute = 0x0b4 +XK_mu = 0x0b5 +XK_paragraph = 0x0b6 +XK_periodcentered = 0x0b7 +XK_cedilla = 0x0b8 +XK_onesuperior = 0x0b9 +XK_masculine = 0x0ba +XK_guillemotright = 0x0bb +XK_onequarter = 0x0bc +XK_onehalf = 0x0bd +XK_threequarters = 0x0be +XK_questiondown = 0x0bf +XK_Agrave = 0x0c0 +XK_Aacute = 0x0c1 +XK_Acircumflex = 0x0c2 +XK_Atilde = 0x0c3 +XK_Adiaeresis = 0x0c4 +XK_Aring = 0x0c5 +XK_AE = 0x0c6 +XK_Ccedilla = 0x0c7 +XK_Egrave = 0x0c8 +XK_Eacute = 0x0c9 +XK_Ecircumflex = 0x0ca +XK_Ediaeresis = 0x0cb +XK_Igrave = 0x0cc +XK_Iacute = 0x0cd +XK_Icircumflex = 0x0ce +XK_Idiaeresis = 0x0cf +XK_ETH = 0x0d0 +XK_Eth = 0x0d0 +XK_Ntilde = 0x0d1 +XK_Ograve = 0x0d2 +XK_Oacute = 0x0d3 +XK_Ocircumflex = 0x0d4 +XK_Otilde = 0x0d5 +XK_Odiaeresis = 0x0d6 +XK_multiply = 0x0d7 +XK_Ooblique = 0x0d8 +XK_Ugrave = 0x0d9 +XK_Uacute = 0x0da +XK_Ucircumflex = 0x0db +XK_Udiaeresis = 0x0dc +XK_Yacute = 0x0dd +XK_THORN = 0x0de +XK_Thorn = 0x0de +XK_ssharp = 0x0df +XK_agrave = 0x0e0 +XK_aacute = 0x0e1 +XK_acircumflex = 0x0e2 +XK_atilde = 0x0e3 +XK_adiaeresis = 0x0e4 +XK_aring = 0x0e5 +XK_ae = 0x0e6 +XK_ccedilla = 0x0e7 +XK_egrave = 0x0e8 +XK_eacute = 0x0e9 +XK_ecircumflex = 0x0ea +XK_ediaeresis = 0x0eb +XK_igrave = 0x0ec +XK_iacute = 0x0ed +XK_icircumflex = 0x0ee +XK_idiaeresis = 0x0ef +XK_eth = 0x0f0 +XK_ntilde = 0x0f1 +XK_ograve = 0x0f2 +XK_oacute = 0x0f3 +XK_ocircumflex = 0x0f4 +XK_otilde = 0x0f5 +XK_odiaeresis = 0x0f6 +XK_division = 0x0f7 +XK_oslash = 0x0f8 +XK_ugrave = 0x0f9 +XK_uacute = 0x0fa +XK_ucircumflex = 0x0fb +XK_udiaeresis = 0x0fc +XK_yacute = 0x0fd +XK_thorn = 0x0fe +XK_ydiaeresis = 0x0ff diff --git a/Xlib/keysymdef/latin2.py b/Xlib/keysymdef/latin2.py new file mode 100644 index 0000000..d0a151c --- /dev/null +++ b/Xlib/keysymdef/latin2.py @@ -0,0 +1,57 @@ +XK_Aogonek = 0x1a1 +XK_breve = 0x1a2 +XK_Lstroke = 0x1a3 +XK_Lcaron = 0x1a5 +XK_Sacute = 0x1a6 +XK_Scaron = 0x1a9 +XK_Scedilla = 0x1aa +XK_Tcaron = 0x1ab +XK_Zacute = 0x1ac +XK_Zcaron = 0x1ae +XK_Zabovedot = 0x1af +XK_aogonek = 0x1b1 +XK_ogonek = 0x1b2 +XK_lstroke = 0x1b3 +XK_lcaron = 0x1b5 +XK_sacute = 0x1b6 +XK_caron = 0x1b7 +XK_scaron = 0x1b9 +XK_scedilla = 0x1ba +XK_tcaron = 0x1bb +XK_zacute = 0x1bc +XK_doubleacute = 0x1bd +XK_zcaron = 0x1be +XK_zabovedot = 0x1bf +XK_Racute = 0x1c0 +XK_Abreve = 0x1c3 +XK_Lacute = 0x1c5 +XK_Cacute = 0x1c6 +XK_Ccaron = 0x1c8 +XK_Eogonek = 0x1ca +XK_Ecaron = 0x1cc +XK_Dcaron = 0x1cf +XK_Dstroke = 0x1d0 +XK_Nacute = 0x1d1 +XK_Ncaron = 0x1d2 +XK_Odoubleacute = 0x1d5 +XK_Rcaron = 0x1d8 +XK_Uring = 0x1d9 +XK_Udoubleacute = 0x1db +XK_Tcedilla = 0x1de +XK_racute = 0x1e0 +XK_abreve = 0x1e3 +XK_lacute = 0x1e5 +XK_cacute = 0x1e6 +XK_ccaron = 0x1e8 +XK_eogonek = 0x1ea +XK_ecaron = 0x1ec +XK_dcaron = 0x1ef +XK_dstroke = 0x1f0 +XK_nacute = 0x1f1 +XK_ncaron = 0x1f2 +XK_odoubleacute = 0x1f5 +XK_udoubleacute = 0x1fb +XK_rcaron = 0x1f8 +XK_uring = 0x1f9 +XK_tcedilla = 0x1fe +XK_abovedot = 0x1ff diff --git a/Xlib/keysymdef/latin3.py b/Xlib/keysymdef/latin3.py new file mode 100644 index 0000000..7c64ca1 --- /dev/null +++ b/Xlib/keysymdef/latin3.py @@ -0,0 +1,22 @@ +XK_Hstroke = 0x2a1 +XK_Hcircumflex = 0x2a6 +XK_Iabovedot = 0x2a9 +XK_Gbreve = 0x2ab +XK_Jcircumflex = 0x2ac +XK_hstroke = 0x2b1 +XK_hcircumflex = 0x2b6 +XK_idotless = 0x2b9 +XK_gbreve = 0x2bb +XK_jcircumflex = 0x2bc +XK_Cabovedot = 0x2c5 +XK_Ccircumflex = 0x2c6 +XK_Gabovedot = 0x2d5 +XK_Gcircumflex = 0x2d8 +XK_Ubreve = 0x2dd +XK_Scircumflex = 0x2de +XK_cabovedot = 0x2e5 +XK_ccircumflex = 0x2e6 +XK_gabovedot = 0x2f5 +XK_gcircumflex = 0x2f8 +XK_ubreve = 0x2fd +XK_scircumflex = 0x2fe diff --git a/Xlib/keysymdef/latin4.py b/Xlib/keysymdef/latin4.py new file mode 100644 index 0000000..3a5924b --- /dev/null +++ b/Xlib/keysymdef/latin4.py @@ -0,0 +1,36 @@ +XK_kra = 0x3a2 +XK_kappa = 0x3a2 +XK_Rcedilla = 0x3a3 +XK_Itilde = 0x3a5 +XK_Lcedilla = 0x3a6 +XK_Emacron = 0x3aa +XK_Gcedilla = 0x3ab +XK_Tslash = 0x3ac +XK_rcedilla = 0x3b3 +XK_itilde = 0x3b5 +XK_lcedilla = 0x3b6 +XK_emacron = 0x3ba +XK_gcedilla = 0x3bb +XK_tslash = 0x3bc +XK_ENG = 0x3bd +XK_eng = 0x3bf +XK_Amacron = 0x3c0 +XK_Iogonek = 0x3c7 +XK_Eabovedot = 0x3cc +XK_Imacron = 0x3cf +XK_Ncedilla = 0x3d1 +XK_Omacron = 0x3d2 +XK_Kcedilla = 0x3d3 +XK_Uogonek = 0x3d9 +XK_Utilde = 0x3dd +XK_Umacron = 0x3de +XK_amacron = 0x3e0 +XK_iogonek = 0x3e7 +XK_eabovedot = 0x3ec +XK_imacron = 0x3ef +XK_ncedilla = 0x3f1 +XK_omacron = 0x3f2 +XK_kcedilla = 0x3f3 +XK_uogonek = 0x3f9 +XK_utilde = 0x3fd +XK_umacron = 0x3fe diff --git a/Xlib/keysymdef/miscellany.py b/Xlib/keysymdef/miscellany.py new file mode 100644 index 0000000..fdfefbe --- /dev/null +++ b/Xlib/keysymdef/miscellany.py @@ -0,0 +1,169 @@ +XK_BackSpace = 0xFF08 +XK_Tab = 0xFF09 +XK_Linefeed = 0xFF0A +XK_Clear = 0xFF0B +XK_Return = 0xFF0D +XK_Pause = 0xFF13 +XK_Scroll_Lock = 0xFF14 +XK_Sys_Req = 0xFF15 +XK_Escape = 0xFF1B +XK_Delete = 0xFFFF +XK_Multi_key = 0xFF20 +XK_SingleCandidate = 0xFF3C +XK_MultipleCandidate = 0xFF3D +XK_PreviousCandidate = 0xFF3E +XK_Kanji = 0xFF21 +XK_Muhenkan = 0xFF22 +XK_Henkan_Mode = 0xFF23 +XK_Henkan = 0xFF23 +XK_Romaji = 0xFF24 +XK_Hiragana = 0xFF25 +XK_Katakana = 0xFF26 +XK_Hiragana_Katakana = 0xFF27 +XK_Zenkaku = 0xFF28 +XK_Hankaku = 0xFF29 +XK_Zenkaku_Hankaku = 0xFF2A +XK_Touroku = 0xFF2B +XK_Massyo = 0xFF2C +XK_Kana_Lock = 0xFF2D +XK_Kana_Shift = 0xFF2E +XK_Eisu_Shift = 0xFF2F +XK_Eisu_toggle = 0xFF30 +XK_Zen_Koho = 0xFF3D +XK_Mae_Koho = 0xFF3E +XK_Home = 0xFF50 +XK_Left = 0xFF51 +XK_Up = 0xFF52 +XK_Right = 0xFF53 +XK_Down = 0xFF54 +XK_Prior = 0xFF55 +XK_Page_Up = 0xFF55 +XK_Next = 0xFF56 +XK_Page_Down = 0xFF56 +XK_End = 0xFF57 +XK_Begin = 0xFF58 +XK_Select = 0xFF60 +XK_Print = 0xFF61 +XK_Execute = 0xFF62 +XK_Insert = 0xFF63 +XK_Undo = 0xFF65 +XK_Redo = 0xFF66 +XK_Menu = 0xFF67 +XK_Find = 0xFF68 +XK_Cancel = 0xFF69 +XK_Help = 0xFF6A +XK_Break = 0xFF6B +XK_Mode_switch = 0xFF7E +XK_script_switch = 0xFF7E +XK_Num_Lock = 0xFF7F +XK_KP_Space = 0xFF80 +XK_KP_Tab = 0xFF89 +XK_KP_Enter = 0xFF8D +XK_KP_F1 = 0xFF91 +XK_KP_F2 = 0xFF92 +XK_KP_F3 = 0xFF93 +XK_KP_F4 = 0xFF94 +XK_KP_Home = 0xFF95 +XK_KP_Left = 0xFF96 +XK_KP_Up = 0xFF97 +XK_KP_Right = 0xFF98 +XK_KP_Down = 0xFF99 +XK_KP_Prior = 0xFF9A +XK_KP_Page_Up = 0xFF9A +XK_KP_Next = 0xFF9B +XK_KP_Page_Down = 0xFF9B +XK_KP_End = 0xFF9C +XK_KP_Begin = 0xFF9D +XK_KP_Insert = 0xFF9E +XK_KP_Delete = 0xFF9F +XK_KP_Equal = 0xFFBD +XK_KP_Multiply = 0xFFAA +XK_KP_Add = 0xFFAB +XK_KP_Separator = 0xFFAC +XK_KP_Subtract = 0xFFAD +XK_KP_Decimal = 0xFFAE +XK_KP_Divide = 0xFFAF +XK_KP_0 = 0xFFB0 +XK_KP_1 = 0xFFB1 +XK_KP_2 = 0xFFB2 +XK_KP_3 = 0xFFB3 +XK_KP_4 = 0xFFB4 +XK_KP_5 = 0xFFB5 +XK_KP_6 = 0xFFB6 +XK_KP_7 = 0xFFB7 +XK_KP_8 = 0xFFB8 +XK_KP_9 = 0xFFB9 +XK_F1 = 0xFFBE +XK_F2 = 0xFFBF +XK_F3 = 0xFFC0 +XK_F4 = 0xFFC1 +XK_F5 = 0xFFC2 +XK_F6 = 0xFFC3 +XK_F7 = 0xFFC4 +XK_F8 = 0xFFC5 +XK_F9 = 0xFFC6 +XK_F10 = 0xFFC7 +XK_F11 = 0xFFC8 +XK_L1 = 0xFFC8 +XK_F12 = 0xFFC9 +XK_L2 = 0xFFC9 +XK_F13 = 0xFFCA +XK_L3 = 0xFFCA +XK_F14 = 0xFFCB +XK_L4 = 0xFFCB +XK_F15 = 0xFFCC +XK_L5 = 0xFFCC +XK_F16 = 0xFFCD +XK_L6 = 0xFFCD +XK_F17 = 0xFFCE +XK_L7 = 0xFFCE +XK_F18 = 0xFFCF +XK_L8 = 0xFFCF +XK_F19 = 0xFFD0 +XK_L9 = 0xFFD0 +XK_F20 = 0xFFD1 +XK_L10 = 0xFFD1 +XK_F21 = 0xFFD2 +XK_R1 = 0xFFD2 +XK_F22 = 0xFFD3 +XK_R2 = 0xFFD3 +XK_F23 = 0xFFD4 +XK_R3 = 0xFFD4 +XK_F24 = 0xFFD5 +XK_R4 = 0xFFD5 +XK_F25 = 0xFFD6 +XK_R5 = 0xFFD6 +XK_F26 = 0xFFD7 +XK_R6 = 0xFFD7 +XK_F27 = 0xFFD8 +XK_R7 = 0xFFD8 +XK_F28 = 0xFFD9 +XK_R8 = 0xFFD9 +XK_F29 = 0xFFDA +XK_R9 = 0xFFDA +XK_F30 = 0xFFDB +XK_R10 = 0xFFDB +XK_F31 = 0xFFDC +XK_R11 = 0xFFDC +XK_F32 = 0xFFDD +XK_R12 = 0xFFDD +XK_F33 = 0xFFDE +XK_R13 = 0xFFDE +XK_F34 = 0xFFDF +XK_R14 = 0xFFDF +XK_F35 = 0xFFE0 +XK_R15 = 0xFFE0 +XK_Shift_L = 0xFFE1 +XK_Shift_R = 0xFFE2 +XK_Control_L = 0xFFE3 +XK_Control_R = 0xFFE4 +XK_Caps_Lock = 0xFFE5 +XK_Shift_Lock = 0xFFE6 +XK_Meta_L = 0xFFE7 +XK_Meta_R = 0xFFE8 +XK_Alt_L = 0xFFE9 +XK_Alt_R = 0xFFEA +XK_Super_L = 0xFFEB +XK_Super_R = 0xFFEC +XK_Hyper_L = 0xFFED +XK_Hyper_R = 0xFFEE diff --git a/Xlib/keysymdef/publishing.py b/Xlib/keysymdef/publishing.py new file mode 100644 index 0000000..e26f1be --- /dev/null +++ b/Xlib/keysymdef/publishing.py @@ -0,0 +1,83 @@ +XK_emspace = 0xaa1 +XK_enspace = 0xaa2 +XK_em3space = 0xaa3 +XK_em4space = 0xaa4 +XK_digitspace = 0xaa5 +XK_punctspace = 0xaa6 +XK_thinspace = 0xaa7 +XK_hairspace = 0xaa8 +XK_emdash = 0xaa9 +XK_endash = 0xaaa +XK_signifblank = 0xaac +XK_ellipsis = 0xaae +XK_doubbaselinedot = 0xaaf +XK_onethird = 0xab0 +XK_twothirds = 0xab1 +XK_onefifth = 0xab2 +XK_twofifths = 0xab3 +XK_threefifths = 0xab4 +XK_fourfifths = 0xab5 +XK_onesixth = 0xab6 +XK_fivesixths = 0xab7 +XK_careof = 0xab8 +XK_figdash = 0xabb +XK_leftanglebracket = 0xabc +XK_decimalpoint = 0xabd +XK_rightanglebracket = 0xabe +XK_marker = 0xabf +XK_oneeighth = 0xac3 +XK_threeeighths = 0xac4 +XK_fiveeighths = 0xac5 +XK_seveneighths = 0xac6 +XK_trademark = 0xac9 +XK_signaturemark = 0xaca +XK_trademarkincircle = 0xacb +XK_leftopentriangle = 0xacc +XK_rightopentriangle = 0xacd +XK_emopencircle = 0xace +XK_emopenrectangle = 0xacf +XK_leftsinglequotemark = 0xad0 +XK_rightsinglequotemark = 0xad1 +XK_leftdoublequotemark = 0xad2 +XK_rightdoublequotemark = 0xad3 +XK_prescription = 0xad4 +XK_minutes = 0xad6 +XK_seconds = 0xad7 +XK_latincross = 0xad9 +XK_hexagram = 0xada +XK_filledrectbullet = 0xadb +XK_filledlefttribullet = 0xadc +XK_filledrighttribullet = 0xadd +XK_emfilledcircle = 0xade +XK_emfilledrect = 0xadf +XK_enopencircbullet = 0xae0 +XK_enopensquarebullet = 0xae1 +XK_openrectbullet = 0xae2 +XK_opentribulletup = 0xae3 +XK_opentribulletdown = 0xae4 +XK_openstar = 0xae5 +XK_enfilledcircbullet = 0xae6 +XK_enfilledsqbullet = 0xae7 +XK_filledtribulletup = 0xae8 +XK_filledtribulletdown = 0xae9 +XK_leftpointer = 0xaea +XK_rightpointer = 0xaeb +XK_club = 0xaec +XK_diamond = 0xaed +XK_heart = 0xaee +XK_maltesecross = 0xaf0 +XK_dagger = 0xaf1 +XK_doubledagger = 0xaf2 +XK_checkmark = 0xaf3 +XK_ballotcross = 0xaf4 +XK_musicalsharp = 0xaf5 +XK_musicalflat = 0xaf6 +XK_malesymbol = 0xaf7 +XK_femalesymbol = 0xaf8 +XK_telephone = 0xaf9 +XK_telephonerecorder = 0xafa +XK_phonographcopyright = 0xafb +XK_caret = 0xafc +XK_singlelowquotemark = 0xafd +XK_doublelowquotemark = 0xafe +XK_cursor = 0xaff diff --git a/Xlib/keysymdef/special.py b/Xlib/keysymdef/special.py new file mode 100644 index 0000000..dc76c17 --- /dev/null +++ b/Xlib/keysymdef/special.py @@ -0,0 +1,24 @@ +XK_blank = 0x9df +XK_soliddiamond = 0x9e0 +XK_checkerboard = 0x9e1 +XK_ht = 0x9e2 +XK_ff = 0x9e3 +XK_cr = 0x9e4 +XK_lf = 0x9e5 +XK_nl = 0x9e8 +XK_vt = 0x9e9 +XK_lowrightcorner = 0x9ea +XK_uprightcorner = 0x9eb +XK_upleftcorner = 0x9ec +XK_lowleftcorner = 0x9ed +XK_crossinglines = 0x9ee +XK_horizlinescan1 = 0x9ef +XK_horizlinescan3 = 0x9f0 +XK_horizlinescan5 = 0x9f1 +XK_horizlinescan7 = 0x9f2 +XK_horizlinescan9 = 0x9f3 +XK_leftt = 0x9f4 +XK_rightt = 0x9f5 +XK_bott = 0x9f6 +XK_topt = 0x9f7 +XK_vertbar = 0x9f8 diff --git a/Xlib/keysymdef/technical.py b/Xlib/keysymdef/technical.py new file mode 100644 index 0000000..00aa7a8 --- /dev/null +++ b/Xlib/keysymdef/technical.py @@ -0,0 +1,49 @@ +XK_leftradical = 0x8a1 +XK_topleftradical = 0x8a2 +XK_horizconnector = 0x8a3 +XK_topintegral = 0x8a4 +XK_botintegral = 0x8a5 +XK_vertconnector = 0x8a6 +XK_topleftsqbracket = 0x8a7 +XK_botleftsqbracket = 0x8a8 +XK_toprightsqbracket = 0x8a9 +XK_botrightsqbracket = 0x8aa +XK_topleftparens = 0x8ab +XK_botleftparens = 0x8ac +XK_toprightparens = 0x8ad +XK_botrightparens = 0x8ae +XK_leftmiddlecurlybrace = 0x8af +XK_rightmiddlecurlybrace = 0x8b0 +XK_topleftsummation = 0x8b1 +XK_botleftsummation = 0x8b2 +XK_topvertsummationconnector = 0x8b3 +XK_botvertsummationconnector = 0x8b4 +XK_toprightsummation = 0x8b5 +XK_botrightsummation = 0x8b6 +XK_rightmiddlesummation = 0x8b7 +XK_lessthanequal = 0x8bc +XK_notequal = 0x8bd +XK_greaterthanequal = 0x8be +XK_integral = 0x8bf +XK_therefore = 0x8c0 +XK_variation = 0x8c1 +XK_infinity = 0x8c2 +XK_nabla = 0x8c5 +XK_approximate = 0x8c8 +XK_similarequal = 0x8c9 +XK_ifonlyif = 0x8cd +XK_implies = 0x8ce +XK_identical = 0x8cf +XK_radical = 0x8d6 +XK_includedin = 0x8da +XK_includes = 0x8db +XK_intersection = 0x8dc +XK_union = 0x8dd +XK_logicaland = 0x8de +XK_logicalor = 0x8df +XK_partialderivative = 0x8ef +XK_function = 0x8f6 +XK_leftarrow = 0x8fb +XK_uparrow = 0x8fc +XK_rightarrow = 0x8fd +XK_downarrow = 0x8fe diff --git a/Xlib/keysymdef/thai.py b/Xlib/keysymdef/thai.py new file mode 100644 index 0000000..2088f8c --- /dev/null +++ b/Xlib/keysymdef/thai.py @@ -0,0 +1,84 @@ +XK_Thai_kokai = 0xda1 +XK_Thai_khokhai = 0xda2 +XK_Thai_khokhuat = 0xda3 +XK_Thai_khokhwai = 0xda4 +XK_Thai_khokhon = 0xda5 +XK_Thai_khorakhang = 0xda6 +XK_Thai_ngongu = 0xda7 +XK_Thai_chochan = 0xda8 +XK_Thai_choching = 0xda9 +XK_Thai_chochang = 0xdaa +XK_Thai_soso = 0xdab +XK_Thai_chochoe = 0xdac +XK_Thai_yoying = 0xdad +XK_Thai_dochada = 0xdae +XK_Thai_topatak = 0xdaf +XK_Thai_thothan = 0xdb0 +XK_Thai_thonangmontho = 0xdb1 +XK_Thai_thophuthao = 0xdb2 +XK_Thai_nonen = 0xdb3 +XK_Thai_dodek = 0xdb4 +XK_Thai_totao = 0xdb5 +XK_Thai_thothung = 0xdb6 +XK_Thai_thothahan = 0xdb7 +XK_Thai_thothong = 0xdb8 +XK_Thai_nonu = 0xdb9 +XK_Thai_bobaimai = 0xdba +XK_Thai_popla = 0xdbb +XK_Thai_phophung = 0xdbc +XK_Thai_fofa = 0xdbd +XK_Thai_phophan = 0xdbe +XK_Thai_fofan = 0xdbf +XK_Thai_phosamphao = 0xdc0 +XK_Thai_moma = 0xdc1 +XK_Thai_yoyak = 0xdc2 +XK_Thai_rorua = 0xdc3 +XK_Thai_ru = 0xdc4 +XK_Thai_loling = 0xdc5 +XK_Thai_lu = 0xdc6 +XK_Thai_wowaen = 0xdc7 +XK_Thai_sosala = 0xdc8 +XK_Thai_sorusi = 0xdc9 +XK_Thai_sosua = 0xdca +XK_Thai_hohip = 0xdcb +XK_Thai_lochula = 0xdcc +XK_Thai_oang = 0xdcd +XK_Thai_honokhuk = 0xdce +XK_Thai_paiyannoi = 0xdcf +XK_Thai_saraa = 0xdd0 +XK_Thai_maihanakat = 0xdd1 +XK_Thai_saraaa = 0xdd2 +XK_Thai_saraam = 0xdd3 +XK_Thai_sarai = 0xdd4 +XK_Thai_saraii = 0xdd5 +XK_Thai_saraue = 0xdd6 +XK_Thai_sarauee = 0xdd7 +XK_Thai_sarau = 0xdd8 +XK_Thai_sarauu = 0xdd9 +XK_Thai_phinthu = 0xdda +XK_Thai_maihanakat_maitho = 0xdde +XK_Thai_baht = 0xddf +XK_Thai_sarae = 0xde0 +XK_Thai_saraae = 0xde1 +XK_Thai_sarao = 0xde2 +XK_Thai_saraaimaimuan = 0xde3 +XK_Thai_saraaimaimalai = 0xde4 +XK_Thai_lakkhangyao = 0xde5 +XK_Thai_maiyamok = 0xde6 +XK_Thai_maitaikhu = 0xde7 +XK_Thai_maiek = 0xde8 +XK_Thai_maitho = 0xde9 +XK_Thai_maitri = 0xdea +XK_Thai_maichattawa = 0xdeb +XK_Thai_thanthakhat = 0xdec +XK_Thai_nikhahit = 0xded +XK_Thai_leksun = 0xdf0 +XK_Thai_leknung = 0xdf1 +XK_Thai_leksong = 0xdf2 +XK_Thai_leksam = 0xdf3 +XK_Thai_leksi = 0xdf4 +XK_Thai_lekha = 0xdf5 +XK_Thai_lekhok = 0xdf6 +XK_Thai_lekchet = 0xdf7 +XK_Thai_lekpaet = 0xdf8 +XK_Thai_lekkao = 0xdf9 diff --git a/Xlib/keysymdef/xf86.py b/Xlib/keysymdef/xf86.py new file mode 100644 index 0000000..4ccf12a --- /dev/null +++ b/Xlib/keysymdef/xf86.py @@ -0,0 +1,202 @@ +XK_XF86_ModeLock = 0x1008FF01 + +XK_XF86_MonBrightnessUp = 0x1008FF02 +XK_XF86_MonBrightnessDown = 0x1008FF03 +XK_XF86_KbdLightOnOff = 0x1008FF04 +XK_XF86_KbdBrightnessUp = 0x1008FF05 +XK_XF86_KbdBrightnessDown = 0x1008FF06 +XK_XF86_MonBrightnessCycle = 0x1008FF07 + +XK_XF86_Standby = 0x1008FF10 +XK_XF86_AudioLowerVolume = 0x1008FF11 +XK_XF86_AudioMute = 0x1008FF12 +XK_XF86_AudioRaiseVolume = 0x1008FF13 +XK_XF86_AudioPlay = 0x1008FF14 +XK_XF86_AudioStop = 0x1008FF15 +XK_XF86_AudioPrev = 0x1008FF16 +XK_XF86_AudioNext = 0x1008FF17 +XK_XF86_HomePage = 0x1008FF18 +XK_XF86_Mail = 0x1008FF19 +XK_XF86_Start = 0x1008FF1A +XK_XF86_Search = 0x1008FF1B +XK_XF86_AudioRecord = 0x1008FF1C + +XK_XF86_Calculator = 0x1008FF1D +XK_XF86_Memo = 0x1008FF1E +XK_XF86_ToDoList = 0x1008FF1F +XK_XF86_Calendar = 0x1008FF20 +XK_XF86_PowerDown = 0x1008FF21 +XK_XF86_ContrastAdjust = 0x1008FF22 +XK_XF86_RockerUp = 0x1008FF23 +XK_XF86_RockerDown = 0x1008FF24 +XK_XF86_RockerEnter = 0x1008FF25 + +XK_XF86_Back = 0x1008FF26 +XK_XF86_Forward = 0x1008FF27 +XK_XF86_Stop = 0x1008FF28 +XK_XF86_Refresh = 0x1008FF29 +XK_XF86_PowerOff = 0x1008FF2A +XK_XF86_WakeUp = 0x1008FF2B +XK_XF86_Eject = 0x1008FF2C +XK_XF86_ScreenSaver = 0x1008FF2D +XK_XF86_WWW = 0x1008FF2E +XK_XF86_Sleep = 0x1008FF2F +XK_XF86_Favorites = 0x1008FF30 +XK_XF86_AudioPause = 0x1008FF31 +XK_XF86_AudioMedia = 0x1008FF32 +XK_XF86_MyComputer = 0x1008FF33 +XK_XF86_VendorHome = 0x1008FF34 +XK_XF86_LightBulb = 0x1008FF35 +XK_XF86_Shop = 0x1008FF36 +XK_XF86_History = 0x1008FF37 +XK_XF86_OpenURL = 0x1008FF38 +XK_XF86_AddFavorite = 0x1008FF39 +XK_XF86_HotLinks = 0x1008FF3A +XK_XF86_BrightnessAdjust = 0x1008FF3B +XK_XF86_Finance = 0x1008FF3C +XK_XF86_Community = 0x1008FF3D +XK_XF86_AudioRewind = 0x1008FF3E +XK_XF86_XF86BackForward = 0x1008FF3F +XK_XF86_Launch0 = 0x1008FF40 +XK_XF86_Launch1 = 0x1008FF41 +XK_XF86_Launch2 = 0x1008FF42 +XK_XF86_Launch3 = 0x1008FF43 +XK_XF86_Launch4 = 0x1008FF44 +XK_XF86_Launch5 = 0x1008FF45 +XK_XF86_Launch6 = 0x1008FF46 +XK_XF86_Launch7 = 0x1008FF47 +XK_XF86_Launch8 = 0x1008FF48 +XK_XF86_Launch9 = 0x1008FF49 +XK_XF86_LaunchA = 0x1008FF4A +XK_XF86_LaunchB = 0x1008FF4B +XK_XF86_LaunchC = 0x1008FF4C +XK_XF86_LaunchD = 0x1008FF4D +XK_XF86_LaunchE = 0x1008FF4E +XK_XF86_LaunchF = 0x1008FF4F + +XK_XF86_ApplicationLeft = 0x1008FF50 +XK_XF86_ApplicationRight = 0x1008FF51 +XK_XF86_Book = 0x1008FF52 +XK_XF86_CD = 0x1008FF53 +XK_XF86_Calculater = 0x1008FF54 +XK_XF86_Clear = 0x1008FF55 +XK_XF86_Close = 0x1008FF56 +XK_XF86_Copy = 0x1008FF57 +XK_XF86_Cut = 0x1008FF58 +XK_XF86_Display = 0x1008FF59 +XK_XF86_DOS = 0x1008FF5A +XK_XF86_Documents = 0x1008FF5B +XK_XF86_Excel = 0x1008FF5C +XK_XF86_Explorer = 0x1008FF5D +XK_XF86_Game = 0x1008FF5E +XK_XF86_Go = 0x1008FF5F +XK_XF86_iTouch = 0x1008FF60 +XK_XF86_LogOff = 0x1008FF61 +XK_XF86_Market = 0x1008FF62 +XK_XF86_Meeting = 0x1008FF63 +XK_XF86_MenuKB = 0x1008FF65 +XK_XF86_MenuPB = 0x1008FF66 +XK_XF86_MySites = 0x1008FF67 +XK_XF86_New = 0x1008FF68 +XK_XF86_News = 0x1008FF69 +XK_XF86_OfficeHome = 0x1008FF6A +XK_XF86_Open = 0x1008FF6B +XK_XF86_Option = 0x1008FF6C +XK_XF86_Paste = 0x1008FF6D +XK_XF86_Phone = 0x1008FF6E +XK_XF86_Q = 0x1008FF70 +XK_XF86_Reply = 0x1008FF72 +XK_XF86_Reload = 0x1008FF73 +XK_XF86_RotateWindows = 0x1008FF74 +XK_XF86_RotationPB = 0x1008FF75 +XK_XF86_RotationKB = 0x1008FF76 +XK_XF86_Save = 0x1008FF77 +XK_XF86_ScrollUp = 0x1008FF78 +XK_XF86_ScrollDown = 0x1008FF79 +XK_XF86_ScrollClick = 0x1008FF7A +XK_XF86_Send = 0x1008FF7B +XK_XF86_Spell = 0x1008FF7C +XK_XF86_SplitScreen = 0x1008FF7D +XK_XF86_Support = 0x1008FF7E +XK_XF86_TaskPane = 0x1008FF7F +XK_XF86_Terminal = 0x1008FF80 +XK_XF86_Tools = 0x1008FF81 +XK_XF86_Travel = 0x1008FF82 +XK_XF86_UserPB = 0x1008FF84 +XK_XF86_User1KB = 0x1008FF85 +XK_XF86_User2KB = 0x1008FF86 +XK_XF86_Video = 0x1008FF87 +XK_XF86_WheelButton = 0x1008FF88 +XK_XF86_Word = 0x1008FF89 +XK_XF86_Xfer = 0x1008FF8A +XK_XF86_ZoomIn = 0x1008FF8B +XK_XF86_ZoomOut = 0x1008FF8C + +XK_XF86_Away = 0x1008FF8D +XK_XF86_Messenger = 0x1008FF8E +XK_XF86_WebCam = 0x1008FF8F +XK_XF86_MailForward = 0x1008FF90 +XK_XF86_Pictures = 0x1008FF91 +XK_XF86_Music = 0x1008FF92 + +XK_XF86_Battery = 0x1008FF93 +XK_XF86_Bluetooth = 0x1008FF94 +XK_XF86_WLAN = 0x1008FF95 +XK_XF86_UWB = 0x1008FF96 + +XK_XF86_AudioForward = 0x1008FF97 +XK_XF86_AudioRepeat = 0x1008FF98 +XK_XF86_AudioRandomPlay = 0x1008FF99 +XK_XF86_Subtitle = 0x1008FF9A +XK_XF86_AudioCycleTrack = 0x1008FF9B +XK_XF86_CycleAngle = 0x1008FF9C +XK_XF86_FrameBack = 0x1008FF9D +XK_XF86_FrameForward = 0x1008FF9E +XK_XF86_Time = 0x1008FF9F +XK_XF86_Select = 0x1008FFA0 +XK_XF86_View = 0x1008FFA1 +XK_XF86_TopMenu = 0x1008FFA2 + +XK_XF86_Red = 0x1008FFA3 +XK_XF86_Green = 0x1008FFA4 +XK_XF86_Yellow = 0x1008FFA5 +XK_XF86_Blue = 0x1008FFA6 + +XK_XF86_Suspend = 0x1008FFA7 +XK_XF86_Hibernate = 0x1008FFA8 +XK_XF86_TouchpadToggle = 0x1008FFA9 +XK_XF86_TouchpadOn = 0x1008FFB0 +XK_XF86_TouchpadOff = 0x1008FFB1 + +XK_XF86_AudioMicMute = 0x1008FFB2 + +XK_XF86_Keyboard = 0x1008FFB3 + +XK_XF86_WWAN = 0x1008FFB4 +XK_XF86_RFKill = 0x1008FFB5 + +XK_XF86_AudioPreset = 0x1008FFB6 + +XK_XF86_RotationLockToggle = 0x1008FFB7 + +XK_XF86_FullScreen = 0x1008FFB8 + +XK_XF86_Switch_VT_1 = 0x1008FE01 +XK_XF86_Switch_VT_2 = 0x1008FE02 +XK_XF86_Switch_VT_3 = 0x1008FE03 +XK_XF86_Switch_VT_4 = 0x1008FE04 +XK_XF86_Switch_VT_5 = 0x1008FE05 +XK_XF86_Switch_VT_6 = 0x1008FE06 +XK_XF86_Switch_VT_7 = 0x1008FE07 +XK_XF86_Switch_VT_8 = 0x1008FE08 +XK_XF86_Switch_VT_9 = 0x1008FE09 +XK_XF86_Switch_VT_10 = 0x1008FE0A +XK_XF86_Switch_VT_11 = 0x1008FE0B +XK_XF86_Switch_VT_12 = 0x1008FE0C + +XK_XF86_Ungrab = 0x1008FE20 +XK_XF86_ClearGrab = 0x1008FE21 +XK_XF86_Next_VMode = 0x1008FE22 +XK_XF86_Prev_VMode = 0x1008FE23 +XK_XF86_LogWindowTree = 0x1008FE24 +XK_XF86_LogGrabInfo = 0x1008FE25 diff --git a/Xlib/keysymdef/xk3270.py b/Xlib/keysymdef/xk3270.py new file mode 100644 index 0000000..019ba3b --- /dev/null +++ b/Xlib/keysymdef/xk3270.py @@ -0,0 +1,30 @@ +XK_3270_Duplicate = 0xFD01 +XK_3270_FieldMark = 0xFD02 +XK_3270_Right2 = 0xFD03 +XK_3270_Left2 = 0xFD04 +XK_3270_BackTab = 0xFD05 +XK_3270_EraseEOF = 0xFD06 +XK_3270_EraseInput = 0xFD07 +XK_3270_Reset = 0xFD08 +XK_3270_Quit = 0xFD09 +XK_3270_PA1 = 0xFD0A +XK_3270_PA2 = 0xFD0B +XK_3270_PA3 = 0xFD0C +XK_3270_Test = 0xFD0D +XK_3270_Attn = 0xFD0E +XK_3270_CursorBlink = 0xFD0F +XK_3270_AltCursor = 0xFD10 +XK_3270_KeyClick = 0xFD11 +XK_3270_Jump = 0xFD12 +XK_3270_Ident = 0xFD13 +XK_3270_Rule = 0xFD14 +XK_3270_Copy = 0xFD15 +XK_3270_Play = 0xFD16 +XK_3270_Setup = 0xFD17 +XK_3270_Record = 0xFD18 +XK_3270_ChangeScreen = 0xFD19 +XK_3270_DeleteWord = 0xFD1A +XK_3270_ExSelect = 0xFD1B +XK_3270_CursorSelect = 0xFD1C +XK_3270_PrintScreen = 0xFD1D +XK_3270_Enter = 0xFD1E diff --git a/Xlib/keysymdef/xkb.py b/Xlib/keysymdef/xkb.py new file mode 100644 index 0000000..a6bde7d --- /dev/null +++ b/Xlib/keysymdef/xkb.py @@ -0,0 +1,100 @@ +XK_ISO_Lock = 0xFE01 +XK_ISO_Level2_Latch = 0xFE02 +XK_ISO_Level3_Shift = 0xFE03 +XK_ISO_Level3_Latch = 0xFE04 +XK_ISO_Level3_Lock = 0xFE05 +XK_ISO_Group_Shift = 0xFF7E +XK_ISO_Group_Latch = 0xFE06 +XK_ISO_Group_Lock = 0xFE07 +XK_ISO_Next_Group = 0xFE08 +XK_ISO_Next_Group_Lock = 0xFE09 +XK_ISO_Prev_Group = 0xFE0A +XK_ISO_Prev_Group_Lock = 0xFE0B +XK_ISO_First_Group = 0xFE0C +XK_ISO_First_Group_Lock = 0xFE0D +XK_ISO_Last_Group = 0xFE0E +XK_ISO_Last_Group_Lock = 0xFE0F +XK_ISO_Left_Tab = 0xFE20 +XK_ISO_Move_Line_Up = 0xFE21 +XK_ISO_Move_Line_Down = 0xFE22 +XK_ISO_Partial_Line_Up = 0xFE23 +XK_ISO_Partial_Line_Down = 0xFE24 +XK_ISO_Partial_Space_Left = 0xFE25 +XK_ISO_Partial_Space_Right = 0xFE26 +XK_ISO_Set_Margin_Left = 0xFE27 +XK_ISO_Set_Margin_Right = 0xFE28 +XK_ISO_Release_Margin_Left = 0xFE29 +XK_ISO_Release_Margin_Right = 0xFE2A +XK_ISO_Release_Both_Margins = 0xFE2B +XK_ISO_Fast_Cursor_Left = 0xFE2C +XK_ISO_Fast_Cursor_Right = 0xFE2D +XK_ISO_Fast_Cursor_Up = 0xFE2E +XK_ISO_Fast_Cursor_Down = 0xFE2F +XK_ISO_Continuous_Underline = 0xFE30 +XK_ISO_Discontinuous_Underline = 0xFE31 +XK_ISO_Emphasize = 0xFE32 +XK_ISO_Center_Object = 0xFE33 +XK_ISO_Enter = 0xFE34 +XK_dead_grave = 0xFE50 +XK_dead_acute = 0xFE51 +XK_dead_circumflex = 0xFE52 +XK_dead_tilde = 0xFE53 +XK_dead_macron = 0xFE54 +XK_dead_breve = 0xFE55 +XK_dead_abovedot = 0xFE56 +XK_dead_diaeresis = 0xFE57 +XK_dead_abovering = 0xFE58 +XK_dead_doubleacute = 0xFE59 +XK_dead_caron = 0xFE5A +XK_dead_cedilla = 0xFE5B +XK_dead_ogonek = 0xFE5C +XK_dead_iota = 0xFE5D +XK_dead_voiced_sound = 0xFE5E +XK_dead_semivoiced_sound = 0xFE5F +XK_dead_belowdot = 0xFE60 +XK_First_Virtual_Screen = 0xFED0 +XK_Prev_Virtual_Screen = 0xFED1 +XK_Next_Virtual_Screen = 0xFED2 +XK_Last_Virtual_Screen = 0xFED4 +XK_Terminate_Server = 0xFED5 +XK_AccessX_Enable = 0xFE70 +XK_AccessX_Feedback_Enable = 0xFE71 +XK_RepeatKeys_Enable = 0xFE72 +XK_SlowKeys_Enable = 0xFE73 +XK_BounceKeys_Enable = 0xFE74 +XK_StickyKeys_Enable = 0xFE75 +XK_MouseKeys_Enable = 0xFE76 +XK_MouseKeys_Accel_Enable = 0xFE77 +XK_Overlay1_Enable = 0xFE78 +XK_Overlay2_Enable = 0xFE79 +XK_AudibleBell_Enable = 0xFE7A +XK_Pointer_Left = 0xFEE0 +XK_Pointer_Right = 0xFEE1 +XK_Pointer_Up = 0xFEE2 +XK_Pointer_Down = 0xFEE3 +XK_Pointer_UpLeft = 0xFEE4 +XK_Pointer_UpRight = 0xFEE5 +XK_Pointer_DownLeft = 0xFEE6 +XK_Pointer_DownRight = 0xFEE7 +XK_Pointer_Button_Dflt = 0xFEE8 +XK_Pointer_Button1 = 0xFEE9 +XK_Pointer_Button2 = 0xFEEA +XK_Pointer_Button3 = 0xFEEB +XK_Pointer_Button4 = 0xFEEC +XK_Pointer_Button5 = 0xFEED +XK_Pointer_DblClick_Dflt = 0xFEEE +XK_Pointer_DblClick1 = 0xFEEF +XK_Pointer_DblClick2 = 0xFEF0 +XK_Pointer_DblClick3 = 0xFEF1 +XK_Pointer_DblClick4 = 0xFEF2 +XK_Pointer_DblClick5 = 0xFEF3 +XK_Pointer_Drag_Dflt = 0xFEF4 +XK_Pointer_Drag1 = 0xFEF5 +XK_Pointer_Drag2 = 0xFEF6 +XK_Pointer_Drag3 = 0xFEF7 +XK_Pointer_Drag4 = 0xFEF8 +XK_Pointer_Drag5 = 0xFEFD +XK_Pointer_EnableKeys = 0xFEF9 +XK_Pointer_Accelerate = 0xFEFA +XK_Pointer_DfltBtnNext = 0xFEFB +XK_Pointer_DfltBtnPrev = 0xFEFC diff --git a/Xlib/protocol/ChangeLog b/Xlib/protocol/ChangeLog new file mode 100644 index 0000000..0bb7dac --- /dev/null +++ b/Xlib/protocol/ChangeLog @@ -0,0 +1,124 @@ +2006-07-22 Mike Grant + * Xlib/protocol/display.py: (mggrant) Fix for 1219457 - flushing + was blocking and waiting for a read operation. Added missing + "import socket" per bug report #681511. Fix for bug:1098695 & + 1098738. The "recv" variable was being used for more than one + thing - renamed one. + + Changelog hasn't been maintained since 2002, but some of the more + significant comments from cvs logs follow: + * Xlib/protocol/request.py: (petli) Fix bugs in definition and + method of GrabButton/Pointer + +2002-02-22 Peter Liljenberg + + * event.py(CirculateNotify, CirculateRequest): These are + identical, so subclass the common Circulate. + +2002-02-13 Peter Liljenberg + + * rq.py (ValueList.parse_binary_value): Use = both for calcsize + and unpacking. Caused problems on Alpha. + +2002-02-11 Peter Liljenberg + + * request.py (GetWindowAttributes): Rename class to win_class. + (AllocColorPlanes): Fix Pad(4) to Pad(8) in reply. + + * rq.py (ReplyLength): Add a reply length field, for completeness + and easier unit test generation. + +2002-02-10 Peter Liljenberg + + * rq.py (DictWrapper.__cmp__): Let DictWrapper compare with plain + dictionaries. + (Event.__init__): Set send_event to 0 when creating new events + objects, and allow events to be compared. + + (Struct.parse_binary): Allow LengthFields to have a parse_value method. + (OddLength.parse_value): Decode field. + (String16.parse_binary_value): Handle OddLength fields. + + (TextElements8.parse_binary_value): Bugfix: return values instead + of v. + (String8.parse_binary_value): Parse String8 with no LengthOf + field. + +2002-02-09 Peter Liljenberg + + * rq.py (TextElements16): Bugfix: inherit TextElements8 instead of + TextElements16. Found while preparing unit tests, whee. + +2002-01-14 Peter Liljenberg + + * display.py (Display.parse_event_response): Fix bug reported by + Ilpo Nyyssönen, whereby ReplyRequests which generates events + (e.g. get_property with delete = 1) will get dropped when the + event is received. + +2001-12-14 Peter Liljenberg + + * display.py (Display.parse_event_response): + * rq.py (Event.__init__): Fixed bug in event type decoding: bit + 0-6 is the event type, and bit 7 is set if the event was sent by + SendEvent. + + +2001-01-16 + + * event.py: Changed some class names so that they correspond + exactly to the event type constants. + +Tue Jan 9 10:03:25 2001 Peter Liljenberg + + * display.py (Display.send_request): Fixed a call to append() with + multiple arguments, something that modern Pythons don't allow. + + +2001-01-04 + + * rq.py: The fix for 64-bit platforms didn't work, and close + scrutiny of structmodule.c shows why: it turns out that '=' + translates into '<' or '>', the one the platform would use. This + means B is one byte, H is two and L is four, and no extra + alignment, always. '@', which is the default, selects native + number of bytes, which on Alpha means that 'L' is eight bytes. + + Now the code goes to pains to ensure that '=' encoding is always + used, so _now_ it should work on all platforms. Ahem. + + +2000-12-29 + + * rq.py: Optimizations: + + replace calls to Field.get_name() with access to attribute + name. + (Struct.build_from_args): + +Fri Dec 29 17:05:02 2000 Peter Liljenberg + + * rq.py: Alpha forces us to probe how many bytes each struct code + in 'bhil' represents, instead of being able to assume that b is 1, + h is 2 and l is 4. + +2000-12-21 + + * request.py (SetClipRectangles): Fixed typo (attribute was + "rectangels"). + +2000-12-20 + + * rq.py (DictWrapper.__setitem__), + (DictWrapper.__delitem__), + (DictWrapper.__setattr__), + (DictWrapper.__delattr__): + Add a few methods to the DictWrapper, to make sure that even if + attributes are changed, all attributes can be found in the _data + mapping. + + (ValueField.__init__): + (Object.__init__): + (ValueField.pack_value): + (Set.__init__): + Added a default parameter, so that structure elements with a + default value can be omitted when calling build_from_args. diff --git a/Xlib/protocol/__init__.py b/Xlib/protocol/__init__.py new file mode 100644 index 0000000..4e2840a --- /dev/null +++ b/Xlib/protocol/__init__.py @@ -0,0 +1,28 @@ +# Xlib.protocol.__init__ -- glue for Xlib.protocol 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__ = [ + 'display', + 'event', + 'request', + 'rq', + 'structs', + ] diff --git a/Xlib/protocol/__pycache__/__init__.cpython-38.pyc b/Xlib/protocol/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..e0fbef6 Binary files /dev/null and b/Xlib/protocol/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/protocol/__pycache__/display.cpython-38.pyc b/Xlib/protocol/__pycache__/display.cpython-38.pyc new file mode 100644 index 0000000..2f39eb4 Binary files /dev/null and b/Xlib/protocol/__pycache__/display.cpython-38.pyc differ diff --git a/Xlib/protocol/__pycache__/event.cpython-38.pyc b/Xlib/protocol/__pycache__/event.cpython-38.pyc new file mode 100644 index 0000000..a815b26 Binary files /dev/null and b/Xlib/protocol/__pycache__/event.cpython-38.pyc differ diff --git a/Xlib/protocol/__pycache__/request.cpython-38.pyc b/Xlib/protocol/__pycache__/request.cpython-38.pyc new file mode 100644 index 0000000..d59fe5e Binary files /dev/null and b/Xlib/protocol/__pycache__/request.cpython-38.pyc differ diff --git a/Xlib/protocol/__pycache__/rq.cpython-38.pyc b/Xlib/protocol/__pycache__/rq.cpython-38.pyc new file mode 100644 index 0000000..4e4dcf9 Binary files /dev/null and b/Xlib/protocol/__pycache__/rq.cpython-38.pyc differ diff --git a/Xlib/protocol/__pycache__/structs.cpython-38.pyc b/Xlib/protocol/__pycache__/structs.cpython-38.pyc new file mode 100644 index 0000000..3ed7a70 Binary files /dev/null and b/Xlib/protocol/__pycache__/structs.cpython-38.pyc differ diff --git a/Xlib/protocol/display.py b/Xlib/protocol/display.py new file mode 100644 index 0000000..56623c3 --- /dev/null +++ b/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 = 1) + + # 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 = 1) + + # 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 = 1) + + 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 = None, event = None, request = None, recv = None): + """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 the 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 = 0 + while 1: + 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 0 + + + 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 1: + # 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 0 + + # 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 = 1) + r._data.update(x) + + del self.sent_requests[0] + + self.data_recv = self.data_recv[alen:] + + return 1 + + else: + # The base reply is 8 bytes long + if len(self.data_recv) < 8: + return 0 + + r._data, d = r._reply.parse_binary(self.data_recv[:8], + self, rawdict = 1) + 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, 1)) + + # 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/Xlib/protocol/event.py b/Xlib/protocol/event.py new file mode 100644 index 0000000..04743c6 --- /dev/null +++ b/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/Xlib/protocol/request.py b/Xlib/protocol/request.py new file mode 100644 index 0000000..b431e13 --- /dev/null +++ b/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/Xlib/protocol/rq.py b/Xlib/protocol/rq.py new file mode 100644 index 0000000..86cb2de --- /dev/null +++ b/Xlib/protocol/rq.py @@ -0,0 +1,1464 @@ +# 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 +import types + +# 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 = 0 + + 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 = 1 + 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 = 0): + + """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 = 0): + + """values, remdata = s.parse_binary(data, display, rawdict = 0) + + 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 = 0, *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, 1) + 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 = 1) + 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 = 1) + # 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/Xlib/protocol/structs.py b/Xlib/protocol/structs.py new file mode 100644 index 0000000..1661440 --- /dev/null +++ b/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/Xlib/rdb.py b/Xlib/rdb.py new file mode 100644 index 0000000..03b06e2 --- /dev/null +++ b/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/Xlib/support/__init__.py b/Xlib/support/__init__.py new file mode 100644 index 0000000..4c0d622 --- /dev/null +++ b/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/Xlib/support/__pycache__/__init__.cpython-38.pyc b/Xlib/support/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..7a9f26a Binary files /dev/null and b/Xlib/support/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/support/__pycache__/connect.cpython-38.pyc b/Xlib/support/__pycache__/connect.cpython-38.pyc new file mode 100644 index 0000000..8889f90 Binary files /dev/null and b/Xlib/support/__pycache__/connect.cpython-38.pyc differ diff --git a/Xlib/support/__pycache__/lock.cpython-38.pyc b/Xlib/support/__pycache__/lock.cpython-38.pyc new file mode 100644 index 0000000..319c975 Binary files /dev/null and b/Xlib/support/__pycache__/lock.cpython-38.pyc differ diff --git a/Xlib/support/__pycache__/unix_connect.cpython-38.pyc b/Xlib/support/__pycache__/unix_connect.cpython-38.pyc new file mode 100644 index 0000000..bd8366d Binary files /dev/null and b/Xlib/support/__pycache__/unix_connect.cpython-38.pyc differ diff --git a/Xlib/support/connect.py b/Xlib/support/connect.py new file mode 100644 index 0000000..4db4c2f --- /dev/null +++ b/Xlib/support/connect.py @@ -0,0 +1,102 @@ +# Xlib.support.connect -- OS-independent 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 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/Xlib/support/lock.py b/Xlib/support/lock.py new file mode 100644 index 0000000..6eee31f --- /dev/null +++ b/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/Xlib/support/unix_connect.py b/Xlib/support/unix_connect.py new file mode 100644 index 0000000..c2261da --- /dev/null +++ b/Xlib/support/unix_connect.py @@ -0,0 +1,206 @@ +# 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 + +# FCNTL is deprecated from Python 2.2, so only import it if we doesn't +# get the names we need. Furthermore, FD_CLOEXEC seems to be missing +# in Python 2.2. + +import fcntl + +if hasattr(fcntl, 'F_SETFD'): + F_SETFD = fcntl.F_SETFD + if hasattr(fcntl, 'FD_CLOEXEC'): + FD_CLOEXEC = fcntl.FD_CLOEXEC + else: + FD_CLOEXEC = 1 +else: + from FCNTL import F_SETFD, FD_CLOEXEC + + +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. + fcntl.fcntl(s.fileno(), F_SETFD, FD_CLOEXEC) + + return s + + +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/Xlib/support/vms_connect.py b/Xlib/support/vms_connect.py new file mode 100644 index 0000000..3c53695 --- /dev/null +++ b/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/Xlib/threaded.py b/Xlib/threaded.py new file mode 100644 index 0000000..44fcafe --- /dev/null +++ b/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/Xlib/xauth.py b/Xlib/xauth.py new file mode 100644 index 0000000..303bd49 --- /dev/null +++ b/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/Xlib/xobject/__init__.py b/Xlib/xobject/__init__.py new file mode 100644 index 0000000..67d3254 --- /dev/null +++ b/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/Xlib/xobject/__pycache__/__init__.cpython-38.pyc b/Xlib/xobject/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..fba46b2 Binary files /dev/null and b/Xlib/xobject/__pycache__/__init__.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/colormap.cpython-38.pyc b/Xlib/xobject/__pycache__/colormap.cpython-38.pyc new file mode 100644 index 0000000..7ffb372 Binary files /dev/null and b/Xlib/xobject/__pycache__/colormap.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/cursor.cpython-38.pyc b/Xlib/xobject/__pycache__/cursor.cpython-38.pyc new file mode 100644 index 0000000..fd607ac Binary files /dev/null and b/Xlib/xobject/__pycache__/cursor.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/drawable.cpython-38.pyc b/Xlib/xobject/__pycache__/drawable.cpython-38.pyc new file mode 100644 index 0000000..eafc1e2 Binary files /dev/null and b/Xlib/xobject/__pycache__/drawable.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/fontable.cpython-38.pyc b/Xlib/xobject/__pycache__/fontable.cpython-38.pyc new file mode 100644 index 0000000..8147841 Binary files /dev/null and b/Xlib/xobject/__pycache__/fontable.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/icccm.cpython-38.pyc b/Xlib/xobject/__pycache__/icccm.cpython-38.pyc new file mode 100644 index 0000000..5b66e60 Binary files /dev/null and b/Xlib/xobject/__pycache__/icccm.cpython-38.pyc differ diff --git a/Xlib/xobject/__pycache__/resource.cpython-38.pyc b/Xlib/xobject/__pycache__/resource.cpython-38.pyc new file mode 100644 index 0000000..90ac021 Binary files /dev/null and b/Xlib/xobject/__pycache__/resource.cpython-38.pyc differ diff --git a/Xlib/xobject/colormap.py b/Xlib/xobject/colormap.py new file mode 100644 index 0000000..033fb49 --- /dev/null +++ b/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/Xlib/xobject/cursor.py b/Xlib/xobject/cursor.py new file mode 100644 index 0000000..432e4fd --- /dev/null +++ b/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/Xlib/xobject/drawable.py b/Xlib/xobject/drawable.py new file mode 100644 index 0000000..c36a973 --- /dev/null +++ b/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, Xutil +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 = 0): + 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 = 0, 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 = 0, 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/Xlib/xobject/fontable.py b/Xlib/xobject/fontable.py new file mode 100644 index 0000000..892f266 --- /dev/null +++ b/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/Xlib/xobject/icccm.py b/Xlib/xobject/icccm.py new file mode 100644 index 0000000..d445e6d --- /dev/null +++ b/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/Xlib/xobject/resource.py b/Xlib/xobject/resource.py new file mode 100644 index 0000000..ea256ca --- /dev/null +++ b/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/charaters/__pycache__/personnage.cpython-38.pyc b/charaters/__pycache__/personnage.cpython-38.pyc new file mode 100644 index 0000000..763ded8 Binary files /dev/null and b/charaters/__pycache__/personnage.cpython-38.pyc differ diff --git a/cli/__pycache__/colors.cpython-38.pyc b/cli/__pycache__/colors.cpython-38.pyc new file mode 100644 index 0000000..4282fbd Binary files /dev/null and b/cli/__pycache__/colors.cpython-38.pyc differ diff --git a/cli/__pycache__/engine.cpython-38.pyc b/cli/__pycache__/engine.cpython-38.pyc new file mode 100644 index 0000000..8f6da44 Binary files /dev/null and b/cli/__pycache__/engine.cpython-38.pyc differ diff --git a/cli/__pycache__/writer.cpython-38.pyc b/cli/__pycache__/writer.cpython-38.pyc new file mode 100644 index 0000000..c68de7c Binary files /dev/null and b/cli/__pycache__/writer.cpython-38.pyc differ diff --git a/cli/layer/__pycache__/menu.cpython-38.pyc b/cli/layer/__pycache__/menu.cpython-38.pyc new file mode 100644 index 0000000..c788192 Binary files /dev/null and b/cli/layer/__pycache__/menu.cpython-38.pyc differ diff --git a/cli/layer/menu.py b/cli/layer/menu.py new file mode 100644 index 0000000..b9fd02d --- /dev/null +++ b/cli/layer/menu.py @@ -0,0 +1,20 @@ +from cli.colors import Colors +from cli.writer import Layer + +class Menu: + def __init__(self, cli, buttons): + self.cli = cli + #self.stats = stats + self.buttons = buttons + self.current = 0 + + def draw_layer(self): + layer = Layer(self.cli.x, self.cli.y) + x = 1 + for button in self.buttons: + color = (Colors.WHITEBG, Colors.BLACK) + if self.buttons[self.current] == button: + color = (Colors.REDBG, Colors.BLACK) + layer.put_string(button, x, self.cli.y-10, *color) + x += 11 + return layer \ No newline at end of file diff --git a/cli/cli.py b/cli/writer.py similarity index 77% rename from cli/cli.py rename to cli/writer.py index fad9763..8f81abf 100644 --- a/cli/cli.py +++ b/cli/writer.py @@ -1,12 +1,12 @@ import os -from time import sleep +#from time import sleep from typing import Dict -from colors import Colors +from cli.colors import Colors class Layer: def __init__(self, x, y): self.screen = {} - self.x = x #largeur + self.x = x #largeur self.y = y #hauteur def clear(self): @@ -54,7 +54,7 @@ class CLI: self.screen[(x, y)] = layers[layer_name].screen[(x, y)] def draw(self): - cli.combine_layers() + self.combine_layers() content = "" for y in range(self.y): #content += "\n" @@ -67,17 +67,17 @@ class CLI: print("\033[H\033[J", end="") print(content) -if __name__ == "__main__": - cli = CLI() - layer = Layer(cli.x, cli.y) - layer.put_char("t", 5, 6, Colors.BLUEBG, Colors.BLACK) - layer.put_string("""test""", 8, 9, Colors.BEIGEBG) - - cli.set_layer("test", layer) - ##cli.put_char("t", 5, 6, Colors.BLUEBG, Colors.BLACK) - #cli.put_string("tttaaaaaa ttt \n ttttttttttnnnnnn t", 8, 9, Colors.BEIGEBG) - #cli.draw() - - while True: - cli.draw() - sleep(1) \ No newline at end of file +#if __name__ == "__main__": +# cli = CLI() +# layer = Layer(cli.x, cli.y) +# layer.put_char("t", 5, 6, Colors.BLUEBG, Colors.BLACK) +# layer.put_string("""test""", 8, 9, Colors.BEIGEBG) +# +# cli.set_layer("test", layer) +# ##cli.put_char("t", 5, 6, Colors.BLUEBG, Colors.BLACK) +# #cli.put_string("tttaaaaaa ttt \n ttttttttttnnnnnn t", 8, 9, Colors.BEIGEBG) +# #cli.draw() +# +# while True: +# cli.draw() +# sleep(1) \ No newline at end of file diff --git a/listener.py b/listener.py new file mode 100644 index 0000000..3b5e880 --- /dev/null +++ b/listener.py @@ -0,0 +1,16 @@ +from pynput.keyboard import Key, Listener +import threading + +def start_listener(): + + + +def show(key): + + print('\nYou Entered {0}'.format( key)) + + if key == Key.delete: + return False + +with Listener(on_press = show) as listener: + listener.start() \ No newline at end of file diff --git a/main.py b/main.py index 4c9198a..d7a4f12 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,25 @@ -from personnage import * +from charaters.personnage import Personnage +from cli.colors import Colors +from cli.layer.menu import Menu +from cli.writer import * +from time import sleep +from pynput.keyboard import Key, Listener + +game = CLI() +menu = Menu(game, ["Inventaire", "Teset"]) + +def show(key): + if key == Key.esc: + menu.current = 1 + + +def draw(): + game.set_layer("menu", menu.draw_layer()) if __name__ == "__main__": - personnage = Personnage() \ No newline at end of file + #personnage = Personnage() + with Listener(on_press = show) as listener: + while True: + draw() + game.draw() + sleep(1) \ No newline at end of file diff --git a/pynput/__init__.py b/pynput/__init__.py new file mode 100644 index 0000000..cdc1f0e --- /dev/null +++ b/pynput/__init__.py @@ -0,0 +1,41 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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/pynput/__pycache__/__init__.cpython-38.pyc b/pynput/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..a9ff0ef Binary files /dev/null and b/pynput/__pycache__/__init__.cpython-38.pyc differ diff --git a/pynput/_info.py b/pynput/_info.py new file mode 100644 index 0000000..be34e1f --- /dev/null +++ b/pynput/_info.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# pystray +# Copyright (C) 2015-2022 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, 7, 6) diff --git a/pynput/_util/__init__.py b/pynput/_util/__init__.py new file mode 100644 index 0000000..070a935 --- /dev/null +++ b/pynput/_util/__init__.py @@ -0,0 +1,465 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 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 or (lambda *a: None))) + + @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 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/pynput/_util/__pycache__/__init__.cpython-38.pyc b/pynput/_util/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..d090251 Binary files /dev/null and b/pynput/_util/__pycache__/__init__.cpython-38.pyc differ diff --git a/pynput/_util/__pycache__/xorg.cpython-38.pyc b/pynput/_util/__pycache__/xorg.cpython-38.pyc new file mode 100644 index 0000000..d6d134b Binary files /dev/null and b/pynput/_util/__pycache__/xorg.cpython-38.pyc differ diff --git a/pynput/_util/__pycache__/xorg_keysyms.cpython-38.pyc b/pynput/_util/__pycache__/xorg_keysyms.cpython-38.pyc new file mode 100644 index 0000000..f27a0af Binary files /dev/null and b/pynput/_util/__pycache__/xorg_keysyms.cpython-38.pyc differ diff --git a/pynput/_util/darwin.py b/pynput/_util/darwin.py new file mode 100644 index 0000000..2982fb8 --- /dev/null +++ b/pynput/_util/darwin.py @@ -0,0 +1,277 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 CoreFoundation +import HIServices +import Quartz + +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: + CoreFoundation.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`. + """ + #: 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 = Quartz.CFMachPortCreateRunLoopSource( + None, tap, 0) + self._loop = Quartz.CFRunLoopGetCurrent() + + Quartz.CFRunLoopAddSource( + self._loop, loop_source, Quartz.kCFRunLoopDefaultMode) + Quartz.CGEventTapEnable(tap, True) + + self._mark_ready() + + # pylint: disable=W0702; we want to silence errors + try: + while self.running: + result = Quartz.CFRunLoopRunInMode( + Quartz.kCFRunLoopDefaultMode, 1, False) + try: + if result != Quartz.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: + Quartz.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 Quartz.CGEventTapCreate( + Quartz.kCGSessionEventTap, + Quartz.kCGHeadInsertEventTap, + Quartz.kCGEventTapOptionListenOnly if ( + True + and not self.suppress + and self._intercept is None) + else Quartz.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. + """ + self._handle(proxy, event_type, event, refcon) + if self._intercept is not None: + return self._intercept(event_type, event) + elif self.suppress: + return None + + def _handle(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/pynput/_util/darwin_vks.py b/pynput/_util/darwin_vks.py new file mode 100644 index 0000000..7eeb41b --- /dev/null +++ b/pynput/_util/darwin_vks.py @@ -0,0 +1,79 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2022 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/pynput/_util/uinput.py b/pynput/_util/uinput.py new file mode 100644 index 0000000..d73e07f --- /dev/null +++ b/pynput/_util/uinput.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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`. + """ + #: 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(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(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/pynput/_util/win32.py b/pynput/_util/win32.py new file mode 100644 index 0000000..756d876 --- /dev/null +++ b/pynput/_util/win32.py @@ -0,0 +1,598 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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`. + + 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_HANDLE` 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(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(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/pynput/_util/win32_vks.py b/pynput/_util/win32_vks.py new file mode 100644 index 0000000..9469e76 --- /dev/null +++ b/pynput/_util/win32_vks.py @@ -0,0 +1,179 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2022 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/pynput/_util/xorg.py b/pynput/_util/xorg.py new file mode 100644 index 0000000..a777a49 --- /dev/null +++ b/pynput/_util/xorg.py @@ -0,0 +1,492 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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`. + """ + #: 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) + self._handle(self._display_stop, event) + + 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(self, display, event): + """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. + """ + pass diff --git a/pynput/_util/xorg_keysyms.py b/pynput/_util/xorg_keysyms.py new file mode 100644 index 0000000..128b8c2 --- /dev/null +++ b/pynput/_util/xorg_keysyms.py @@ -0,0 +1,1715 @@ +# coding: utf-8 +# pynput +# Copyright (C) 2015-2022 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/pynput/keyboard/__init__.py b/pynput/keyboard/__init__.py new file mode 100644 index 0000000..822602e --- /dev/null +++ b/pynput/keyboard/__init__.py @@ -0,0 +1,233 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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): + #: The key. + self.key = key + + class Release(Events.Event): + """A key release event. + """ + def __init__(self, key): + #: The key. + self.key = key + + 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: + return Key[p.lower()] + 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): + """The press callback. + + This is automatically registered upon creation. + + :param key: The key provided by the base class. + """ + for hotkey in self._hotkeys: + hotkey.press(self.canonical(key)) + + def _on_release(self, key): + """The release callback. + + This is automatically registered upon creation. + + :param key: The key provided by the base class. + """ + for hotkey in self._hotkeys: + hotkey.release(self.canonical(key)) diff --git a/pynput/keyboard/__pycache__/__init__.cpython-38.pyc b/pynput/keyboard/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..5be6860 Binary files /dev/null and b/pynput/keyboard/__pycache__/__init__.cpython-38.pyc differ diff --git a/pynput/keyboard/__pycache__/_base.cpython-38.pyc b/pynput/keyboard/__pycache__/_base.cpython-38.pyc new file mode 100644 index 0000000..cc39192 Binary files /dev/null and b/pynput/keyboard/__pycache__/_base.cpython-38.pyc differ diff --git a/pynput/keyboard/__pycache__/_xorg.cpython-38.pyc b/pynput/keyboard/__pycache__/_xorg.cpython-38.pyc new file mode 100644 index 0000000..71296bb Binary files /dev/null and b/pynput/keyboard/__pycache__/_xorg.cpython-38.pyc differ diff --git a/pynput/keyboard/_base.py b/pynput/keyboard/_base.py new file mode 100644 index 0000000..151ee2e --- /dev/null +++ b/pynput/keyboard/_base.py @@ -0,0 +1,739 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 = 0 + + #: The left Alt key. This is a modifier. + alt_l = 0 + + #: The right Alt key. This is a modifier. + alt_r = 0 + + #: The AltGr key. This is a modifier. + alt_gr = 0 + + #: The Backspace key. + backspace = 0 + + #: The CapsLock key. + caps_lock = 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 = 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 = 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 = 0 + + #: A generic Ctrl key. This is a modifier. + ctrl = 0 + + #: The left Ctrl key. This is a modifier. + ctrl_l = 0 + + #: The right Ctrl key. This is a modifier. + ctrl_r = 0 + + #: The Delete key. + delete = 0 + + #: A down arrow key. + down = 0 + + #: The End key. + end = 0 + + #: The Enter or Return key. + enter = 0 + + #: The Esc key. + esc = 0 + + #: The function keys. F1 to F20 are defined. + f1 = 0 + f2 = 0 + f3 = 0 + f4 = 0 + f5 = 0 + f6 = 0 + f7 = 0 + f8 = 0 + f9 = 0 + f10 = 0 + f11 = 0 + f12 = 0 + f13 = 0 + f14 = 0 + f15 = 0 + f16 = 0 + f17 = 0 + f18 = 0 + f19 = 0 + f20 = 0 + + #: The Home key. + home = 0 + + #: A left arrow key. + left = 0 + + #: The PageDown key. + page_down = 0 + + #: The PageUp key. + page_up = 0 + + #: A right arrow key. + right = 0 + + #: A generic Shift key. This is a modifier. + shift = 0 + + #: The left Shift key. This is a modifier. + shift_l = 0 + + #: The right Shift key. This is a modifier. + shift_r = 0 + + #: The Space key. + space = 0 + + #: The Tab key. + tab = 0 + + #: An up arrow key. + up = 0 + + #: The play/pause toggle. + media_play_pause = 0 + + #: The volume mute button. + media_volume_mute = 0 + + #: The volume down button. + media_volume_down = 0 + + #: The volume up button. + media_volume_up = 0 + + #: The previous track button. + media_previous = 0 + + #: The next track button. + media_next = 0 + + #: The Insert key. This may be undefined for some platforms. + insert = 0 + + #: The Menu key. This may be undefined for some platforms. + menu = 0 + + #: The NumLock key. This may be undefined for some platforms. + num_lock = 0 + + #: The Pause/Break key. This may be undefined for some platforms. + pause = 0 + + #: The PrintScreen key. This may be undefined for some platforms. + print_screen = 0 + + #: The ScrollLock key. This may be undefined for some platforms. + scroll_lock = 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. + + :param callable on_press: The callback to call when a button is pressed. + + It will be called with the argument ``(key)``, where ``key`` is a + :class:`KeyCode`, a :class:`Key` or ``None`` if the key is unknown. + + :param callable on_release: The callback to call when a button is released. + + It will be called with the argument ``(key)``, where ``key`` is a + :class:`KeyCode`, a :class:`Key` or ``None`` if the key is unknown. + + :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.kCGEventKeyDown``, 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=on_press, on_release=on_release, 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/pynput/keyboard/_darwin.py b/pynput/keyboard/_darwin.py new file mode 100644 index 0000000..a62c6ad --- /dev/null +++ b/pynput/keyboard/_darwin.py @@ -0,0 +1,345 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 + +import Quartz + +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 + +# 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( + Quartz.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( + Quartz.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 = Quartz.CGEventCreateKeyboardEvent( + None, 0 if vk is None else vk, is_pressed) + + Quartz.CGEventSetFlags( + result, + 0 + | (Quartz.kCGEventFlagMaskAlternate + if Key.alt in modifiers else 0) + + | (Quartz.kCGEventFlagMaskCommand + if Key.cmd in modifiers else 0) + + | (Quartz.kCGEventFlagMaskControl + if Key.ctrl in modifiers else 0) + + | (Quartz.kCGEventFlagMaskShift + if Key.shift in modifiers else 0)) + + if vk is None and self.char is not None: + Quartz.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) +# 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: + Quartz.CGEventPost( + Quartz.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 = ( + Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown) | + Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp) | + Quartz.CGEventMaskBit(Quartz.kCGEventFlagsChanged) | + Quartz.CGEventMaskBit(Quartz.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: Quartz.kCGEventFlagMaskAlternate, + Key.alt_l: Quartz.kCGEventFlagMaskAlternate, + Key.alt_r: Quartz.kCGEventFlagMaskAlternate, + Key.cmd: Quartz.kCGEventFlagMaskCommand, + Key.cmd_l: Quartz.kCGEventFlagMaskCommand, + Key.cmd_r: Quartz.kCGEventFlagMaskCommand, + Key.ctrl: Quartz.kCGEventFlagMaskControl, + Key.ctrl_l: Quartz.kCGEventFlagMaskControl, + Key.ctrl_r: Quartz.kCGEventFlagMaskControl, + Key.shift: Quartz.kCGEventFlagMaskShift, + Key.shift_l: Quartz.kCGEventFlagMaskShift, + Key.shift_r: Quartz.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(self, _proxy, event_type, event, _refcon): + # 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 == Quartz.kCGEventKeyDown: + # This is a normal key press + self.on_press(key) + + elif event_type == Quartz.kCGEventKeyUp: + # This is a normal key release + self.on_release(key) + + 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) + self.on_release(key) + + elif event_type == Quartz.NSSystemDefined: + sys_event = Quartz.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 = Quartz.CGEventGetFlags(event) + is_press = flags & self._MODIFIER_FLAGS.get(key, 0) + if is_press: + self.on_press(key) + else: + self.on_release(key) + + finally: + # Store the current flag mask to be able to detect modifier state + # changes + self._flags = Quartz.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 = Quartz.CGEventGetIntegerValueField( + event, Quartz.kCGKeyboardEventKeycode) + event_type = Quartz.CGEventGetType(event) + is_media = True if event_type == Quartz.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 = Quartz.CGEventKeyboardGetUnicodeString( + event, 100, None, None) + try: + printable = chars.isprintable() + except AttributeError: + printable = chars.isalnum() + if not printable and vk in SYMBOLS \ + and Quartz.CGEventGetFlags(event) \ + & Quartz.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/pynput/keyboard/_dummy.py b/pynput/keyboard/_dummy.py new file mode 100644 index 0000000..ea70949 --- /dev/null +++ b/pynput/keyboard/_dummy.py @@ -0,0 +1,23 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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/pynput/keyboard/_uinput.py b/pynput/keyboard/_uinput.py new file mode 100644 index 0000000..e6dae4f --- /dev/null +++ b/pynput/keyboard/_uinput.py @@ -0,0 +1,445 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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(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) + + if is_press: + self.on_press(key) + else: + self.on_release(key) + + +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/pynput/keyboard/_win32.py b/pynput/keyboard/_win32.py new file mode 100644 index 0000000..5ff1d2d --- /dev/null +++ b/pynput/keyboard/_win32.py @@ -0,0 +1,347 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 + """ + if self.vk: + vk = self.vk + scan = self._scan \ + or MapVirtualKey(vk, MapVirtualKey.MAPVK_VK_TO_VSC) + flags = 0 + 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_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): + SendInput( + 1, + ctypes.byref(INPUT( + type=INPUT.KEYBOARD, + value=INPUT_union( + ki=KEYBDINPUT(**key._parameters(is_press))))), + 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 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``. + """ + _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 + + # Suppress further propagation of the event if it is filtered + if self._event_filter(msg, data) is False: + return None + elif is_packet: + return (msg | self._UTF16_FLAG, data.scanCode) + else: + return (msg, 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 + if is_utf16: + msg = msg ^ self._UTF16_FLAG + scan = vk + key = KeyCode.from_char(six.unichr(scan)) + else: + try: + key = self._event_to_key(msg, vk) + except OSError: + key = None + + if msg in self._PRESS_MESSAGES: + self.on_press(key) + + elif msg in self._RELEASE_MESSAGES: + self.on_release(key) + + # 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/pynput/keyboard/_xorg.py b/pynput/keyboard/_xorg.py new file mode 100644 index 0000000..3a5c459 --- /dev/null +++ b/pynput/keyboard/_xorg.py @@ -0,0 +1,668 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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 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 event: The *X* keyboard event. + + :param int keysym: The keysym to handle. + """ + 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 events 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(self, display, event): + # 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) + + elif event.type == Xlib.X.KeyRelease: + self.on_release(key) + + 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)) + + 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/pynput/mouse/__init__.py b/pynput/mouse/__init__.py new file mode 100644 index 0000000..e26edcd --- /dev/null +++ b/pynput/mouse/__init__.py @@ -0,0 +1,98 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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): + #: The X screen coordinate. + self.x = x + + #: The Y screen coordinate. + self.y = y + + class Click(Events.Event): + """A click event. + """ + def __init__(self, x, y, button, pressed): + #: 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 + + class Scroll(Events.Event): + """A scroll event. + """ + def __init__(self, x, y, dx, dy): + #: 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 + + def __init__(self): + super(Events, self).__init__( + on_move=self.Move, + on_click=self.Click, + on_scroll=self.Scroll) diff --git a/pynput/mouse/__pycache__/__init__.cpython-38.pyc b/pynput/mouse/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..435b9a0 Binary files /dev/null and b/pynput/mouse/__pycache__/__init__.cpython-38.pyc differ diff --git a/pynput/mouse/__pycache__/_base.cpython-38.pyc b/pynput/mouse/__pycache__/_base.cpython-38.pyc new file mode 100644 index 0000000..4f32a18 Binary files /dev/null and b/pynput/mouse/__pycache__/_base.cpython-38.pyc differ diff --git a/pynput/mouse/__pycache__/_xorg.cpython-38.pyc b/pynput/mouse/__pycache__/_xorg.cpython-38.pyc new file mode 100644 index 0000000..cca865b Binary files /dev/null and b/pynput/mouse/__pycache__/_xorg.cpython-38.pyc differ diff --git a/pynput/mouse/_base.py b/pynput/mouse/_base.py new file mode 100644 index 0000000..1087ab9 --- /dev/null +++ b/pynput/mouse/_base.py @@ -0,0 +1,263 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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. + + :param callable on_move: The callback to call when mouse move events occur. + + It will be called with the arguments ``(x, y)``, which is the new + pointer position. If this callback raises :class:`StopException` or + returns ``False``, the listener is stopped. + + :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)``, + where ``(x, y)`` is the new pointer position, ``button`` is one of the + :class:`Button` values and ``pressed`` is whether the button was + pressed. + + If this callback raises :class:`StopException` or returns ``False``, + the listener is stopped. + + :param callable on_scroll: The callback to call when mouse scroll + events occur. + + It will be called with the arguments ``(x, y, dx, dy)``, where + ``(x, y)`` is the new pointer position, and ``(dx, dy)`` is the scroll + vector. + + If this callback raises :class:`StopException` or returns ``False``, + the listener is stopped. + + :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=on_move, on_click=on_click, on_scroll=on_scroll, + suppress=suppress) +# pylint: enable=W0223 diff --git a/pynput/mouse/_darwin.py b/pynput/mouse/_darwin.py new file mode 100644 index 0000000..78d7d7a --- /dev/null +++ b/pynput/mouse/_darwin.py @@ -0,0 +1,212 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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(self, _proxy, event_type, event, _refcon): + """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) + + elif event_type == Quartz.kCGEventScrollWheel: + dx = Quartz.CGEventGetIntegerValueField( + event, + Quartz.kCGScrollWheelEventDeltaAxis2) + dy = Quartz.CGEventGetIntegerValueField( + event, + Quartz.kCGScrollWheelEventDeltaAxis1) + self.on_scroll(px, py, dx, dy) + + 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) + elif event_type == drag: + self.on_move(px, py) diff --git a/pynput/mouse/_dummy.py b/pynput/mouse/_dummy.py new file mode 100644 index 0000000..56a9332 --- /dev/null +++ b/pynput/mouse/_dummy.py @@ -0,0 +1,22 @@ +# pynput +# Copyright (C) 2015-2022 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/pynput/mouse/_win32.py b/pynput/mouse/_win32.py new file mode 100644 index 0000000..d0a37de --- /dev/null +++ b/pynput/mouse/_win32.py @@ -0,0 +1,221 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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) + + 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) + + 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``. + """ + _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(self, code, msg, lpdata): + if code != SystemHook.HC_ACTION: + return + + data = ctypes.cast(lpdata, self._LPMSLLHOOKSTRUCT).contents + + # 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) + + elif msg in self.CLICK_BUTTONS: + button, pressed = self.CLICK_BUTTONS[msg] + self.on_click(data.pt.x, data.pt.y, button, pressed) + + 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) + + 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) diff --git a/pynput/mouse/_xorg.py b/pynput/mouse/_xorg.py new file mode 100644 index 0000000..18119c0 --- /dev/null +++ b/pynput/mouse/_xorg.py @@ -0,0 +1,181 @@ +# coding=utf-8 +# pynput +# Copyright (C) 2015-2022 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(self, dummy_display, event): + 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) + else: + self.on_click(px, py, self._button(event.detail), True) + + 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) + + else: + self.on_move(px, py) + + + 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