annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/multicall.py @ 69:33d812a61356

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