Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2#@+leo-ver=5-thin 

3#@+node:ekr.20140907103315.18766: * @file ../plugins/qt_events.py 

4#@@first 

5"""Leo's Qt event handling code.""" 

6#@+<< about internal bindings >> 

7#@+node:ekr.20110605121601.18538: ** << about internal bindings >> 

8#@@language rest 

9#@+at 

10# Here are the rules for translating key bindings (in leoSettings.leo) into keys 

11# for k.bindingsDict: 

12# 

13# 1. The case of plain letters is significant: a is not A. 

14# 

15# 2. The Shift- prefix can be applied *only* to letters. Leo will ignore (with a 

16# warning) the shift prefix applied to any other binding, e.g., Ctrl-Shift-( 

17# 

18# 3. The case of letters prefixed by Ctrl-, Alt-, Key- or Shift- is *not* 

19# significant. Thus, the Shift- prefix is required if you want an upper-case 

20# letter (with the exception of 'bare' uppercase letters.) 

21# 

22# The following table illustrates these rules. In each row, the first entry is the 

23# key (for k.bindingsDict) and the other entries are equivalents that the user may 

24# specify in leoSettings.leo: 

25# 

26# a, Key-a, Key-A 

27# A, Shift-A 

28# Alt-a, Alt-A 

29# Alt-A, Alt-Shift-a, Alt-Shift-A 

30# Ctrl-a, Ctrl-A 

31# Ctrl-A, Ctrl-Shift-a, Ctrl-Shift-A 

32# , Key-!,Key-exclam,exclam 

33# 

34# This table is consistent with how Leo already works (because it is consistent 

35# with Tk's key-event specifiers). It is also, I think, the least confusing set of 

36# rules. 

37#@-<< about internal bindings >> 

38from typing import Any, List 

39from leo.core import leoGlobals as g 

40from leo.core import leoGui 

41from leo.core.leoQt import QtCore, QtGui, QtWidgets 

42from leo.core.leoQt import Key, KeyboardModifier, Type 

43#@+others 

44#@+node:ekr.20210512101604.1: ** class LossageData 

45class LossageData: 

46 

47 def __init__(self, actual_ch, binding, ch, keynum, mods, mods2, mods3, text, toString): 

48 

49 self.actual_ch = actual_ch 

50 self.binding = binding 

51 self.ch = ch 

52 self.keynum = keynum 

53 self.mods = mods 

54 self.mods2 = mods2 

55 self.mods3 = mods3 

56 self.stroke = None # Set later. 

57 self.text = text 

58 self.toString = toString 

59 

60 def __repr__(self): 

61 return ( 

62 f"keynum: {self.keynum:>7x} " 

63 f"binding: {self.binding}" 

64 ) 

65 # f"ch: {self.ch:>7s} " 

66 # f"= {self.actual_ch!r}" 

67 # f"mods: {self.mods}, {self.mods2}, {self.mods3}\n" 

68 # f"stroke: {self.stroke!r}\n" 

69 # f"text: {self.text!r}\n" 

70 # f"toString: {self.toString!r}\n" 

71 

72 __str__ = __repr__ 

73#@+node:ekr.20141028061518.17: ** class LeoQtEventFilter 

74class LeoQtEventFilter(QtCore.QObject): # type:ignore 

75 #@+others 

76 #@+node:ekr.20110605121601.18539: *3* filter.ctor 

77 def __init__(self, c, w, tag=''): 

78 """Ctor for LeoQtEventFilter class.""" 

79 super().__init__() 

80 self.c = c 

81 self.w = w # A leoQtX object, *not* a Qt object. 

82 self.tag = tag 

83 # Debugging. 

84 self.keyIsActive = False 

85 # Pretend there is a binding for these characters. 

86 close_flashers = c.config.getString('close-flash-brackets') or '' 

87 open_flashers = c.config.getString('open-flash-brackets') or '' 

88 self.flashers = open_flashers + close_flashers 

89 # #1563: Support alternate keyboards. 

90 self.keyboard_kind = c.config.getString('keyboard-kind') or 'default-keyboard' 

91 # Support for ctagscompleter.py plugin. 

