Download Latest Version Xwintrack_1.4.0.tar.gz (39.4 kB)
Email in envelope

Get an email when there's a new version of Xwintrack

Home
Name Modified Size InfoDownloads / Week
Source files 2020-11-25
Changelog.txt 2021-01-13 13.1 kB
Readme.txt 2021-01-13 25.6 kB
Xwintrack_1.4.0.tar.gz 2021-01-13 39.4 kB
Xwintrack_1.3.0.tar.gz 2020-11-25 35.3 kB
Xwintrack_1.1.0.tar.gz 2020-11-05 20.1 kB
Xwintrack.tar.gz 2020-11-02 19.6 kB
Totals: 7 Items   153.0 kB 0
xwintrack  Footswitch X Window tracker
    Version 1.4.0

    A python 3 Xwindow tool.
    Keytracker, mousetracker, movement tracker
    Allows tracking of keys, mouse buttons and mouse position in a selected
    X window or globally.

    Performs many of xdotool's functions
    Other than Xlib requires: xkbcomp to build keyboard dictionaries
    
    It performs no logging of its own, it tracks and reports what is occurring,
    allowing the programmer to do want they will with the information.

    Originally for use with the transcription tool footswitch2,
    to track transcription entry in LibreOffice, to maintain a
    timestamped copy of the text.
    This enables the transcriber to search for when a phrase was uttered
    within the audio and jump to that position.

    Mouse and movement tracking retained  and enhanced, solely because it may be
    useful to others.
         
    Inspiration from:

       pyxhook Copyright (C) 2008 Tim Alexander <dragonfyre13@gmail.com>

       pyxhook extensively modified by Daniel Folkinshteyn <nanotube@users.sf.net>

       A hat tip to python-xlib/examples/record_demo.py Copyright (C) 2000-2002  Peter Liljenberg

       Functionality of xdotool Copyright (c) 2007, 2008, 2009: Jordan Sissel.

    #
    xwintrack Copyright (C) 2020 James Healey <rolfofsaxony@gmx.com>
    #
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.
    #
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    xwintrack developed and Tested with python-xlib version 0.20-3
    Tested solely on Linux (Mint/Ubuntu and Manjaro) python 3.6.9

    Enhancements:
    Most code re-written, leaving core pieces from the Xlib examples in place
    and following the structure of pyxhook
    
    Use event state bitwise tests to determine keyboard and mouse modifiers.
    Cope with Num_Lock accommodating numeric pad keys.
    Cope with Caps_Lock.
    Allow for Alt Gr options and other modifiers and combinations
    Key Action Down, Held, Up
    Mouse Action Down, Up, Scroll
    Mouse co-ordinates retrieved from the mouse button event 
    Mouse event reports if a modifier key was active 
    Mouse event reports if another mouse button was active 
    Mouse event reports combination of mouse button and Key modifiers
     providing a powerful tool for user written Mouse based HotKey functions 
    Ability to track events for a single window, rather than all windows
    Limit reporting to Currently open Windows or allow All
    Limit overheads by allowing selection of event types:
     keys only, mouse actions, keys and mouse buttons, movement only, all events 
    Ability to specify/limit key characters reported on
    350 x speed up of key symbol look-up
    Named threads
    Call event function with lambdas for *args or **kwargs
    Numerous example programs
        
     NB: If logging key characters into a file or database, ensure that
         you test for returned 'Null' characters, which can cause problems.
         Test for the event.Char variable  equal to '\x00' and discard it
         (One entire day wasted discovering why an sqlite3 Db record
          was stored as a Blob instead of Text - Null characters!)

Stand-alone Functions:
    General Window Queries/Actions
    Find a window, based on its title
    Find a window, based on its class/program
    Find a window, based on text anywhere in Title/class or Id
    Find or Wait for a window to open if not currently available
    Get a list of current windows
    Get details of a specific window by specified Id
    Select a window from the desktop
    Change the cursor to a green dotbox to signify something (like Select Window)
    Change the cursor back to a normal pointer
    Raise a specific window 
    Test if a window is still open 
    Get pointer position
    Get screen geometry
    Get active modifiers
    Move pointer
    Drag pointer
    Relative pointer move
    Press mouse button
    Release mouse button
    Mouse button press & release
    Double Click mouse button
    Mouse button drag
    Key entry with/without modifiers
    Text entry
    Text entry from file
    Run a program 
    
