3
__author__ = 'David Malcolm <dmalcolm@redhat.com>'
6
# FIXME: under construction
7
# The event handler callback seems to trap and lose Ctrl-C so you need to be ready to be
8
# kill the python process via some other means
15
if isinstance(source, atspi.Accessible):
16
sourceStr = " source:%s"%(str(dogtail.tree.Node(source)))
19
print "Got event: %s%s"%(event.type, sourceStr)
24
Abstract base class for writing out events
26
def recordClick(self, node):
27
raise NotImplementedError
29
class ScriptWriter(Writer):
31
Abstract Writer subclass which writes out Python scripts
35
class OOScriptWriter(ScriptWriter):
37
Concrete Writer subclass which writes out Python scripts in an object-oriented
41
# maintain a dict from variable names to search paths
44
self.debugVariables = False
46
def generateVariableName(self, predicate):
48
result = predicate.makeScriptVariableName()
49
if result in self.variables:
50
# This variable name is already in use; need to append a number:
52
while result+str(index) in self.variables:
54
return result+str(index)
58
def printVariables(self):
61
for (varName, varAbsPath) in self.variables.iteritems():
62
print "varName:%s -> absPath:%s"%(varName, varAbsPath)
64
def generateAbsSearchPathMethodCall(self, absSearchPath):
66
Generates a method call that identifies the absolute search path,
67
optimizing away prefixes where possible with variable names.
69
# We optimize away the longest common absolute path prefix, i.e. the
70
# shortest relative path suffix:
72
print "*******************"
73
print "generateAbsSearchPathMethodCall for %s"%absSearchPath
76
shortestRelativePath = None
77
for (varName, varAbsPath) in self.variables.iteritems():
78
relPath = varAbsPath.getRelativePath(absSearchPath)
80
if shortestRelativePath:
81
if relPath.length() < shortestRelativePath[2].length():
82
shortestRelativePath = (varName, varAbsPath, relPath)
84
shortestRelativePath = (varName, varAbsPath, relPath)
87
if shortestRelativePath:
88
(varName, varAbsPath, relPath) = shortestRelativePath
89
print "shortestRelativePath: (%s, %s, %s)"%(varName, varAbsPath, relPath)
91
print "shortestRelativePath: None"
92
print "*******************"
94
if shortestRelativePath:
95
(varName, varAbsPath, relPath) = shortestRelativePath
96
return varName+relPath.makeScriptMethodCall()
98
# Have to specify it as an absolute path:
99
return "root"+absSearchPath.makeScriptMethodCall()
101
def recordClick(self, node):
102
searchPath = node.getAbsoluteSearchPath()
105
print "----------------------------------"
106
print "click on %s"%searchPath
107
print "Full script would be: root%s"%searchPath.makeScriptMethodCall()
109
# Generate variables for nodes likely to be referred to often (application, window)
110
# FIXME: make this smarter?
112
if i<searchPath.length():
114
prefixPath = searchPath.getPrefix(i)
116
if self.debugVariables:
117
print "Considering: %s"%prefixPath
119
if not prefixPath in self.variables.values():
120
if self.debugVariables:
121
print "It is not yet a variable"
122
self.printVariables()
124
varName = prefixPath.getPredicate(i-1).makeScriptVariableName()
125
print varName+" = "+self.generateAbsSearchPathMethodCall(prefixPath)
126
self.variables[varName]=prefixPath
128
if self.debugVariables:
129
print "It is already a variable"
131
result = self.generateAbsSearchPathMethodCall(searchPath)
135
print "----------------------------------"
139
class ProceduralScriptWriter(ScriptWriter):
141
Concrete Writer subclass which writes out Python scripts in a procedural
144
def recordClick(self, node):
145
# FIXME: not yet written
146
raise NotImplementedError
148
# Singleton EventRecorder
151
# Test event recording class; under construction
154
self.writer = OOScriptWriter()
155
self.__registerEvents()
156
self.lastFocussedNode = None
157
self.absoluteNodePaths = True
159
def __registerEvents(self):
160
# Only specific events are recorded:
163
atspi.EventListener(marshalOnFocus, ["focus:"])
165
# Mouse button-1 clicks:
166
atspi.EventListener(marshalOnMouseClick, ["mouse:button:1p"])
169
atspi.EventListener(marshalOnWindowCreate, ["window:create"])
171
def onFocus(self, event):
173
sourceNode = dogtail.tree.Node(event.source)
174
#print "Focus on %s"%str(sourceNode)
175
#path = sourceNode.getAbsoluteSourcePath()
176
#print "SourcePath: %s"%path
177
#print " Script: %s"%path.make
178
self.lastFocussedNode = sourceNode
180
def onMouseClick(self, event):
182
sourceNode = dogtail.tree.Node(event.source)
183
# sourceNode seems to always be set to "main" (other events come through on all objects)
184
# so we pretend the click was on the last node to be focussed
185
# print "Click on %s"%str(self.getLogStringForNode(self.lastFocussedNode))
186
if self.lastFocussedNode!=None:
187
self.writer.recordClick(self.lastFocussedNode)
189
def onWindowCreate(self, event):
191
sourceNode = dogtail.tree.Node(event.source)
192
# print "Window creation: %s"%str(sourceNode)
194
def getLogStringForNode(self, node):
195
if self.absoluteNodePaths:
196
return node.getAbsoluteSearchPath()
200
# Under construction. These ought to be methods, but am having Python assertion
201
# failures in refcounting when trying to hook them up using lambda expressions; grrr...
202
def marshalOnFocus(event):
203
recorder.onFocus(event)
205
def marshalOnMouseClick(event):
206
recorder.onMouseClick(event)
208
def marshalOnWindowCreate(event):
209
recorder.onWindowCreate(event)
211
recorder = EventRecorder()
212
#recorder.writer.debug = True
213
#recorder.writer.debugVariables = True