--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (C) 2011-2012 Neil Brown <neilb@suse.de>
+#
+# 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 2 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.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# fakeinput.py
+# based on pykey, see also "crikey"
+# and http://shallowsky.com/blog/tags/crikey/
+#
+# a char or a string can be sent as typed input to the
+# 'focus' window in X11.
+# Strangely, '<' cannot be marked as shifted, so it is entered
+# as an unshifted '<'.
+
+import Xlib.display
+import Xlib.X
+import Xlib.XK
+import Xlib.protocol.event
+
+UseXTest = True
+
+try :
+ import Xlib.ext.xtest
+except ImportError:
+ UseXTest = False
+ print "no XTest extension; using XSendEvent"
+
+import sys, time
+
+special_X_keysyms = {
+ '\b': "BackSpace",
+ ' ' : "space",
+ '\t' : "Tab",
+ '\n' : "Return", # for some reason this needs to be cr, not lf
+ '\r' : "Return",
+ '\033' : "Escape",
+ '!' : "exclam",
+ '#' : "numbersign",
+ '%' : "percent",
+ '$' : "dollar",
+ '&' : "ampersand",
+ '"' : "quotedbl",
+ '\'' : "apostrophe",
+ '(' : "parenleft",
+ ')' : "parenright",
+ '*' : "asterisk",
+ '=' : "equal",
+ '+' : "plus",
+ ',' : "comma",
+ '-' : "minus",
+ '.' : "period",
+ '/' : "slash",
+ ':' : "colon",
+ ';' : "semicolon",
+ '<' : "less",
+ '>' : "greater",
+ '?' : "question",
+ '@' : "at",
+ '[' : "bracketleft",
+ ']' : "bracketright",
+ '\\' : "backslash",
+ '^' : "asciicircum",
+ '_' : "underscore",
+ '`' : "grave",
+ '{' : "braceleft",
+ '|' : "bar",
+ '}' : "braceright",
+ '~' : "asciitilde"
+ }
+
+def get_keysym(ch) :
+ keysym = Xlib.XK.string_to_keysym(ch)
+ if keysym == 0 :
+ # Unfortunately, although this works to get the correct keysym
+ # i.e. keysym for '#' is returned as "numbersign"
+ # the subsequent display.keysym_to_keycode("numbersign") is 0.
+ keysym = Xlib.XK.string_to_keysym(special_X_keysyms[ch])
+ return keysym
+
+def is_shifted(ch) :
+ if ch.isupper() :
+ return True
+ if "~!@#$%^&*()_+{}|:\">?".find(ch) >= 0 :
+ return True
+ return False
+
+class fakeinput:
+ def __init__(self, display = None):
+ global UseXTest
+ if display:
+ self.display = display
+ else:
+ self.display = Xlib.display.Display()
+
+ self.UseXTest = UseXTest
+
+ if UseXTest and not self.display.query_extension("XTEST") :
+ self.UseXTest = False
+
+ self.new_window()
+
+ def new_window(self):
+ if not self.UseXTest:
+ self.window = self.display.get_input_focus()._data["focus"];
+
+ def char_to_keycode(self, ch):
+ keysym = get_keysym(ch)
+ keycode = self.display.keysym_to_keycode(keysym)
+ if keycode == 0 :
+ print "fakeinput: Sorry, can't map", ch
+
+ if (is_shifted(ch)) :
+ shift_mask = Xlib.X.ShiftMask
+ else :
+ shift_mask = 0
+
+ return keycode, shift_mask
+
+ def send_char(self, ch, dosync = True) :
+ keycode, shift_mask = self.char_to_keycode(ch)
+ if (self.UseXTest) :
+ if shift_mask != 0 :
+ Xlib.ext.xtest.fake_input(self.display, Xlib.X.KeyPress, 50)
+ Xlib.ext.xtest.fake_input(self.display, Xlib.X.KeyPress, keycode)
+ Xlib.ext.xtest.fake_input(self.display, Xlib.X.KeyRelease, keycode)
+ if shift_mask != 0 :
+ Xlib.ext.xtest.fake_input(self.display, Xlib.X.KeyRelease, 50)
+ else :
+ event = Xlib.protocol.event.KeyPress(
+ time = int(time.time()),
+ root = self.display.screen().root,
+ window = self.window,
+ same_screen = 0, child = Xlib.X.NONE,
+ root_x = 0, root_y = 0, event_x = 0, event_y = 0,
+ state = shift_mask,
+ detail = keycode
+ )
+ self.window.send_event(event, propagate = True)
+ event = Xlib.protocol.event.KeyRelease(
+ time = int(time.time()),
+ root = self.display.screen().root,
+ window = self.window,
+ same_screen = 0, child = Xlib.X.NONE,
+ root_x = 0, root_y = 0, event_x = 0, event_y = 0,
+ state = shift_mask,
+ detail = keycode
+ )
+ self.window.send_event(event, propagate = True)
+ if dosync:
+ self.display.sync()
+
+ def send_str(self, str):
+ for ch in str:
+ self.send_char(ch, dosync = False)
+ self.display.sync()
+
+
+if __name__ == "__main__":
+ import sys, time
+ if len(sys.argv) != 2:
+ print "Please provide an arg to be typed"
+ sys.exit(0)
+ print "Please select the target window in 3 seconds"
+ f = fakeinput()
+ time.sleep(3)
+ f.send_str(sys.argv[1])