92 self.ctagscompleter_active = False 

93 self.ctagscompleter_onKey = None 

94 #@+node:ekr.20110605121601.18540: *3* filter.eventFilter & helpers 

95 def eventFilter(self, obj, event): 

96 """Return False if Qt should handle the event.""" 

97 c, k = self.c, self.c.k 

98 # 

99 # Handle non-key events first. 

100 if not g.app: 

101 return False # For unit tests, but g.unitTesting may be False! 

102 if not self.c.p: 

103 return False # Startup. 

104 # 

105 # Trace events. 

106 if 'events' in g.app.debug: 

107 if isinstance(event, QtGui.QKeyEvent): 

108 self.traceKeys(obj, event) 

109 else: 

110 self.traceEvent(obj, event) 

111 self.traceWidget(event) 

112 # 

113 # Let Qt handle the non-key events. 

114 if self.doNonKeyEvent(event, obj): 

115 return False 

116 # 

117 # Ignore incomplete key events. 

118 if self.shouldIgnoreKeyEvent(event, obj): 

119 return False 

120 # 

121 # Generate a g.KeyStroke for k.masterKeyHandler. 

122 try: 

123 binding, ch, lossage = self.toBinding(event) 

124 if not binding: 

125 return False # Not the correct event type. 

126 # 

127 # Pass the KeyStroke to masterKeyHandler. 

128 key_event = self.createKeyEvent(event, c, self.w, ch, binding) 

129 # 

130 # #1933: Update the g.app.lossage 

131 if len(g.app.lossage) > 99: 

132 g.app.lossage.pop() 

133 lossage.stroke = key_event.stroke 

134 g.app.lossage.insert(0, lossage) 

135 # 

136 # Call masterKeyHandler! 

137 k.masterKeyHandler(key_event) 

138 c.outerUpdate() 

139 except Exception: 

140 g.es_exception() 

141 return True 

142 # Whatever happens, suppress all other Qt key handling. 

143 #@+node:ekr.20110605195119.16937: *4* filter.createKeyEvent 

144 def createKeyEvent(self, event, c, w, ch, binding): 

145 

146 return leoGui.LeoKeyEvent( 

147 c=self.c, 

148 char=ch, 

149 # char = None doesn't work at present. 

150 # But really, the binding should suffice. 

151 event=event, 

152 binding=binding, 

153 w=w, 

154 x=getattr(event, 'x', None) or 0, 

155 y=getattr(event, 'y', None) or 0, 

156 x_root=getattr(event, 'x_root', None) or 0, 

157 y_root=getattr(event, 'y_root', None) or 0, 

158 ) 

159 #@+node:ekr.20180413180751.2: *4* filter.doNonKeyEvent 

160 def doNonKeyEvent(self, event, obj): 

161 """Handle all non-key event. """ 

162 c = self.c 

163 eventType = event.type() 

164 if eventType == Type.WindowActivate: 

165 g.app.gui.onActivateEvent(event, c, obj, self.tag) 

166 elif eventType == Type.WindowDeactivate: 

167 g.app.gui.onDeactivateEvent(event, c, obj, self.tag) 

168 elif eventType == Type.FocusIn: 

169 if self.tag == 'body': 

170 c.frame.body.onFocusIn(obj) 

171 if c.frame and c.frame.top and obj is c.frame.top.lineEdit: 

172 if c.k.getStateKind() == 'getArg': 

173 c.frame.top.lineEdit.restore_selection() 

174 elif eventType == Type.FocusOut and self.tag == 'body': 

175 c.frame.body.onFocusOut(obj) 

176 return eventType not in (Type.ShortcutOverride, Type.KeyPress, Type.KeyRelease) 

177 # Return True unless we have a key event. 

178 #@+node:ekr.20180413180751.3: *4* filter.shouldIgnoreKeyEvent 

179 def shouldIgnoreKeyEvent(self, event, obj): 

180 """ 

181 Return True if we should ignore the key event. 

182 

183 Alas, QLineEdit *only* generates ev.KeyRelease on Windows, Ubuntu, 

184 so the following hack is required. 

185 """ 

