annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/multicall.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
rev   line source
jpayne@68 1 """
jpayne@68 2 MultiCall - a class which inherits its methods from a Tkinter widget (Text, for
jpayne@68 3 example), but enables multiple calls of functions per virtual event - all
jpayne@68 4 matching events will be called, not only the most specific one. This is done
jpayne@68 5 by wrapping the event functions - event_add, event_delete and event_info.
jpayne@68 6 MultiCall recognizes only a subset of legal event sequences. Sequences which
jpayne@68 7 are not recognized are treated by the original Tk handling mechanism. A
jpayne@68 8 more-specific event will be called before a less-specific event.
jpayne@68 9
jpayne@68 10 The recognized sequences are complete one-event sequences (no emacs-style
jpayne@68 11 Ctrl-X Ctrl-C, no shortcuts like <3>), for all types of events.
jpayne@68 12 Key/Button Press/Release events can have modifiers.
jpayne@68 13 The recognized modifiers are Shift, Control, Option and Command for Mac, and
jpayne@68 14 Control, Alt, Shift, Meta/M for other platforms.
jpayne@68 15
jpayne@68 16 For all events which were handled by MultiCall, a new member is added to the
jpayne@68 17 event instance passed to the binded functions - mc_type. This is one of the
jpayne@68 18 event type constants defined in this module (such as MC_KEYPRESS).
jpayne@68 19 For Key/Button events (which are handled by MultiCall and may receive
jpayne@68 20 modifiers), another member is added - mc_state. This member gives the state
jpayne@68 21 of the recognized modifiers, as a combination of the modifier constants
jpayne@68 22 also defined in this module (for example, MC_SHIFT).
jpayne@68 23 Using these members is absolutely portable.
jpayne@68 24
jpayne@68 25 The order by which events are called is defined by these rules:
jpayne@68 26 1. A more-specific event will be called before a less-specific event.
jpayne@68 27 2. A recently-binded event will be called before a previously-binded event,
jpayne@68 28 unless this conflicts with the first rule.
jpayne@68 29 Each function will be called at most once for each event.
jpayne@68 30 """
jpayne@68 31 import re
jpayne@68 32 import sys
jpayne@68 33
jpayne@68 34 import tkinter
jpayne@68 35
jpayne@68 36 # the event type constants, which define the meaning of mc_type
jpayne@68 37 MC_KEYPRESS=0; MC_KEYRELEASE=1; MC_BUTTONPRESS=2; MC_BUTTONRELEASE=3;
jpayne@68 38 MC_ACTIVATE=4; MC_CIRCULATE=5; MC_COLORMAP=6; MC_CONFIGURE=7;
jpayne@68 39 MC_DEACTIVATE=8; MC_DESTROY=9; MC_ENTER=10; MC_EXPOSE=11; MC_FOCUSIN=12;
jpayne@68 40 MC_FOCUSOUT=13; MC_GRAVITY=14; MC_LEAVE=15; MC_MAP=16; MC_MOTION=17;
jpayne@68 41 MC_MOUSEWHEEL=18; MC_PROPERTY=19; MC_REPARENT=20; MC_UNMAP=21; MC_VISIBILITY=22;
jpayne@68 42 # the modifier state constants, which define the meaning of mc_state
jpayne@68 43 MC_SHIFT = 1<<0; MC_CONTROL = 1<<2; MC_ALT = 1<<3; MC_META = 1<<5
jpayne@68 44 MC_OPTION = 1<<6; MC_COMMAND = 1<<7
jpayne@68 45
jpayne@68 46 # define the list of modifiers, to be used in complex event types.
jpayne@68 47 if sys.platform == "darwin":
jpayne@68 48 _modifiers = (("Shift",), ("Control",), ("Option",), ("Command",))
jpayne@68 49 _modifier_masks = (MC_SHIFT, MC_CONTROL, MC_OPTION, MC_COMMAND)
jpayne@68 50 else:
jpayne@68 51 _modifiers = (("Control",), ("Alt",), ("Shift",), ("Meta", "M"))
jpayne@68 52 _modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META)
jpayne@68 53
jpayne@68 54 # a dictionary to map a modifier name into its number
jpayne@68 55 _modifier_names = dict([(name, number)
jpayne@68 56 for number in range(len(_modifiers))
jpayne@68 57 for name in _modifiers[number]])
jpayne@68 58
jpayne@68 59 # In 3.4, if no shell window is ever open, the underlying Tk widget is
jpayne@68 60 # destroyed before .__del__ methods here are called. The following
jpayne@68 61 # is used to selectively ignore shutdown exceptions to avoid
jpayne@68 62 # 'Exception ignored' messages. See http://bugs.python.org/issue20167
jpayne@68 63 APPLICATION_GONE = "application has been destroyed"
jpayne@68 64
jpayne@68 65 # A binder is a class which binds functions to one type of event. It has two
jpayne@68 66 # methods: bind and unbind, which get a function and a parsed sequence, as
jpayne@68 67 # returned by _parse_sequence(). There are two types of binders:
jpayne@68 68 # _SimpleBinder handles event types with no modifiers and no detail.
jpayne@68 69 # No Python functions are called when no events are binded.
jpayne@68 70 # _ComplexBinder handles event types with modifiers and a detail.
jpayne@68 71 # A Python function is called each time an event is generated.
jpayne@68 72
jpayne@68 73 class _SimpleBinder:
jpayne@68 74 def __init__(self, type, widget, widgetinst):
jpayne@68 75 self.type = type
jpayne@68 76 self.sequence = '<'+_types[type][0]+'>'
jpayne@68 77 self.widget = widget
jpayne@68 78 self.widgetinst = widgetinst
jpayne@68 79 self.bindedfuncs = []
jpayne@68 80 self.handlerid = None
jpayne@68 81
jpayne@68 82 def bind(self, triplet, func):
jpayne@68 83 if not self.handlerid:
jpayne@68 84 def handler(event, l = self.bindedfuncs, mc_type = self.type):
jpayne@68 85 event.mc_type = mc_type
jpayne@68 86 wascalled = {}
jpayne@68 87 for i in range(len(l)-1, -1, -1):
jpayne@68 88 func = l[i]
jpayne@68 89 if func not in wascalled:
jpayne@68 90 wascalled[func] = True
jpayne@68 91 r = func(event)
jpayne@68 92 if r:
jpayne@68 93 return r
jpayne@68 94 self.handlerid = self.widget.bind(self.widgetinst,
jpayne@68 95 self.sequence, handler)
jpayne@68 96 self.bindedfuncs.append(func)
jpayne@68 97
jpayne@68 98 def unbind(self, triplet, func):
jpayne@68 99 self.bindedfuncs.remove(func)
jpayne@68 100 if not self.bindedfuncs:
jpayne@68 101 self.widget.unbind(self.widgetinst, self.sequence, self.handlerid)
jpayne@68 102 self.handlerid = None
jpayne@68 103
jpayne@68 104 def __del__(self):
jpayne@68 105 if self.handlerid:
jpayne@68 106 try:
jpayne@68 107 self.widget.unbind(self.widgetinst, self.sequence,
jpayne@68 108 self.handlerid)
jpayne@68 109 except tkinter.TclError as e:
jpayne@68 110 if not APPLICATION_GONE in e.args[0]:
jpayne@68 111 raise
jpayne@68 112
jpayne@68 113 # An int in range(1 << len(_modifiers)) represents a combination of modifiers
jpayne@68 114 # (if the least significant bit is on, _modifiers[0] is on, and so on).
jpayne@68 115 # _state_subsets gives for each combination of modifiers, or *state*,
jpayne@68 116 # a list of the states which are a subset of it. This list is ordered by the
jpayne@68 117 # number of modifiers is the state - the most specific state comes first.
jpayne@68 118 _states = range(1 << len(_modifiers))
jpayne@68 119 _state_names = [''.join(m[0]+'-'
jpayne@68 120 for i, m in enumerate(_modifiers)
jpayne@68 121 if (1 << i) & s)
jpayne@68 122 for s in _states]
jpayne@68 123
jpayne@68 124 def expand_substates(states):
jpayne@68 125 '''For each item of states return a list containing all combinations of
jpayne@68 126 that item with individual bits reset, sorted by the number of set bits.
jpayne@68 127 '''
jpayne@68 128 def nbits(n):
jpayne@68 129 "number of bits set in n base 2"
jpayne@68 130 nb = 0
jpayne@68 131 while n:
jpayne@68 132 n, rem = divmod(n, 2)
jpayne@68 133 nb += rem
jpayne@68 134 return nb
jpayne@68 135 statelist = []
jpayne@68 136 for state in states:
jpayne@68 137 substates = list(set(state & x for x in states))
jpayne@68 138 substates.sort(key=nbits, reverse=True)
jpayne@68 139 statelist.append(substates)
jpayne@68 140 return statelist
jpayne@68 141
jpayne@68 142 _state_subsets = expand_substates(_states)
jpayne@68 143
jpayne@68 144 # _state_codes gives for each state, the portable code to be passed as mc_state
jpayne@68 145 _state_codes = []
jpayne@68 146 for s in _states:
jpayne@68 147 r = 0
jpayne@68 148 for i in range(len(_modifiers)):
jpayne@68 149 if (1 << i) & s:
jpayne@68 150 r |= _modifier_masks[i]
jpayne@68 151 _state_codes.append(r)
jpayne@68 152
jpayne@68 153 class _ComplexBinder:
jpayne@68 154 # This class binds many functions, and only unbinds them when it is deleted.
jpayne@68 155 # self.handlerids is the list of seqs and ids of binded handler functions.
jpayne@68 156 # The binded functions sit in a dictionary of lists of lists, which maps
jpayne@68 157 # a detail (or None) and a state into a list of functions.
jpayne@68 158 # When a new detail is discovered, handlers for all the possible states
jpayne@68 159 # are binded.
jpayne@68 160
jpayne@68 161 def __create_handler(self, lists, mc_type, mc_state):
jpayne@68 162 def handler(event, lists = lists,
jpayne@68 163 mc_type = mc_type, mc_state = mc_state,
jpayne@68 164 ishandlerrunning = self.ishandlerrunning,
jpayne@68 165 doafterhandler = self.doafterhandler):
jpayne@68 166 ishandlerrunning[:] = [True]
jpayne@68 167 event.mc_type = mc_type
jpayne@68 168 event.mc_state = mc_state
jpayne@68 169 wascalled = {}
jpayne@68 170 r = None
jpayne@68 171 for l in lists:
jpayne@68 172 for i in range(len(l)-1, -1, -1):
jpayne@68 173 func = l[i]
jpayne@68 174 if func not in wascalled:
jpayne@68 175 wascalled[func] = True
jpayne@68 176 r = l[i](event)
jpayne@68 177 if r:
jpayne@68 178 break
jpayne@68 179 if r:
jpayne@68 180 break
jpayne@68 181 ishandlerrunning[:] = []
jpayne@68 182 # Call all functions in doafterhandler and remove them from list
jpayne@68 183 for f in doafterhandler:
jpayne@68 184 f()
jpayne@68 185 doafterhandler[:] = []
jpayne@68 186 if r:
jpayne@68 187 return r
jpayne@68 188 return handler
jpayne@68 189
jpayne@68 190 def __init__(self, type, widget, widgetinst):
jpayne@68 191 self.type = type
jpayne@68 192 self.typename = _types[type][0]
jpayne@68 193 self.widget = widget
jpayne@68 194 self.widgetinst = widgetinst
jpayne@68 195 self.bindedfuncs = {None: [[] for s in _states]}
jpayne@68 196 self.handlerids = []
jpayne@68 197 # we don't want to change the lists of functions while a handler is
jpayne@68 198 # running - it will mess up the loop and anyway, we usually want the
jpayne@68 199 # change to happen from the next event. So we have a list of functions
jpayne@68 200 # for the handler to run after it finishes calling the binded functions.
jpayne@68 201 # It calls them only once.
jpayne@68 202 # ishandlerrunning is a list. An empty one means no, otherwise - yes.
jpayne@68 203 # this is done so that it would be mutable.
jpayne@68 204 self.ishandlerrunning = []
jpayne@68 205 self.doafterhandler = []
jpayne@68 206 for s in _states:
jpayne@68 207 lists = [self.bindedfuncs[None][i] for i in _state_subsets[s]]
jpayne@68 208 handler = self.__create_handler(lists, type, _state_codes[s])
jpayne@68 209 seq = '<'+_state_names[s]+self.typename+'>'
jpayne@68 210 self.handlerids.append((seq, self.widget.bind(self.widgetinst,
jpayne@68 211 seq, handler)))
jpayne@68 212
jpayne@68 213 def bind(self, triplet, func):
jpayne@68 214 if triplet[2] not in self.bindedfuncs:
jpayne@68 215 self.bindedfuncs[triplet[2]] = [[] for s in _states]
jpayne@68 216 for s in _states:
jpayne@68 217 lists = [ self.bindedfuncs[detail][i]
jpayne@68 218 for detail in (triplet[2], None)
jpayne@68 219 for i in _state_subsets[s] ]
jpayne@68 220 handler = self.__create_handler(lists, self.type,
jpayne@68 221 _state_codes[s])
jpayne@68 222 seq = "<%s%s-%s>"% (_state_names[s], self.typename, triplet[2])
jpayne@68 223 self.handlerids.append((seq, self.widget.bind(self.widgetinst,
jpayne@68 224 seq, handler)))
jpayne@68 225 doit = lambda: self.bindedfuncs[triplet[2]][triplet[0]].append(func)
jpayne@68 226 if not self.ishandlerrunning:
jpayne@68 227 doit()
jpayne@68 228 else:
jpayne@68 229 self.doafterhandler.append(doit)
jpayne@68 230
jpayne@68 231 def unbind(self, triplet, func):
jpayne@68 232 doit = lambda: self.bindedfuncs[triplet[2]][triplet[0]].remove(func)
jpayne@68 233 if not self.ishandlerrunning:
jpayne@68 234 doit()
jpayne@68 235 else:
jpayne@68 236 self.doafterhandler.append(doit)
jpayne@68 237
jpayne@68 238 def __del__(self):
jpayne@68 239 for seq, id in self.handlerids:
jpayne@68 240 try:
jpayne@68 241 self.widget.unbind(self.widgetinst, seq, id)
jpayne@68 242 except tkinter.TclError as e:
jpayne@68 243 if not APPLICATION_GONE in e.args[0]:
jpayne@68 244 raise
jpayne@68 245
jpayne@68 246 # define the list of event types to be handled by MultiEvent. the order is
jpayne@68 247 # compatible with the definition of event type constants.
jpayne@68 248 _types = (
jpayne@68 249 ("KeyPress", "Key"), ("KeyRelease",), ("ButtonPress", "Button"),
jpayne@68 250 ("ButtonRelease",), ("Activate",), ("Circulate",), ("Colormap",),
jpayne@68 251 ("Configure",), ("Deactivate",), ("Destroy",), ("Enter",), ("Expose",),
jpayne@68 252 ("FocusIn",), ("FocusOut",), ("Gravity",), ("Leave",), ("Map",),
jpayne@68 253 ("Motion",), ("MouseWheel",), ("Property",), ("Reparent",), ("Unmap",),
jpayne@68 254 ("Visibility",),
jpayne@68 255 )
jpayne@68 256
jpayne@68 257 # which binder should be used for every event type?
jpayne@68 258 _binder_classes = (_ComplexBinder,) * 4 + (_SimpleBinder,) * (len(_types)-4)
jpayne@68 259
jpayne@68 260 # A dictionary to map a type name into its number
jpayne@68 261 _type_names = dict([(name, number)
jpayne@68 262 for number in range(len(_types))
jpayne@68 263 for name in _types[number]])
jpayne@68 264
jpayne@68 265 _keysym_re = re.compile(r"^\w+$")
jpayne@68 266 _button_re = re.compile(r"^[1-5]$")
jpayne@68 267 def _parse_sequence(sequence):
jpayne@68 268 """Get a string which should describe an event sequence. If it is
jpayne@68 269 successfully parsed as one, return a tuple containing the state (as an int),
jpayne@68 270 the event type (as an index of _types), and the detail - None if none, or a
jpayne@68 271 string if there is one. If the parsing is unsuccessful, return None.
jpayne@68 272 """
jpayne@68 273 if not sequence or sequence[0] != '<' or sequence[-1] != '>':
jpayne@68 274 return None
jpayne@68 275 words = sequence[1:-1].split('-')
jpayne@68 276 modifiers = 0
jpayne@68 277 while words and words[0] in _modifier_names:
jpayne@68 278 modifiers |= 1 << _modifier_names[words[0]]
jpayne@68 279 del words[0]
jpayne@68 280 if words and words[0] in _type_names:
jpayne@68 281 type = _type_names[words[0]]
jpayne@68 282 del words[0]
jpayne@68 283 else:
jpayne@68 284 return None
jpayne@68 285 if _binder_classes[type] is _SimpleBinder:
jpayne@68 286 if modifiers or words:
jpayne@68 287 return None
jpayne@68 288 else:
jpayne@68 289 detail = None
jpayne@68 290 else:
jpayne@68 291 # _ComplexBinder
jpayne@68 292 if type in [_type_names[s] for s in ("KeyPress", "KeyRelease")]:
jpayne@68 293 type_re = _keysym_re
jpayne@68 294 else:
jpayne@68 295 type_re = _button_re
jpayne@68 296
jpayne@68 297 if not words:
jpayne@68 298 detail = None
jpayne@68 299 elif len(words) == 1 and type_re.match(words[0]):
jpayne@68 300 detail = words[0]
jpayne@68 301 else:
jpayne@68 302 return None
jpayne@68 303
jpayne@68 304 return modifiers, type, detail
jpayne@68 305
jpayne@68 306 def _triplet_to_sequence(triplet):
jpayne@68 307 if triplet[2]:
jpayne@68 308 return '<'+_state_names[triplet[0]]+_types[triplet[1]][0]+'-'+ \
jpayne@68 309 triplet[2]+'>'
jpayne@68 310 else:
jpayne@68 311 return '<'+_state_names[triplet[0]]+_types[triplet[1]][0]+'>'
jpayne@68 312
jpayne@68 313 _multicall_dict = {}
jpayne@68 314 def MultiCallCreator(widget):
jpayne@68 315 """Return a MultiCall class which inherits its methods from the
jpayne@68 316 given widget class (for example, Tkinter.Text). This is used
jpayne@68 317 instead of a templating mechanism.
jpayne@68 318 """
jpayne@68 319 if widget in _multicall_dict:
jpayne@68 320 return _multicall_dict[widget]
jpayne@68 321
jpayne@68 322 class MultiCall (widget):
jpayne@68 323 assert issubclass(widget, tkinter.Misc)
jpayne@68 324
jpayne@68 325 def __init__(self, *args, **kwargs):
jpayne@68 326 widget.__init__(self, *args, **kwargs)
jpayne@68 327 # a dictionary which maps a virtual event to a tuple with:
jpayne@68 328 # 0. the function binded
jpayne@68 329 # 1. a list of triplets - the sequences it is binded to
jpayne@68 330 self.__eventinfo = {}
jpayne@68 331 self.__binders = [_binder_classes[i](i, widget, self)
jpayne@68 332 for i in range(len(_types))]
jpayne@68 333
jpayne@68 334 def bind(self, sequence=None, func=None, add=None):
jpayne@68 335 #print("bind(%s, %s, %s)" % (sequence, func, add),
jpayne@68 336 # file=sys.__stderr__)
jpayne@68 337 if type(sequence) is str and len(sequence) > 2 and \
jpayne@68 338 sequence[:2] == "<<" and sequence[-2:] == ">>":
jpayne@68 339 if sequence in self.__eventinfo:
jpayne@68 340 ei = self.__eventinfo[sequence]
jpayne@68 341 if ei[0] is not None:
jpayne@68 342 for triplet in ei[1]:
jpayne@68 343 self.__binders[triplet[1]].unbind(triplet, ei[0])
jpayne@68 344 ei[0] = func
jpayne@68 345 if ei[0] is not None:
jpayne@68 346 for triplet in ei[1]:
jpayne@68 347 self.__binders[triplet[1]].bind(triplet, func)
jpayne@68 348 else:
jpayne@68 349 self.__eventinfo[sequence] = [func, []]
jpayne@68 350 return widget.bind(self, sequence, func, add)
jpayne@68 351
jpayne@68 352 def unbind(self, sequence, funcid=None):
jpayne@68 353 if type(sequence) is str and len(sequence) > 2 and \
jpayne@68 354 sequence[:2] == "<<" and sequence[-2:] == ">>" and \
jpayne@68 355 sequence in self.__eventinfo:
jpayne@68 356 func, triplets = self.__eventinfo[sequence]
jpayne@68 357 if func is not None:
jpayne@68 358 for triplet in triplets:
jpayne@68 359 self.__binders[triplet[1]].unbind(triplet, func)
jpayne@68 360 self.__eventinfo[sequence][0] = None
jpayne@68 361 return widget.unbind(self, sequence, funcid)
jpayne@68 362
jpayne@68 363 def event_add(self, virtual, *sequences):
jpayne@68 364 #print("event_add(%s, %s)" % (repr(virtual), repr(sequences)),
jpayne@68 365 # file=sys.__stderr__)
jpayne@68 366 if virtual not in self.__eventinfo:
jpayne@68 367 self.__eventinfo[virtual] = [None, []]
jpayne@68 368
jpayne@68 369 func, triplets = self.__eventinfo[virtual]
jpayne@68 370 for seq in sequences:
jpayne@68 371 triplet = _parse_sequence(seq)
jpayne@68 372 if triplet is None:
jpayne@68 373 #print("Tkinter event_add(%s)" % seq, file=sys.__stderr__)
jpayne@68 374 widget.event_add(self, virtual, seq)
jpayne@68 375 else:
jpayne@68 376 if func is not None:
jpayne@68 377 self.__binders[triplet[1]].bind(triplet, func)
jpayne@68 378 triplets.append(triplet)
jpayne@68 379
jpayne@68 380 def event_delete(self, virtual, *sequences):
jpayne@68 381 if virtual not in self.__eventinfo:
jpayne@68 382 return
jpayne@68 383 func, triplets = self.__eventinfo[virtual]
jpayne@68 384 for seq in sequences:
jpayne@68 385 triplet = _parse_sequence(seq)
jpayne@68 386 if triplet is None:
jpayne@68 387 #print("Tkinter event_delete: %s" % seq, file=sys.__stderr__)
jpayne@68 388 widget.event_delete(self, virtual, seq)
jpayne@68 389 else:
jpayne@68 390 if func is not None:
jpayne@68 391 self.__binders[triplet[1]].unbind(triplet, func)
jpayne@68 392 triplets.remove(triplet)
jpayne@68 393
jpayne@68 394 def event_info(self, virtual=None):
jpayne@68 395 if virtual is None or virtual not in self.__eventinfo:
jpayne@68 396 return widget.event_info(self, virtual)
jpayne@68 397 else:
jpayne@68 398 return tuple(map(_triplet_to_sequence,
jpayne@68 399 self.__eventinfo[virtual][1])) + \
jpayne@68 400 widget.event_info(self, virtual)
jpayne@68 401
jpayne@68 402 def __del__(self):
jpayne@68 403 for virtual in self.__eventinfo:
jpayne@68 404 func, triplets = self.__eventinfo[virtual]
jpayne@68 405 if func:
jpayne@68 406 for triplet in triplets:
jpayne@68 407 try:
jpayne@68 408 self.__binders[triplet[1]].unbind(triplet, func)
jpayne@68 409 except tkinter.TclError as e:
jpayne@68 410 if not APPLICATION_GONE in e.args[0]:
jpayne@68 411 raise
jpayne@68 412
jpayne@68 413 _multicall_dict[widget] = MultiCall
jpayne@68 414 return MultiCall
jpayne@68 415
jpayne@68 416
jpayne@68 417 def _multi_call(parent): # htest #
jpayne@68 418 top = tkinter.Toplevel(parent)
jpayne@68 419 top.title("Test MultiCall")
jpayne@68 420 x, y = map(int, parent.geometry().split('+')[1:])
jpayne@68 421 top.geometry("+%d+%d" % (x, y + 175))
jpayne@68 422 text = MultiCallCreator(tkinter.Text)(top)
jpayne@68 423 text.pack()
jpayne@68 424 def bindseq(seq, n=[0]):
jpayne@68 425 def handler(event):
jpayne@68 426 print(seq)
jpayne@68 427 text.bind("<<handler%d>>"%n[0], handler)
jpayne@68 428 text.event_add("<<handler%d>>"%n[0], seq)
jpayne@68 429 n[0] += 1
jpayne@68 430 bindseq("<Key>")
jpayne@68 431 bindseq("<Control-Key>")
jpayne@68 432 bindseq("<Alt-Key-a>")
jpayne@68 433 bindseq("<Control-Key-a>")
jpayne@68 434 bindseq("<Alt-Control-Key-a>")
jpayne@68 435 bindseq("<Key-b>")
jpayne@68 436 bindseq("<Control-Button-1>")
jpayne@68 437 bindseq("<Button-2>")
jpayne@68 438 bindseq("<Alt-Button-1>")
jpayne@68 439 bindseq("<FocusOut>")
jpayne@68 440 bindseq("<Enter>")
jpayne@68 441 bindseq("<Leave>")
jpayne@68 442
jpayne@68 443 if __name__ == "__main__":
jpayne@68 444 from unittest import main
jpayne@68 445 main('idlelib.idle_test.test_mainmenu', verbosity=2, exit=False)
jpayne@68 446
jpayne@68 447 from idlelib.idle_test.htest import run
jpayne@68 448 run(_multi_call)