Source code for vimtk.xctrl

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
"""
Notes:
    # https://stackoverflow.com/questions/51070465/is-it-possible-to-get-the-directory-of-a-specific-nautilus-window-in-a-script?noredirect=1#comment95427874_51070465
    sudo apt install python-nautilus
    mkdir -p ~/.local/share/nautilus-python/extensions

TODO:
    need to handle wayland.

    To replace xdootool, look at
    wtype,
    river,
    xmonad,
    xmobar
    dmenu,
    xlock

"""
import time
import re
import logging
from vimtk import cplat
from shlex import quote as cmd_quote

logger = logging.getLogger(__name__)


[docs] def is_directory_open(dpath): # FIXME import ubelt as ub # pip install me! https://github.com/Erotemic/ubelt import platform from os.path import basename import re computer_name = platform.node() dname = basename(dpath) if not ub.find_exe('wmctrl'): raise Exception('wmctrl must be installed') for line in ub.cmd('wmctrl -lxp')['out'].splitlines(): parts = re.split(' +', line) if len(parts) > 3 and parts[3] == 'nautilus.Nautilus': if parts[4] == computer_name: # FIXME: Might be a False positive! line_dname = ' '.join(parts[5:]) if line_dname == dname: return True # Always correctly returns False return False
[docs] def wmctrl_list(): import ubelt as ub lines = ub.cmd('wmctrl -lxp')['out'] windows = {} for line in lines.split('\n'): if line: parts = re.split(' +', line) hexid, deskid, pid, wm_class, client = parts[0:5] title = ' '.join(parts[5:]) wm_id = int(hexid, 16) windows[wm_id] = { 'hexid': hexid, 'wm_id': wm_id, 'deskid': deskid, 'pid': int(pid), 'wm_class': wm_class, 'client': client, 'title': title, } return windows
[docs] def windows_in_order(): """ CommandLine: python -m vimtk.xctrl windows_in_order References: https://stackoverflow.com/questions/15638885/linux-how-to-get-a-list-of-all-visible-windows Example: >>> # xdoctest: +REQUIRES(env:DISPLAY) >>> from vimtk.xctrl import * >>> result = list(windows_in_order()) >>> for win in result: ... if win.visible(): ... print(win) Ignore: # Why is this slow somtimes? import subprocess subprocess.call(['xprop', '-root']) proc = subprocess.Popen(['xprop', '-root'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1, text=True) out, err = proc.communicate() proc = subprocess.Popen('xprop -root', shell=True, stdout=subprocess.PIPE, bufsize=1) info = ub.cmd('xprop -root | grep "^_NET_CLIENT_LIST_STACKING"', shell=True) info = ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING', shell=True) info = ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING') # I don't understand why this can be fast sometimes and slow others import subprocess import timerit import itertools as it import ubelt as ub options = { 'bufsize': [-1, 0], 'shell': [True, False], 'stdout': [subprocess.PIPE, None], 'stderr': [subprocess.PIPE, None], 'stdin': [subprocess.PIPE, None], 'universal_newlines': [True, False], # 'cwd': [None, '.'] # 'env': [None, {}] } ti = timerit.Timerit(3, bestof=1, verbose=3) for vals in it.product(*options.values()): opt = ub.dzip(options.keys(), vals) command = ['xprop', '-root', '_NET_CLIENT_LIST_STACKING'] name = ub.urepr(opt, explicit=True, nobr=1, nl=0, itemsep='') if opt['shell']: command = ' '.join(command) for timer in ti.reset(name): with timer: proc = subprocess.Popen(command, **opt) out, err = proc.communicate() assert proc.returncode == 0 # print(out) for timer in ti.reset('ubelt'): with timer: print(ub.cmd('xprop -root _NET_CLIENT_LIST_STACKING')['out']) print(ub.urepr(ub.sorted_vals(ti.measures['mean']), nl=1, precision=6)) proc = subprocess.Popen('xprop -root', shell=True, stdout=subprocess.PIPE, bufsize=0) out, err = proc.communicate() info = ub.cmd('xprop -root', verbose=3, shell=True) ub.cmd('wmctrl -lxp')['out'] os.system('wmctrl -lxp') """ # info = XCtrl.cmd('xprop -root') info = XCtrl.cmd('xprop -root _NET_CLIENT_LIST_STACKING') lines = [line for line in info['out'].split('\n') if line.startswith('_NET_CLIENT_LIST_STACKING')] assert len(lines) == 1, str(lines) winid_order_str = lines[0] winid_order = winid_order_str.split('#')[1].strip().split(', ')[::-1] winid_order = [int(h, 16) for h in winid_order] windows = wmctrl_list() for wm_id in winid_order: info = windows[wm_id] yield XWindow(wm_id, info)
[docs] def find_windows(proc=None, title=None, visible=True): """ CommandLine: python -m vimtk.xctrl find_windows Example: >>> # xdoctest: +REQUIRES(env:DISPLAY) >>> from vimtk.xctrl import * # NOQA >>> for win in find_windows('gvim'): >>> print(ub.urepr(win.info())) >>> for win in find_windows('terminator'): >>> print(ub.urepr(win.info())) """ import re for win in windows_in_order(): flag = True if proc: try: proc_name = win.process_name() flag &= bool(re.match(proc, proc_name)) except Exception: flag = False if title: try: win_title = win.title() flag &= bool(re.match(title, win_title)) except Exception: flag = False if visible: try: flag &= win.visible() except Exception: flag = False if flag: yield win
[docs] class XWindow(object): """ TODO: make API consistent with the win32 version """ def __init__(self, wm_id, info=None, sleeptime=0.01): self.wm_id = wm_id self.cache = info self.sleeptime = 0.01
[docs] @classmethod def find(XWindow, pattern, method='mru'): wm_id = XCtrl.find_window_id(pattern, method=method) self = XWindow(wm_id) return self
[docs] @classmethod def findall(XWindow, pattern): wm_ids = XCtrl.findall_window_ids(pattern) result = [XWindow(wm_id) for wm_id in wm_ids] return result
[docs] @classmethod def current(XWindow): r""" CommandLine: VIMTK_TEST=1 xdoctest -m vimtk.xctrl XWindow.current Example: >>> # xdoctest: +REQUIRES(env:VIMTK_TEST) >>> from vimtk.xctrl import * # NOQA >>> import ubelt as ub >>> self = XWindow.current() >>> print('self: XWindow = {}'.format(ub.urepr(self, nl=1))) >>> print('info = ' + ub.urepr(self.wininfo())) """ import ubelt as ub wm_id = int(ub.cmd('xdotool getwindowfocus')['out'].strip()) win = XWindow(wm_id) return win
[docs] def _wmquery(self, key): if self.cache: return self.cache[key] windows = wmctrl_list() info = windows[self.wm_id] self.cache = info return info['title']
@property def hexid(self): return hex(self.wm_id)
[docs] def title(self): self._wmquery('title')
[docs] def visible(self): """ Basically true for wmctrl (afaik) """ return True
def __nice__(self): try: fname = self.process_name() except Exception: fname = '<error: unable to get process name>' return str(self.wm_id) + ' ' + fname + ' ' + repr(self.title())
[docs] def wm_class(self): return self._wmquery('wm_class')
[docs] def process(self): import psutil pid = self._wmquery('pid') proc = psutil.Process(pid) return proc
[docs] def size(self): # Get the current size info = self.wininfo() w, h = int(info['Width']), int(info['Height']) dsize = (w, h) return dsize
[docs] def resize(self, width, height): """ CommandLine: VIMTK_TEST=1 xdoctest -m vimtk.xctrl XWindow.resize Example: >>> # xdoctest: +REQUIRES(env:VIMTK_TEST) >>> from vimtk.xctrl import * # NOQA >>> self = XWindow.current() >>> w, h = self.size() >>> self.resize(w + 10, h + 10) """ import ubelt as ub command = f'xdotool windowsize {self.wm_id} {width} {height}' ub.cmd(command, verbose=3)
[docs] def wininfo(self): """ """ import ubelt as ub cmdinfo = ub.cmd('xwininfo -id {}'.format(self.wm_id)) if cmdinfo['ret'] != 0: print('info = {}'.format(ub.urepr(cmdinfo, nl=1))) raise Exception(cmdinfo['ret']) out = cmdinfo['out'] info = {} curr_key = None val_accum = [] # Parse key/val lines def accept(info, curr_key, val_accum): if curr_key is not None: info[curr_key] = (' '.join(val_accum)).strip() val_accum.clear() for line in out.split('\n'): if ':' in line: accept(info, curr_key, val_accum) key, val = line.split(':', 1) val_accum.append(val) curr_key = key.strip() else: val_accum.append(line) accept(info, curr_key, val_accum) return info
[docs] def process_name(self): proc = self.process() return proc.name()
[docs] def focus(self, sleeptime=None): import ubelt as ub ub.cmd('wmctrl -ia {}'.format(self.hexid)) time.sleep(sleeptime if sleeptime is not None else self.sleeptime)
[docs] def info(self): info = self.cache.copy() # type: ignore info['proc_name'] = self.process_name() return info
[docs] def move(self, bbox): """ CommandLine: # List windows wmctrl -l # List desktops wmctrl -d # Window info xwininfo -id 60817412 python -m vimtk.xctrl XWindow.move joncrall 0+1920,680,400,600,400 python -m vimtk.xctrl XWindow.move joncrall [0,0,1000,1000] python -m vimtk.xctrl XWindow.move GVIM special2 python -m vimtk.xctrl XWindow.move joncrall special2 python -m vimtk.xctrl XWindow.move x-terminal-emulator.X-terminal-emulator [0,0,1000,1000] CommandLine: python -m vimtk.xctrl XWindow.move CommandLine: python -m vimtk.xctrl XCtrl.move_window Example: >>> # xdoctest: +SKIP >>> XCtrl.move_window('joncrall', '[0,0,1000,1000]') Ignore: # >>> orig_window = [] # >>> X = xctrl.XCtrl win_key = 'x-terminal-emulator.X-terminal-emulator' win_id = X.findall_window_ids(key)[0] python -m xctrl XCtrl.findall_window_ids gvim """ monitor_infos = { i + 1: cplat.get_resolution_info(i) for i in range(2) } # TODO: cut out borders # TODO: fix screeninfo monitor offsets # TODO: dynamic num screens def rel_to_abs_bbox(m, x, y, w, h): """ monitor_num, relative x, y, w, h """ minfo = monitor_infos[m] # print('minfo(%d) = %s' % (m, ub.urepr(minfo),)) mx, my = minfo['off_x'], minfo['off_y'] mw, mh = minfo['pixels_w'], minfo['pixels_h'] # Transform to the absolution position abs_x = (x * mw) + mx abs_y = (y * mh) + my abs_w = (w * mw) abs_h = (h * mh) abs_bbox = [abs_x, abs_y, abs_w, abs_h] abs_bbox = ','.join(map(str, map(int, abs_bbox))) return abs_bbox if self.title().startswith('joncrall') and bbox == 'special2': # Specify the relative position abs_bbox = rel_to_abs_bbox(m=2, x=0.0, y=0.7, w=1.0, h=0.3) elif self.title().startswith('GVIM') and bbox == 'special2': # Specify the relative position abs_bbox = rel_to_abs_bbox(m=2, x=0.0, y=0.0, w=1.0, h=0.7) else: abs_bbox = ','.join(map(str, eval(bbox))) print('MOVING: win_key = %r' % (self.title(),)) print('TO: abs_bbox = %r' % (abs_bbox,)) # abs_bbox.replace('[', '').replace(']', '') # get = lambda cmd: XCtrl.cmd(' '.join(["/bin/bash", "-c", cmd]))['out'] # NOQA win_id = XCtrl.find_window_id(self.title(), error='raise') print('MOVING: win_id = %r' % (win_id,)) fmtdict = locals() cmd_list = [ ("wmctrl -ir {win_id} -b remove,maximized_horz".format(**fmtdict)), ("wmctrl -ir {win_id} -b remove,maximized_vert".format(**fmtdict)), ("wmctrl -ir {win_id} -e 0,{abs_bbox}".format(**fmtdict)), ] print('\n'.join(cmd_list)) for cmd in cmd_list: XCtrl.cmd(cmd)
[docs] def _wmctrl_terminal_patterns(): """ wmctrl patterns associated with common terminals """ terminal_pattern = r'|'.join([ 'terminal', re.escape('terminator.Terminator'), # gtk3 terminator re.escape('x-terminal-emulator.X-terminal-emulator'), # gtk2 terminator # other common terminal applications 'tilix', 'konsole', 'rxvt', 'terminology', 'xterm', 'tilda', 'Yakuake', 'kitty.kitty', ]) return terminal_pattern
[docs] class XCtrl(object): r""" xdotool key ctrl+shift+i References: http://superuser.com/questions/382616/detecting-currently-active-window http://askubuntu.com/questions/455762/xbindkeys-wont-work-properly Ignore: xdotool keyup --window 0 7 type --clearmodifiers ---window 0 '%paste' # List current windows: wmctrl -l # Get current window xdotool getwindowfocus getwindowname #==== # Get last opened window #==== win_title=x-terminal-emulator.X-terminal-emulator key_ = 'x-terminal-emulator.X-terminal-emulator' # Get all windows in current workspace workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1` win_list=`wmctrl -lx | grep $win_title | grep " $workspace_number " | awk '{print $1}'` # Get stacking order of windows in current workspace win_order=$(xprop -root|grep "^_NET_CLIENT_LIST_STACKING" | tr "," " ") echo $win_order CommandLine: python -m vimtk.xctrl XCtrl:0 Example: >>> # xdoctest: +SKIP >>> # Script >>> orig_window = [] >>> copy_text_to_clipboard(lorium_ipsum()) >>> doscript = [ >>> ('focus', 'x-terminal-emulator.X-terminal-emulator'), >>> ('type', '%paste'), >>> ('key', 'KP_Enter'), >>> # ('focus', 'GVIM') >>> ] >>> XCtrl.do(*doscript, sleeptime=.01) Ignore: >>> # xdoctest: +SKIP >>> copy_text_to_clipboard(text) >>> if '\n' in text or len(text) > 20: >>> text = '\'%paste\'' >>> else: >>> text = cmd_quote(text.lstrip(' ')) >>> ('focus', 'GVIM'), >>> # >>> doscript = [ >>> ('focus', 'x-terminal-emulator.X-terminal-emulator'), >>> ('type', text), >>> ('key', 'KP_Enter'), >>> ] >>> XCtrl.do(*doscript, sleeptime=.01) """ # @staticmethod # def send_raw_key_input(keys): # print('send key input: %r' % (keys,)) # args = ['xdotool', 'type', keys] # XCtrl.cmd(*args, quiet=True, silence=True)
[docs] @classmethod def cmd(XCtrl, command): import ubelt as ub logging.debug('[cmd] {}'.format(command)) info = ub.cmd(command) if info['ret'] != 0: logging.warning('Something went wrong {}'.format(ub.urepr(info))) # type: ignore return info
[docs] @classmethod def findall_window_ids(XCtrl, pattern=None): """ Returns: List[int]: wmctl ids for the matching windows CommandLine: python -m vimtk.xctrl XCtrl.findall_window_ids --pat=gvim --noskip python -m vimtk.xctrl XCtrl.findall_window_ids --pat=gvim python -m vimtk.xctrl XCtrl.findall_window_ids --pat=joncrall Example: >>> # xdoctest: +REQUIRES(--noskip) >>> from vimtk.xctrl import * # NOQA >>> pattern = ub.argval('--pat') >>> winid_list = XCtrl.findall_window_ids(pattern) >>> print('winid_list = {!r}'.format(winid_list)) Ignore: wmctrl -l xprop -id wmctrl -l | awk '{print $1}' | xprop -id 0x00a00007 | grep "WM_CLASS(STRING)" """ # List all windows and their identifiers info = XCtrl.cmd('wmctrl -lx') lines = info['out'].split('\n') if pattern is not None: # Find windows with identifiers matching the pattern lines = [line for line in lines if re.search(pattern, line)] # Get the hex-id portion of the output winid_list = [line.split()[0] for line in lines] winid_list = [int(h, 16) for h in winid_list if h] return winid_list
[docs] @classmethod def sort_window_ids(XCtrl, winid_list, order='mru'): """ Orders window ids by most recently used """ def isect(list1, list2): set2 = set(list2) return [item for item in list1 if item in set2] winid_order = XCtrl.sorted_window_ids(order) sorted_win_ids = isect(winid_order, winid_list) return sorted_win_ids
[docs] @staticmethod def killold(pattern, num=4): """ Leaves no more than `num` instances of a program alive. Ordering is determined by most recent usage. CommandLine: python -m vimtk.xctrl XCtrl.killold gvim 2 Example: >>> # xdoctest: +SKIP >>> XCtrl = xctrl.XCtrl >>> pattern = 'gvim' >>> num = 2 """ import psutil import ubelt as ub num = int(num) winid_list = XCtrl.findall_window_ids(pattern) winid_list = XCtrl.sort_window_ids(winid_list, 'mru')[num:] info = XCtrl.cmd('wmctrl -lxp') lines = info['out'].split('\n') lines = [' '.join(list(ub.take(line.split(), [0, 2]))) # type: ignore for line in lines] output_lines = lines # output_lines = XCtrl.cmd( # """wmctrl -lxp | awk '{print $1 " " $3}'""", # **cmdkw)['out'].strip().split('\n') output_fields = [line.split(' ') for line in output_lines] output_fields = [(int(wid, 16), int(pid)) for wid, pid in output_fields] pid_list = [pid for wid, pid in output_fields if wid in winid_list] for pid in pid_list: proc = psutil.Process(pid=pid) proc.kill()
[docs] @staticmethod def sorted_window_ids(order='mru'): """ Returns window ids orderd by criteria default is mru (most recently used) CommandLine: xprop -root | grep "^_NET_CLIENT_LIST_STACKING" | tr "," " " python -m vimtk.xctrl XCtrl.sorted_window_ids CommandLine: python -m vimtk.xctrl XCtrl.sorted_window_ids Example: >>> # xdoctest: +SKIP >>> winid_order = XCtrl.sorted_window_ids() >>> print('winid_order = {!r}'.format(winid_order)) """ info = XCtrl.cmd('xprop -root') lines = [line for line in info['out'].split('\n') if line.startswith('_NET_CLIENT_LIST_STACKING')] assert len(lines) == 1, str(lines) winid_order_str = lines[0] winid_order = winid_order_str.split('#')[1].strip().split(', ')[::-1] winid_order = [int(h, 16) for h in winid_order] if order == 'lru': winid_order = winid_order[::-1] elif order == 'mru': winid_order = winid_order else: raise NotImplementedError(order) return winid_order
[docs] @staticmethod def find_window_id(pattern, method='mru', error='raise'): """ xprop -id 0x00a00007 | grep "WM_CLASS(STRING)" """ logging.debug('Find window id pattern={}, method={}'.format(pattern, method)) winid_candidates = XCtrl.findall_window_ids(pattern) if len(winid_candidates) == 0: if error == 'raise': available_windows = XCtrl.cmd('wmctrl -lx')['out'] msg = 'No window matches pattern=%r' % (pattern,) msg += '\navailable windows are:\n%s' % (available_windows,) logger.error(msg) raise Exception(msg) win_id = None elif len(winid_candidates) == 1: win_id = winid_candidates[0] else: # print('Multiple (%d) windows matches pattern=%r' % ( # len(winid_list), pattern,)) # Find most recently used window with the focus name. win_id = XCtrl.sort_window_ids(winid_candidates, method)[0] return win_id
[docs] @staticmethod def current_gvim_edit(op='e', fpath=''): r""" CommandLine: python -m vimtk.xctrl XCtrl.current_gvim_edit sp ~/.bashrc """ import ubelt as ub import pathlib assert fpath is not None fpath = ub.shrinkuser(pathlib.Path(fpath).resolve()) # type: ignore # print('fpath = %r' % (fpath,)) cplat.copy_text_to_clipboard(fpath) doscript = [ ('focus', 'gvim'), ('key', 'Escape'), ('type2', ';' + op + ' ' + fpath), # ('type2', ';' + op + ' '), # ('key', 'ctrl+v'), ('key', 'KP_Enter'), ] XCtrl.do(*doscript, verbose=0, sleeptime=.001)
[docs] @staticmethod def copy_gvim_to_terminal_script(text, return_to_win="1", verbose=0, sleeptime=.02): """ vimtk.xctrl.XCtrl.copy_gvim_to_terminal_script('print("hi")', verbose=1) python -m vimtk.xctrl XCtrl.copy_gvim_to_terminal_script "echo hi" 1 1 If this doesn't work make sure pyperclip is installed and set to xsel print('foobar') echo hi """ # Prepare to send text to xdotool cplat.copy_text_to_clipboard(text) if verbose: print('text = %r' % (text,)) print(cplat.get_clipboard()) terminal_pattern = r'\|'.join([ 'terminal', re.escape('terminator.Terminator'), # gtk3 terminator re.escape('x-terminal-emulator.X-terminal-emulator'), # gtk2 terminator ]) # Build xdtool script doscript = [ ('remember_window_id', 'ACTIVE_WIN'), # ('focus', 'x-terminal-emulator.X-terminal-emulator'), ('focus', terminal_pattern), ('key', 'ctrl+shift+v'), ('key', 'KP_Enter'), ] if '\n' in text: # Press enter twice for multiline texts doscript += [ ('key', 'KP_Enter'), ] if return_to_win == "1": doscript += [ ('focus_id', '$ACTIVE_WIN'), ] # execute script # verbose = 1 XCtrl.do(*doscript, sleeptime=sleeptime, verbose=verbose)
[docs] @staticmethod def do(*cmd_list, **kwargs): """ DEPRICATE THIS """ import ubelt as ub verbose = kwargs.get('verbose', False) if verbose: print = logger.info else: print = logger.debug print('Executing x do: %s' % (ub.urepr(cmd_list),)) # type: ignore # http://askubuntu.com/questions/455762/xbindkeys-wont-work-properly # Make things work even if other keys are pressed defaultsleep = 0.0 sleeptime = kwargs.get('sleeptime', defaultsleep) time.sleep(.05) XCtrl.cmd('xset r off') memory = {} for count, item in enumerate(cmd_list): # print('item = %r' % (item,)) sleeptime = kwargs.get('sleeptime', defaultsleep) assert isinstance(item, tuple) assert len(item) >= 2 xcmd, key_ = item[0:2] if len(item) >= 3: if isinstance(item[2], str) and item[2].endswith('?'): sleeptime = float(item[2][:-1]) print('special command sleep') print('sleeptime = %r' % (sleeptime,)) else: sleeptime = float(item[2]) args = [] print('# Step %d' % (count,)) print('xcmd = {!r}'.format(xcmd)) if xcmd == 'focus': key_ = str(key_) if key_.startswith('$'): key_ = memory[key_[1:]] pattern = key_ win_id = XCtrl.find_window_id(pattern, method='mru') if win_id is None: args = ['wmctrl', '-xa', pattern] else: args = ['wmctrl', '-ia', hex(win_id)] elif xcmd == 'focus_id': key_ = str(key_) if key_.startswith('$'): key_ = memory[key_[1:]] assert isinstance(key_, str) args = ['wmctrl', '-ia', hex(key_)] # type: ignore elif xcmd == 'remember_window_id': memory[key_] = XCtrl.current_window_id() continue elif xcmd == 'remember_window_name': memory[key_] = XCtrl.current_window_name() continue elif xcmd == 'type': args = [ 'xdotool', 'keyup', '--window', '0', '7', 'type', '--clearmodifiers', '--window', '0', str(key_) ] elif xcmd == 'type2': args = [ 'xdotool', 'type', cmd_quote(str(key_)) ] elif xcmd == 'xset-r-on': args = ['xset', 'r', 'on'] elif xcmd == 'xset-r-off': args = ['xset', 'r', 'off'] else: args = ['xdotool', str(xcmd), str(key_)] print('args = {!r}'.format(args)) XCtrl.cmd(args) if sleeptime > 0: time.sleep(sleeptime) XCtrl.cmd('xset r on')
[docs] @staticmethod def current_window_id(): logging.debug('Get current window id') info = XCtrl.cmd('xdotool getwindowfocus') value = int(info['out'].strip()) logging.debug('... current window id = {}'.format(value)) return value
[docs] @staticmethod def current_window_name(): logging.debug('Get current window name') info = XCtrl.cmd('xdotool getwindowfocus getwindowname') value = cmd_quote(info['out'].strip()) logging.debug('... current window name = {}'.format(value)) return value
[docs] @staticmethod def focus_window(winhandle, path=None, name=None, sleeptime=.01): """ sudo apt-get install xautomation apt-get install autokey-gtk wmctrl -xa gnome-terminal.Gnome-terminal wmctrl -xl """ print('focus: ' + winhandle) args = ['wmctrl', '-xa', winhandle] XCtrl.cmd(args) time.sleep(sleeptime)
[docs] @classmethod def send_keys(XCtrl, key, sleeptime=0.1): args = ['xdotool', 'key', str(key)] XCtrl.cmd(args) time.sleep(sleeptime)
# @classmethod # def focus(XCtrl, pattern=None, win_id=None, sleeptime=.01): # """ # sudo apt-get install xautomation # apt-get install autokey-gtk # wmctrl -xa gnome-terminal.Gnome-terminal # wmctrl -xl # """ # if pattern is not None: # assert win_id is None # if win_id is None: # assert pattern is not None # win_id = XCtrl.find_window_id(pattern, method='mru') # if win_id is None: # args = ['wmctrl', '-xa', pattern] # else: # args = ['wmctrl', '-ia', hex(win_id)] # XCtrl.cmd(*args, verbose=False) # time.sleep(sleeptime) if __name__ == '__main__': r""" CommandLine: export PYTHONPATH=$PYTHONPATH:$HOME/code/vimtk python -m vimtk.xctrl """ import xdoctest xdoctest.doctest_module(__file__)