186 c = self.c 

187 t = event.type() 

188 isEditWidget = (obj == c.frame.tree.edit_widget(c.p)) 

189 if isEditWidget: 

190 return t != Type.KeyRelease 

191 # QLineEdit: ignore all key events except keyRelease events. 

192 if t == Type.KeyPress: 

193 return False # Never ignore KeyPress events. 

194 # This doesn't work. Two shortcut-override events are generated! 

195 # if t == ev.ShortcutOverride and event.text(): 

196 # return False # Don't ignore shortcut overrides with a real value. 

197 return True # Ignore everything else. 

198 #@+node:ekr.20110605121601.18543: *4* filter.toBinding & helpers 

199 def toBinding(self, event): 

200 """ 

201 Return (binding, actual_ch): 

202 

203 binding: A user binding, to create g.KeyStroke. 

204 Spelling no longer fragile. 

205 actual_ch: The insertable key, or ''. 

206 """ 

207 mods = self.qtMods(event) 

208 keynum, text, toString, ch = self.qtKey(event) 

209 actual_ch = text or toString 

210 # 

211 # Never allow empty chars, or chars in g.app.gui.ignoreChars 

212 if toString in g.app.gui.ignoreChars: 

213 return None, None, None 

214 ch = ch or toString or '' 

215 if not ch: 

216 return None, None, None 

217 # 

218 # Check for AltGr and Alt+Ctrl keys *before* creating a binding. 

219 actual_ch, ch, mods2 = self.doMacTweaks(actual_ch, ch, mods) 

220 mods3 = self.doAltTweaks(actual_ch, keynum, mods2, toString) 

221 # 

222 # Use *ch* in the binding. 

223 # Clearer w/o f-strings. 

224 binding = '%s%s' % (''.join([f"{z}+" for z in mods3]), ch) 

225 # 

226 # Return the tweaked *actual* char. 

227 binding, actual_ch = self.doLateTweaks(binding, actual_ch) 

228 # 

229 # #1933: Create lossage data. 

230 lossage = LossageData( 

231 actual_ch, binding, ch, keynum, mods, mods2, mods3, text, toString) 

232 return binding, actual_ch, lossage 

233 #@+node:ekr.20180419154543.1: *5* filter.doAltTweaks 

234 def doAltTweaks(self, actual_ch, keynum, mods, toString): 

235 """Turn AltGr and some Alt-Ctrl keys into plain keys.""" 

236 

237 def removeAltCtrl(mods): 

238 for mod in ('Alt', 'Control'): 

239 if mod in mods: 

240 mods.remove(mod) 

241 return mods 

242 

243 # 

244 # Remove Alt, Ctrl for AltGr keys. 

245 # See https://en.wikipedia.org/wiki/AltGr_key 

246 

247 if keynum == Key.Key_AltGr: 

248 return removeAltCtrl(mods) 

249 # 

250 # Never alter complex characters. 

251 if len(actual_ch) != 1: 

252 return mods 

253 # 

254 # #1563: A hack for German and Spanish keyboards: 

255 # Remove *plain* Shift modifier for colon and semicolon. 

256 # https://en.m.wikipedia.org/wiki/German_keyboard_layout 

257 kind = self.keyboard_kind.lower() 

258 if (kind in ('german', 'spanish') 

259 and actual_ch in ":;" 

260 and 'Shift' in mods 

261 and 'Alt' not in mods and 'Control' not in mods 

262 ): 

263 mods.remove('Shift') 

264 elif kind == 'us-international': 

265 pass # To do. 

266 # 

267 # Handle Alt-Ctrl modifiers for chars whose that are not ascii. 

268 # Testing: Alt-Ctrl-E is '€'. 

269 if ord(actual_ch) > 127 and 'Alt' in mods and 'Control' in mods: 

270 return removeAltCtrl(mods) 

271 return mods 

272 #@+node:ekr.20180417161548.1: *5* filter.doLateTweaks 

273 def doLateTweaks(self, binding, ch): 

274 """Make final tweaks. g.KeyStroke does other tweaks later.""" 

275 # 

276 # These are needed because ch is separate from binding. 