TrackManager Usage:
    There are only 3 classes,
        TrackManager, the main class to instantiate
        trackkeyevent, which returns details of a key event
        trackmouseevent, which returns details of a mouse event.
        
    Create one or more Trackmanager's and then declare the event/s callback function/s
    you are interested in.
    
    There are 5 functions that can be declared.
        KeyDown : The function to execute when a key is pressed.
                  Returns the trackkeyevent class.
        KeyUp   : The function to execute when a key is released.
                  Returns the trackkeyevent class.
        MouseButtonDown :
                  The function to execute when a mouse button is pressed.
                  Returns the trackmouseevent class.
        MouseButtonUp :
                  The function to execute when a mouse button is released.
                  Returns the trackmouseevent class.
        MouseMovement :
                  The function to execute when a mouse moves.
                  Returns the trackmouseevent class.
    
    The callback is your function to interpret the event and perform whatever is necessary.
    The callback can be a lambda function, if you need to pass other variables.
    You can define the lambda function to use *args (see example XwinExAdv.py) or **kwargs 
    (see example XwinExAdv2.py)
    
    tm = xwintrack.TrackManager(winid=0,restricted_to_characters=[],action_required="all",tm_name="")
    tm.KeyDown = kbevent
    
    Start tracking
    tm.start()
    
    Cancel tracking
    if tm.is_alive():
        tm.cancel()
        
    The TrackManager has a variable IsRunning and a function is_running()
    This can be tested periodically to test if the watched window is still open
    and the trackmanager still active.
    If you are not incorporating this code into a Gui, you will need to establish some
    form of loop, to keep this all running. Again see examples.
    If you are running Gui, test the is_running() function periodically,
    in case you need to run the cancel() function and perform a join() operation
    for example:
 
        if self.monitor_listener:
            if not self.monitor_listener.is_running():
                self.monitor_listener.cancel()
                self.monitor_listener.join(0.1)        
                self.monitor_listener = False

    The underlying Xlib thread has the usual "is_alive" function. 
    
    class TrackManager(threading.Thread):
    """ Instantiate the class and hand it a function
        An event is returned when it occurs
        The track*event class that is returned, where * is key, or mouse, is as follows:
        
        key event   : Window, WindowName, ProcName, Key, Ascii, Char, ScanCode, TextMessage 
            Window Handle:  Window id number
            Window Name:    Window Text Name
            Proc Name:      Name of process using window
            Key Pressed:    Key
            Ascii Value:    Ascii Value
            Char:           Character if applicable
            ScanCode:       ScanCode of key (just in case)
            Modifier:       Numeric value indicating Active modifiers
            Action:         Numeric value indicating Down (0), Held (1), Up (2)
            TextMessage:    Description of event

        mouse event : Window, WindowName, ProcName, Position, Button, Modifier, TextMessage 
            Window Handle:  Window id number
            Window Name:    Window Text Name
            Proc Name:      Name of process using window
            Position:       X, Y Position of mouse pointer
            Button:         Button number
            Modifier:       Numeric value indicating Active modifiers
            Action:         Numeric value indicating Down (0), Up (2)
            TextMessage:    Description of event

    Functions: note Down and Up are used to avoid confusion with internal X Press and X Release
        KeyDown : The function to execute when a key is pressed.
                  Returns the trackkeyevent class.
        KeyUp   : The function to execute when a key is released.
                  Returns the trackkeyevent class.
        MouseButtonDown :
                  The function to execute when a mouse button is pressed.
                  Returns the trackmouseevent class.
        MouseButtonUp :
                  The function to execute when a mouse button is released.
                  Returns the trackmouseevent class.
        MouseMovement :
                  The function to execute when a mouse moves.
                  Returns the trackmouseevent class.

    Optional parameters:
        winid   : The Xwindow id that you wish to track, ignoring all input
                  from others.
                  The default is 0, which listens to All device input
                  The source is identifiable via event Window, WindowName, or ProcName

        restricted_to_characters :
                  A list [] of keyboard characters that you wish reported, ignoring
                  characters not in the list
                  A full set would be:
                  [' ', '!', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '¡', '¢', '£', '¤', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '®', '¯', '°', '±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿', 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '×', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'Þ', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', 'ÿ', '€']
                  A more specialised value might be ['.','?','!'] i.e. punctuation
                  which marks the end of a sentence.
                  
                  An empty list is the default, which sends back everything.

        action_required : Default "keys"
                  If you only require limited event types, receiving notifications for
                  events you don't want is a waste of resources.
                  Use this parameter to define the events reported.
                   
                  "keys"    - keys only
                  "mouse"   - mouse buttons only
                  "km"      - keys and mouse buttons only
                  "move"    - mouse pointer only
                  "all"     - all device events, keys, mouse buttons and pointer movement
                  "select"  - mouse button press only.
                  If tracking a single window, Mouse motion is reported anywhere on the display
                  when the "watched" window has Focus
                  Mouse motion reports not only the mouse position but also which, if any,
                  mouse buttons are held down, allowing for Drag options to be calculated.
                  The "select" option is used internally, it populates 2 variables within TrackManager:
                   select_button and select_win, they denote the mouse button pressed and standard
                   dictionary of the window attributes that the Click happened on.
                  If you choose to use "select" directly rather than the xwindowselect() function,
                   you decide which Button press means what.

        sub_windows : Default False
                  Set to True, Sub Windows opened within a "watched" window (see winid), will also
                  send Key and Mouse events.
 
        tm_name     : An identifying name for this occurrence of TrackManager,
                    : in case you are running more than one.
                    : Otherwise the thread is identified by its number e.g. Thread-2 

    Modifiers: 
        Modifiers are accumlative, so if shift and ctrl are depressed when another key
        is pressed, the modifier value will be the sum of two values.
        i.e.
            # 0     - standard    # no Modifier
            # 1     - Shift
            # 4     - Ctrl
            # 5     - Ctrl + Shift
            # 8     - Alt_Left
            # 64    - Super_L and Super_R (Win/Menu keys)
            # 128   - Alt_Right
            # 129   - Alt_R + Shift
            # ...
        Note: While caps_lock and num_lock are available and xwintrack uses them
              internally, it does not specifically report them.
              It gives more modifiers to check for little benefit. 
        With key release (Up) X reports a modifier key as its own modifier.
        xwintrack deducts it in an attempt at sanity.
            
       Modifiers for mouse buttons:
            # 0     - standard    # no Modifier
            # 1     - Shift
            # 4     - Ctrl
            # 5     - Ctrl + Shift
            # 8     - Alt_Left
            # 9     - Alt_Left + Shift
            # 12    - Alt_Left + Ctrl
            # 13    - Alt_Left + Shift + Ctrl
            # 64    - Super (L & R)
            # 128   - Alt-R
            # 256   - Button 1
            # 257   - Button 1 + Shift  
            # ...
            # 512   - Button 2
            # 1024  - Button 3
            # ...

        With button release (Up) X reports the button as its own modifier.
        xwintrack deducts it in an attempt at sanity.
        
    Button numbers:
        1 - Left
        2 - Middle
        3 - Right
        4 - Wheel Up (forward)
        5 - Wheel Down (backward)
        check the wheel action for pressed or released
            0 - pressed
            2 - released   
    Key Actions:
            0 - pressed
            1 - held
            2 - released       

    See the file Key_names.txt for all available names of keys.

    Identifying a Window to watch:
    
    xwintrack
        can be used to identify the window you want to watch by setting it up as a one off
        to receive a mouse click (function "xwindowselect")
        or any of the "find" functions.
        (See example programs)
    xdotool
        can also be used, either requesting a mouse click
        (xdotool selectwindow)
        or by searching for a named open window
        (xdotool search --name "LibreOffice Writer") for example.
    Again, see examples.
    
    Check the example programs for usage.
 
 Stand-alone Functions:
  Designed to replicate key xdotool functions
  
   * Findclass(window=None, search="", found = []):
    ''' Find windows matching a class name / program
        The window and found variables are populated automatically and should not be set.
        Call with search="class I want"
        Input   :   class name
        Returns : a list of dictionaries
                "handle":   Window Id
                "class":    Program name (class),
                "name":     window title,
                "state":    window state, 1 - Visible, 3 - Minimised
    '''
    *
    * Findname(window=None, search="", found = []):
    ''' Find windows matching a Window name - the search variable
        The window and found variables are populated automatically and should not be set.
        Call with search="name I want"
        Input   :   window name
        Returns :   a list of dictionaries
                "handle":   Window Id
                "class":    Program name (class),
                "name":     window title,
                "state":    window state, 1 - Visible, 3 - Minimised
    '''
    *
    * Find(window=None, search="", found = []):
    ''' Generic Find windows matching the search variable to something in name, class or id
        The window and found variables are populated automatically and should not be set.
        Call with search="name I want"
        Input   :   window name
        Returns :   a list of dictionaries
                "handle":   Window Id
                "class":    Program name (class),
                "name":     window title,
                "state":    window state, 1 - Visible, 3 - Minimised
    '''
    *
    * SyncFind(search="", wait=120, progress=True, x=0, y=0):
    ''' A generic Find windows matching the search variable somewhere, that waits for a valid window
        Call with search="thing I want" and a maximum time to wait in seconds
        Fails with empty list if nothing found with time period
        Input   :   search text
                :   wait     - wait limit in seconds - default 120
                :   progress - True or False
                             : True opens a progress window
                :   x        - horizontal position of the progress window
                :   y        - vertical position of the progress window
        Returns :   a list of dictionaries
                "handle":   Window Id
                "class":    Program name (class),
                "name":     window title,
                "state":    window state, 1 - Visible, 3 - Minimised
    '''     
    *
    xwindowexist(id):
    ''' Test window exists
        When a program like libreoffice has multiple windows open
        If the window you are monitoring closes, it isn't reported as dying.
        This test allows you to test from your program via a timer, if the
        specific window you're working with is still available
        Input   :   Id
        Returns :   True / False
    '''
    *
    xwindowget(id):
    ''' return the window
        Input   :   Id
        Returns :   window or None
    '''
    *
    xwindowquery(id):
    ''' Get details of a window given its Id number
        Input   :   Id
        Returns : a dictionary
                "name":     window title,
                "class":    Program name (class),
                "handle":   window Id,
                "state":    window state, 1 - Visible, 3 - Minimised
                "pid":      Process Id
    '''
    *
    xwindowraise(id):
    ''' Raise given window to focus
        Input   : Id
        Returns : True or False
    '''
    *
    xwindowlist():
    ''' Get list of windows
        Returns : generator of dictionaries
                "name":     window title,
                "class":    Program name (class),
                "handle":   window Id,
                "state":    window state, 1 - Visible, 3 - Minimised
                "pid":      Process Id
    '''
    *
    xcursorselect():
    ''' Change the cursor to a green dotbox to indicate a selection is required
        Beware - there is no way back to the original themed cursor - see xcursornormal()
    '''
    *
    xcursornormal():
    ''' Change the cursor back to White left_ptr to indicate selection finished
        Sadly under python there appears to be no way to identify the existing
        cursor image, so we're left with returning to a standard X cursor, rather
        than the Themed one
    '''
    *
    xwindowselect(wait=120):
    ''' Allows you to select a visible window with a Left Click
        A right or Middle Click cancels the function
        Input   : wait= n (optional) seconds to wait for a click or timeout (Default 120)
        Returns : a single dictionary of the selected window or None
                "handle":   Window Id
                "class":    Program name (class),
                "name":     window title,
                "state":    window state, 1 - Visible, 3 - Minimised
    '''
    *
    # Window input functions i.e. xwintrack.function()
    *
    pointerpos():
    ''' Returns current pointer position - X, Y , Width of Screen, Height of Screen
    '''
    *
    getgeometry():
    ''' Returns Width, Height of Screen
    '''
    *
    getmodifiers():
    ''' Returns a single value which represents any and all
        current active modifiers
    '''
    *
    pointermove(x, y):
    ''' Moves the mouse pointer to X, Y
    '''
    *
    pointerdrag(x, y):
    ''' Move mouse pointer to position x, y, in increments
    '''
    *
    pointerrelmove(x, y):
    ''' Mouse pointer move position relative to current position
        x = +/- from current x
        y = +/- from current y
    '''
    *    
    typetext(win=None, text="", delay=0.01, raise_window=False, clearmods=False, file=False):
    ''' Enters the text string into the given window
        Input:
        win:    Window target for text
        text:   The text to enter
        delay:  delay in seconds, int or float
        raise_window:   True or False, put the window on top
        clearmods:      True/False, Clear any current modifiers and then re-instate them
                        Shift|Caps_Lock|Control|Alt|Num_Lock
        file:           True/False - If True the "text" variable is a file name
                                     input will be read from the file.
        Note: if you need inverted commas or quotes in the text wrap it in triple quotes
        use e.g.text='''your "text" here''' 
    '''
    *
    keypress(win=None, key="", delay=0, raise_window=False, mods=[]):
    ''' Enters key into the given window
        Input:
        win:    Window target for text
        key:    The key to enter - a character or its name
                e.g. a,A,~,space,comma,(, parenleft, F8, etc  
        delay:  delay in seconds, int or float
        raise_window:   True or False, put the window on top
        mods:   Modifiers to be applied to the key
                [Shift,Control,Alt,AltGr]
                A value of 0 - no modifier
                A value of 1 - apply modifier
        Beware of using modifiers when the character is constructed with modifiers
    '''
    *
    buttonpress(button):
    ''' Press mouse button
    '''
    *
    buttonrelease(button):
    ''' Release mouse button
    '''
    *
    buttonclick(button):
    ''' Press mouse button, then Release button
    '''
    *
    buttondclick(button):
    ''' Double Click mouse button
    '''
    *
    buttondrag(button,x,y):
    ''' Press mouse button
        Drag to position x,y
        Release mouse button
    '''
    *
    exec(command):
    ''' Execute a command (Linux)
        expects a [list] e.g. ['firefox -search "charles V"']
        returns the process number of the new process
        Restricted to commands that don't require communication.
        i.e. Don't expect a list of files from ['ls']
    '''
    *
    *
    xwin_keymap.py
    This code is run as needed i.e. if the file $HOME/.config/Xwintrack/xwintrack_keys.py'
    is missing    
    *
    buildkeys():
    ''' Builds the $HOME/.config/Xwintrack/xwintrack_keys.py dictionaries
 
        These dictionaries are used to ascertain the keycodes and symbols used with
        the active keyboard.
        Specifically for the typetext and keypress functions
        
        The code_to_key dict links the X key mnemonic with the key code.
        e.g. '9': '<ESC>', '10': '<AE01>', '11': '<AE02>'

        The key_mods dict links the mnemonic with the character in each modifier state
             mnemonic  [Normal, Shift,    Alt_R,    Shift+Alt_R]        
        e.g. '<AE05>': ['5', 'percent', 'onehalf', 'threeeighths']
        
        The char_to_key dict links the character name with the mnemonic
        e.g. '1': '<AE01>', 'exclam': '<AE01>', 'bar': '<LSGT>'
        
        The char_to_symbolname dict links the printed character to the character name
        i.e. ',': 'comma', '©': 'copyright', '¤': 'currency', 'd': 'd'
        
        The char_to_symbolname is derived from latin1 if you wish to use another set
        change the import statement or add another.        
        
        when using the 'typetext' function:
        char -> char_to_symbolname
        symbolname -> to char_to_key picks up the mnemonic
        mnemonic -> to key_mods picks up the modifiers
        
        Usage is, get the keycode from X, or the character to emulate, lookup the mnemonic,
        get the key_mods to work out which modifiers are required to replicate the given
        key as a KeyPress.
        How I wish, I never started down this track of replicating some of the
        xdotool functionality?
        The idea is that it will build dictionaries relevant to the current keyboard.
        If that changes, delete the existing $HOME/.config/Xwintrack/xwintrack_keys.py file and
        a new one will be built.
        The location for the file $HOME/.config/Xwintrack/xwintrack_keys.py is to ensure it is user
        specific and because, as it is built as needed, it must reside somewhere that can
        be written to.
    '''
Source: Readme.txt, updated 2021-01-13