277 if ch == '\r': 

278 ch = '\n' 

279 if binding == 'Escape': 

280 ch = 'Escape' 

281 # 

282 # Adjust the case of the binding string (for the minibuffer). 

283 if len(ch) == 1 and len(binding) == 1 and ch.isalpha() and binding.isalpha(): 

284 if ch != binding: 

285 binding = ch 

286 return binding, ch 

287 #@+node:ekr.20180419160958.1: *5* filter.doMacTweaks 

288 def doMacTweaks(self, actual_ch, ch, mods): 

289 """Replace MacOS Alt characters.""" 

290 if not g.isMac: 

291 return actual_ch, ch, mods 

292 if ch == 'Backspace': 

293 # On the Mac, the reported char can be DEL (7F) 

294 return '\b', ch, mods 

295 if len(mods) == 1 and mods[0] == 'Alt': 

296 # Patch provided by resi147. 

297 # See the thread: special characters in MacOSX, like '@'. 

298 mac_d = { 

299 '/': '\\', 

300 '5': '[', 

301 '6': ']', 

302 '7': '|', 

303 '8': '{', 

304 '9': '}', 

305 'e': '€', 

306 'l': '@', 

307 } 

308 if ch.lower() in mac_d: 

309 # Ignore the case. 

310 actual_ch = ch = g.checkUnicode(mac_d.get(ch.lower())) 

311 mods = [] 

312 return actual_ch, ch, mods 

313 #@+node:ekr.20110605121601.18544: *5* filter.qtKey 

314 def qtKey(self, event): 

315 """ 

316 Return the components of a Qt key event. 

317 

318 Modifiers are handled separately. 

319 

320 Return (keynum, text, toString, ch). 

321 

322 keynum: event.key() 

323 ch: chr(keynum) or '' if there is an exception. 

324 toString: 

325 For special keys: made-up spelling that become part of the setting. 

326 For all others: QtGui.QKeySequence(keynum).toString() 

327 text: event.text() 

328 """ 

329 text, toString, ch = '', '', '' # Defaults. 

330 # 

331 # Leo 6.4: Test keynum's directly. 

332 # The values are the same in Qt4, Qt5, Qt6. 

333 keynum = event.key() 

334 if keynum in ( 

335 0x01000020, # Key_Shift 

336 0x01000021, # Key_Control 

337 0x01000022, # Key_Meta 

338 0x01000023, # Key_Alt 

339 0x01001103, # Key_AltGr 

340 0x01000024, # Key_CapsLock 

341 ): 

342 # Disallow bare modifiers. 

343 return keynum, text, toString, ch 

344 # 

345 # Compute toString and ch. 

346 text = event.text() # This is the unicode character! 

347 toString = QtGui.QKeySequence(keynum).toString() 

348 # 

349 # #1244461: Numpad 'Enter' key does not work in minibuffer 

350 if toString == 'Enter': 

351 toString = 'Return' 

352 if toString == 'Esc': 

353 toString = 'Escape' 

354 try: 

355 ch = chr(keynum) 

356 except ValueError: 

357 pass 

358 return keynum, text, toString, ch 

359 #@+node:ekr.20120204061120.10084: *5* filter.qtMods 

360 def qtMods(self, event): 

361 """Return the text version of the modifiers of the key event.""" 

362 modifiers = event.modifiers() 

363 mod_table = ( 

364 (KeyboardModifier.AltModifier, 'Alt'), 

365 (KeyboardModifier.ControlModifier, 'Control'), 

366 (KeyboardModifier.MetaModifier, 'Meta'), 

367 (KeyboardModifier.ShiftModifier, 'Shift'), 

368 (KeyboardModifier.KeypadModifier, 'KeyPad'), 

369 # #1448: Replacing this by 'Key' would make separate keypad bindings impossible. 

370 ) 

371 # pylint: disable=superfluous-parens. 

372 mods = [b for a, b in mod_table if (modifiers & a)] 

373 return mods 

374 #@+node:ekr.20140907103315.18767: *3* filter.Tracing 

375 #@+node:ekr.20190922075339.1: *4* filter.traceKeys 

376 def traceKeys(self, obj, event): 

377 if g.unitTesting: 

378 return 

379 e = QtCore.QEvent 

380 key_events = { 

381 e.KeyPress: 'key-press', # 6 

382 e.KeyRelease: 'key-release', # 7 

383 e.Shortcut: 'shortcut', # 117 

384 e.ShortcutOverride: 'shortcut-override', # 51 

385 } 

386 kind = key_events.get(event.type()) 

387 if kind: 

388 mods = ','.join(self.qtMods(event)) 

389 g.trace(f"{kind:>20}: {mods:>7} {event.text()!r}") 

390 #@+node:ekr.20110605121601.18548: *4* filter.traceEvent 

391 def traceEvent(self, obj, event): 

392 if g.unitTesting: 

393 return 

394 # http://qt-project.org/doc/qt-4.8/qevent.html#properties 

395 exclude_names = ('tree', 'log', 'body', 'minibuffer') 

396 traceActivate = True 

397 traceFocus = False 

398 traceHide = False 

399 traceHover = False 

400 traceKey = False 

401 traceLayout = False 

402 traceMouse = False 

403 tracePaint = False 

404 traceUpdate = False 

405 c, e = self.c, QtCore.QEvent 

406 eventType = event.type() 

407 # http://doc.qt.io/qt-5/qevent.html 

408 show: List[Any] = [] 

409 ignore = [ 

410 e.MetaCall, # 43 

411 e.Timer, # 1 

412 e.ToolTip, # 110 

413 ] 

414 activate_events = ( 

415 (e.Close, 'close'), # 19 

416 (e.WindowActivate, 'window-activate'), # 24 

417 (e.WindowBlocked, 'window-blocked'), # 103 

418 (e.WindowUnblocked, 'window-unblocked'), # 104 

419 (e.WindowDeactivate, 'window-deactivate'), # 25 

420 ) 

421 focus_events = [ 

422 (e.Enter, 'enter'), # 10 

423 (e.Leave, 'leave'), # 11 

424 (e.FocusIn, 'focus-in'), # 8 

425 (e.FocusOut, 'focus-out'), # 9 

426 (e.ShowToParent, 'show-to-parent'), # 26 

427 ] 

428 if hasattr(e, 'FocusAboutToChange'): 

429 # pylint: disable=no-member 

430 focus_events.extend([ 

431 (e.FocusAboutToChange, 'focus-about-to-change'), # 23 

432 ]) 

433 hide_events = ( 

434 (e.Hide, 'hide'), # 18 

435 (e.HideToParent, 'hide-to-parent'), # 27 

436 # (e.LeaveEditFocus,'leave-edit-focus'), # 151 

437 (e.Show, 'show'), # 17 

438 ) 

439 hover_events = ( 

440 (e.HoverEnter, 'hover-enter'), # 127 

441 (e.HoverLeave, 'hover-leave'), # 128 

442 (e.HoverMove, 'hover-move'), # 129 

443 ) 

444 key_events = [ 

445 (e.KeyPress, 'key-press'), # 6 

446 (e.KeyRelease, 'key-release'), # 7 

447 (e.Shortcut, 'shortcut'), # 117 

448 (e.ShortcutOverride, 'shortcut-override'), # 51 

449 ] 

450 if hasattr(e, 'InputMethodQuery'): 

451 # pylint: disable=no-member 

452 key_events.extend([ 

453 (e.InputMethodQuery, 'input-method-query'), # 207 

454 ]) 

455 layout_events = [ 

456 (e.ChildAdded, 'child-added'), # 68 

457 (e.ChildRemoved, 'child-removed'), # 71 

458 (e.DynamicPropertyChange, 'dynamic-property-change'), # 170 

459 (e.FontChange, 'font-change'), # 97 

460 (e.LayoutRequest, 'layout-request'), # 76 

461 (e.Move, 'move'), # 13 widget's position changed. 

462 (e.Resize, 'resize'), # 14 

463 (e.StyleChange, 'style-change'), # 100 

464 (e.ZOrderChange, 'z-order-change'), # 126 

465 ] 

466 if hasattr(e, 'CloseSoftwareInputPanel'): 

467 layout_events.extend([ 

468 (e.CloseSoftwareInputPanel, 'close-sip'), # 200 

469 ]) 

470 mouse_events = ( 

471 (e.MouseMove, 'mouse-move'), # 155 

472 (e.MouseButtonPress, 'mouse-press'), # 2 

473 (e.MouseButtonRelease, 'mouse-release'), # 3 

474 (e.Wheel, 'mouse-wheel'), # 31 

475 ) 

476 paint_events = [ 

477 (e.ChildPolished, 'child-polished'), # 69 

478 (e.PaletteChange, 'palette-change'), # 39 

479 (e.ParentChange, 'parent-change'), # 21 

480 (e.Paint, 'paint'), # 12 

481 (e.Polish, 'polish'), # 75 

482 (e.PolishRequest, 'polish-request'), # 74 

483 ] 

484 if hasattr(e, 'RequestSoftwareInputPanel'): 

485 paint_events.extend([ 

486 (e.RequestSoftwareInputPanel, 'sip'), # 199 

487 ]) 

488 update_events = ( 

489 (e.UpdateLater, 'update-later'), # 78 

490 (e.UpdateRequest, 'update'), # 77 

491 ) 

492 option_table = ( 

493 (traceActivate, activate_events), 

494 (traceFocus, focus_events), 

495 (traceHide, hide_events), 

496 (traceHover, hover_events), 

497 (traceKey, key_events), 

498 (traceLayout, layout_events), 

499 (traceMouse, mouse_events), 

500 (tracePaint, paint_events), 

501 (traceUpdate, update_events), 

502 ) 

503 for option, table in option_table: 

504 if option: 

505 show.extend(table) 

506 else: 

507 for n, tag in table: 

508 ignore.append(n) 

509 for val, kind in show: 

510 if self.tag in exclude_names: 

511 return 

512 if eventType == val: 

513 tag = ( 

514 obj.objectName() if hasattr(obj, 'objectName') 

515 else f"id: {id(obj)}, {obj.__class__.__name__}" 

516 ) 

517 if traceKey: 

518 g.trace( 

519 f"{kind:-25} {self.tag:-25} " 

520 f"in-state: {repr(c.k and c.k.inState()):5} obj: {tag}") 

521 return 

522 if eventType not in ignore: 

523 tag = ( 

524 obj.objectName() if hasattr(obj, 'objectName') 

525 else f"id: {id(obj)}, {obj.__class__.__name__}" 

526 ) 

527 g.trace(f"{eventType:-25} {self.tag:-25} {tag}") 

528 #@+node:ekr.20131121050226.16331: *4* filter.traceWidget 

529 def traceWidget(self, event): 

530 """Show unexpected events in unusual widgets.""" 

531 verbose = False 

532 # Not good for --trace-events 

533 e = QtCore.QEvent 

534 assert isinstance(event, QtCore.QEvent) 

535 et = event.type() 

536 # http://qt-project.org/doc/qt-4.8/qevent.html#properties 

537 ignore_d = { 

538 e.ChildAdded: 'child-added', # 68 

539 e.ChildPolished: 'child-polished', # 69 

540 e.ChildRemoved: 'child-removed', # 71 

541 e.Close: 'close', # 19 

542 e.CloseSoftwareInputPanel: 'close-software-input-panel', # 200 

543 178: 'contents-rect-change', # 178 

544 # e.DeferredDelete:'deferred-delete', # 52 (let's trace this) 

545 e.DynamicPropertyChange: 'dynamic-property-change', # 170 

546 e.FocusOut: 'focus-out', # 9 (We don't care if we are leaving an unknown widget) 

547 e.FontChange: 'font-change', # 97 

548 e.Hide: 'hide', # 18 

549 e.HideToParent: 'hide-to-parent', # 27 

550 e.HoverEnter: 'hover-enter', # 127 

551 e.HoverLeave: 'hover-leave', # 128 

552 e.HoverMove: 'hover-move', # 129 

553 e.KeyPress: 'key-press', # 6 

554 e.KeyRelease: 'key-release', # 7 

555 e.LayoutRequest: 'layout-request', # 76 

556 e.Leave: 'leave', # 11 (We don't care if we are leaving an unknown widget) 

557 # e.LeaveEditFocus:'leave-edit-focus', # 151 

558 e.MetaCall: 'meta-call', # 43 

559 e.Move: 'move', # 13 widget's position changed. 

560 e.MouseButtonPress: 'mouse-button-press', # 2 

561 e.MouseButtonRelease: 'mouse-button-release', # 3 

562 e.MouseButtonDblClick: 'mouse-button-double-click', # 4 

563 e.MouseMove: 'mouse-move', # 5 

564 e.MouseTrackingChange: 'mouse-tracking-change', # 105 

565 e.Paint: 'paint', # 12 

566 e.PaletteChange: 'palette-change', # 39 

567 e.ParentChange: 'parent-change', # 21 

568 e.Polish: 'polish', # 75 

569 e.PolishRequest: 'polish-request', # 74 

570 e.RequestSoftwareInputPanel: 'request-software-input-panel', # 199 

571 e.Resize: 'resize', # 14 

572 e.ShortcutOverride: 'shortcut-override', # 51 

573 e.Show: 'show', # 17 

574 e.ShowToParent: 'show-to-parent', # 26 

575 e.StyleChange: 'style-change', # 100 

576 e.StatusTip: 'status-tip', # 112 

577 e.Timer: 'timer', # 1 

578 e.ToolTip: 'tool-tip', # 110 

579 e.WindowBlocked: 'window-blocked', # 103 

580 e.WindowUnblocked: 'window-unblocked', # 104 

581 e.ZOrderChange: 'z-order-change', # 126 

582 } 

583 focus_d = { 

584 e.DeferredDelete: 'deferred-delete', # 52 

585 e.Enter: 'enter', # 10 

586 e.FocusIn: 'focus-in', # 8 

587 e.WindowActivate: 'window-activate', # 24 

588 e.WindowDeactivate: 'window-deactivate', # 25 

589 } 

590 line_edit_ignore_d = { 

591 e.Enter: 'enter', # 10 (mouse over) 

592 e.Leave: 'leave', # 11 (mouse over) 

593 e.FocusOut: 'focus-out', # 9 

594 e.WindowActivate: 'window-activate', # 24 

595 e.WindowDeactivate: 'window-deactivate', # 25 

596 } 

597 none_ignore_d = { 

598 e.Enter: 'enter', # 10 (mouse over) 

599 e.Leave: 'leave', # 11 (mouse over) 

600 e.FocusOut: 'focus-out', # 9 

601 e.WindowActivate: 'window-activate', # 24 

602 } 

603 if et in ignore_d: 

604 return 

605 w = QtWidgets.QApplication.focusWidget() 

606 if verbose: # Too verbose for --trace-events. 

607 for d in (ignore_d, focus_d, line_edit_ignore_d, none_ignore_d): 

608 t = d.get(et) 

609 if t: 

610 break 

611 else: 

612 t = et 

613 g.trace(f"{t:20} {w.__class__}") 

614 return 

615 if w is None: 

616 if et not in none_ignore_d: 

617 t = focus_d.get(et) or et 

618 g.trace(f"None {t}") 

619 if isinstance(w, QtWidgets.QPushButton): 

620 return 

621 if isinstance(w, QtWidgets.QLineEdit): 

622 if et not in line_edit_ignore_d: 

623 t = focus_d.get(et) or et 

624 if hasattr(w, 'objectName'): 

625 tag = w.objectName() 

626 else: 

627 tag = f"id: {id(w)}, {w.__class__.__name__}" 

628 g.trace(f"{t:20} {tag}") 

629 return 

630 t = focus_d.get(et) or et 

631 if hasattr(w, 'objectName'): 

632 tag = w.objectName() 

633 else: 

634 tag = f"id: {id(w)}, {w.__class__.__name__}" 

635 g.trace(f"{t:20} {tag}") 

636 #@-others 

637#@-others 

638#@@language python 

639#@@tabwidth -4 

640#@@pagewidth 70 

641#@-leo