update editor, key handling in webview

keyPressEvent/etc no longer work with qwebengineview, so we need to
install an event filter to catch things like ctrl+c. drag & drop
doesn't seem to be supported until 5.7
This commit is contained in:
Damien Elmes 2016-06-06 17:54:39 +10:00
parent 9abc9fde9f
commit d7339d9a27
3 changed files with 122 additions and 186 deletions

View File

@ -81,7 +81,7 @@ function sendState() {
'sub': document.queryCommandState("subscript"), 'sub': document.queryCommandState("subscript"),
'col': document.queryCommandValue("forecolor") 'col': document.queryCommandValue("forecolor")
}; };
py.run("state:" + JSON.stringify(r)); pycmd("state:" + JSON.stringify(r));
}; };
function setFormat(cmd, arg, nosave) { function setFormat(cmd, arg, nosave) {
@ -100,7 +100,7 @@ function clearChangeTimer() {
function onFocus(elem) { function onFocus(elem) {
currentField = elem; currentField = elem;
py.run("focus:" + currentField.id.substring(1)); pycmd("focus:" + currentField.id.substring(1));
// don't adjust cursor on mouse clicks // don't adjust cursor on mouse clicks
if (mouseDown) { return; } if (mouseDown) { return; }
// do this twice so that there's no flicker on newer versions // do this twice so that there's no flicker on newer versions
@ -156,7 +156,7 @@ function saveField(type) {
return; return;
} }
// type is either 'blur' or 'key' // type is either 'blur' or 'key'
py.run(type + ":" + currentField.innerHTML); pycmd(type + ":" + currentField.innerHTML);
clearChangeTimer(); clearChangeTimer();
}; };
@ -258,7 +258,7 @@ document.onclick = function (evt) {
</script></head><body> </script></head><body>
<div id="fields"></div> <div id="fields"></div>
<div id="dupes"><a href="#" onclick="py.run('dupes');return false;">%s</a></div> <div id="dupes" style="display:none;"><a href="#" onclick="pycmd('dupes');return false;">%s</a></div>
</body></html> </body></html>
""" """
@ -279,14 +279,13 @@ class Editor(object):
self.setupButtons() self.setupButtons()
self.setupWeb() self.setupWeb()
self.setupTags() self.setupTags()
self.setupKeyboard()
# Initial setup # Initial setup
############################################################ ############################################################
def setupOuter(self): def setupOuter(self):
l = QVBoxLayout() l = QVBoxLayout()
l.setMargin(0) l.setContentsMargins(0,0,0,0)
l.setSpacing(0) l.setSpacing(0)
self.widget.setLayout(l) self.widget.setLayout(l)
self.outerLayout = l self.outerLayout = l
@ -294,13 +293,15 @@ class Editor(object):
def setupWeb(self): def setupWeb(self):
self.web = EditorWebView(self.widget, self) self.web = EditorWebView(self.widget, self)
self.web.allowDrops = True self.web.allowDrops = True
self.web.setBridge(self.bridge) self.web.onBridgeCmd = self.onBridgeCmd
self.outerLayout.addWidget(self.web, 1) self.outerLayout.addWidget(self.web, 1)
# pick up the window colour # pick up the window colour - missing on qt5.5
p = self.web.palette() if hasattr(self.web.page(), "setBackgroundColor"):
p.setBrush(QPalette.Base, Qt.transparent) self.web.page().setBackgroundColor(Qt.transparent)
self.web.page().setPalette(p) self.web.onLoadFinished = self._loadFinished
self.web.setAttribute(Qt.WA_OpaquePaintEvent, False) self.web.stdHtml(_html % (
getBase(self.mw.col), anki.js.jquery,
_("Show Duplicates")))
# Top buttons # Top buttons
###################################################################### ######################################################################
@ -309,9 +310,9 @@ class Editor(object):
check=False, native=False, canDisable=True): check=False, native=False, canDisable=True):
b = QPushButton(text) b = QPushButton(text)
if check: if check:
b.connect(b, SIGNAL("clicked(bool)"), func) b.clicked["bool"].connect(func)
else: else:
b.connect(b, SIGNAL("clicked()"), func) b.clicked.connect(func)
if size: if size:
b.setFixedHeight(20) b.setFixedHeight(20)
b.setFixedWidth(20) b.setFixedWidth(20)
@ -348,10 +349,10 @@ class Editor(object):
# icons # icons
self.iconsBox = QHBoxLayout() self.iconsBox = QHBoxLayout()
if not isMac: if not isMac:
self.iconsBox.setMargin(6) self.iconsBox.setContentsMargins(6,6,6,6)
self.iconsBox.setSpacing(0) self.iconsBox.setSpacing(0)
else: else:
self.iconsBox.setMargin(0) self.iconsBox.setContentsMargins(0,0,0,0)
self.iconsBox.setSpacing(14) self.iconsBox.setSpacing(14)
self.outerLayout.addLayout(self.iconsBox) self.outerLayout.addLayout(self.iconsBox)
b = self._addButton b = self._addButton
@ -386,24 +387,19 @@ class Editor(object):
_("Cloze deletion (Ctrl+Shift+C)"), text="[...]") _("Cloze deletion (Ctrl+Shift+C)"), text="[...]")
but.setFixedWidth(24) but.setFixedWidth(24)
s = self.clozeShortcut2 = QShortcut( s = self.clozeShortcut2 = QShortcut(
QKeySequence(_("Ctrl+Alt+Shift+C")), self.parentWindow) QKeySequence(_("Ctrl+Alt+Shift+C")), self.parentWindow,
s.connect(s, SIGNAL("activated()"), self.onCloze) activated=self.onCloze)
# fixme: better image names # fixme: better image names
b("mail-attachment", self.onAddMedia, _("F3"), b("mail-attachment", self.onAddMedia, _("F3"),
_("Attach pictures/audio/video (F3)")) _("Attach pictures/audio/video (F3)"))
b("media-record", self.onRecSound, _("F5"), _("Record audio (F5)")) b("media-record", self.onRecSound, _("F5"), _("Record audio (F5)"))
b("adv", self.onAdvanced, text=downArrow()) b("adv", self.onAdvanced, text=downArrow())
s = QShortcut(QKeySequence("Ctrl+T, T"), self.widget) s = QShortcut(QKeySequence("Ctrl+T, T"), self.widget, activated=self.insertLatex)
s.connect(s, SIGNAL("activated()"), self.insertLatex) s = QShortcut(QKeySequence("Ctrl+T, E"), self.widget, activated=self.insertLatexEqn)
s = QShortcut(QKeySequence("Ctrl+T, E"), self.widget) s = QShortcut(QKeySequence("Ctrl+T, M"), self.widget, activated=self.insertLatexMathEnv)
s.connect(s, SIGNAL("activated()"), self.insertLatexEqn) s = QShortcut(QKeySequence("Ctrl+Shift+X"), self.widget, activated=self.onHtmlEdit)
s = QShortcut(QKeySequence("Ctrl+T, M"), self.widget)
s.connect(s, SIGNAL("activated()"), self.insertLatexMathEnv)
s = QShortcut(QKeySequence("Ctrl+Shift+X"), self.widget)
s.connect(s, SIGNAL("activated()"), self.onHtmlEdit)
# tags # tags
s = QShortcut(QKeySequence("Ctrl+Shift+T"), self.widget) s = QShortcut(QKeySequence("Ctrl+Shift+T"), self.widget, activated=lambda: self.tags.setFocus())
s.connect(s, SIGNAL("activated()"), lambda: self.tags.setFocus())
runHook("setupEditorButtons", self) runHook("setupEditorButtons", self)
def enableButtons(self, val=True): def enableButtons(self, val=True):
@ -432,20 +428,20 @@ class Editor(object):
parent=self.parentWindow parent=self.parentWindow
CardLayout(self.mw, self.note, ord=ord, parent=parent, CardLayout(self.mw, self.note, ord=ord, parent=parent,
addMode=self.addMode) addMode=self.addMode)
self.loadNote()
if isWin: if isWin:
self.parentWindow.activateWindow() self.parentWindow.activateWindow()
# JS->Python bridge # JS->Python bridge
###################################################################### ######################################################################
def bridge(self, str): def onBridgeCmd(self, cmd):
if not self.note or not runHook: if not self.note or not runHook:
# shutdown # shutdown
return return
# focus lost or key/button pressed? # focus lost or key/button pressed?
if str.startswith("blur") or str.startswith("key"): if cmd.startswith("blur") or cmd.startswith("key"):
(type, txt) = str.split(":", 1) (type, txt) = cmd.split(":", 1)
txt = urllib.parse.unquote(txt)
txt = self.mungeHTML(txt) txt = self.mungeHTML(txt)
# misbehaving apps may include a null byte in the text # misbehaving apps may include a null byte in the text
txt = txt.replace("\x00", "") txt = txt.replace("\x00", "")
@ -474,24 +470,24 @@ class Editor(object):
runHook("editTimer", self.note) runHook("editTimer", self.note)
self.checkValid() self.checkValid()
# focused into field? # focused into field?
elif str.startswith("focus"): elif cmd.startswith("focus"):
(type, num) = str.split(":", 1) (type, num) = cmd.split(":", 1)
self.enableButtons() self.enableButtons()
self.currentField = int(num) self.currentField = int(num)
runHook("editFocusGained", self.note, self.currentField) runHook("editFocusGained", self.note, self.currentField)
# state buttons changed? # state buttons changed?
elif str.startswith("state"): elif cmd.startswith("state"):
(cmd, txt) = str.split(":", 1) (cmd, txt) = cmd.split(":", 1)
r = json.loads(txt) r = json.loads(txt)
self._buttons['text_bold'].setChecked(r['bold']) self._buttons['text_bold'].setChecked(r['bold'])
self._buttons['text_italic'].setChecked(r['italic']) self._buttons['text_italic'].setChecked(r['italic'])
self._buttons['text_under'].setChecked(r['under']) self._buttons['text_under'].setChecked(r['under'])
self._buttons['text_super'].setChecked(r['super']) self._buttons['text_super'].setChecked(r['super'])
self._buttons['text_sub'].setChecked(r['sub']) self._buttons['text_sub'].setChecked(r['sub'])
elif str.startswith("dupes"): elif cmd.startswith("dupes"):
self.showDupes() self.showDupes()
else: else:
print(str) print(cmd)
def mungeHTML(self, txt): def mungeHTML(self, txt):
if txt == "<br>": if txt == "<br>":
@ -501,7 +497,7 @@ class Editor(object):
# Setting/unsetting the current note # Setting/unsetting the current note
###################################################################### ######################################################################
def _loadFinished(self, w): def _loadFinished(self):
self._loaded = True self._loaded = True
if self.note: if self.note:
self.loadNote() self.loadNote()
@ -513,13 +509,8 @@ class Editor(object):
self.disableButtons() self.disableButtons()
if focus: if focus:
self.stealFocus = True self.stealFocus = True
# change timer
if self.note: if self.note:
self.web.setHtml(_html % ( self.loadNote()
getBase(self.mw.col), anki.js.jquery,
_("Show Duplicates")), loadCB=self._loadFinished)
self.updateTags()
self.updateKeyboard()
else: else:
self.hideCompleters() self.hideCompleters()
if hide: if hide:
@ -543,11 +534,13 @@ class Editor(object):
self.web.eval("setFonts(%s);" % ( self.web.eval("setFonts(%s);" % (
json.dumps(self.fonts()))) json.dumps(self.fonts())))
self.checkValid() self.checkValid()
self.updateTags()
self.widget.show() self.widget.show()
if self.stealFocus: if self.stealFocus:
self.web.setFocus() self.web.setFocus()
self.stealFocus = False self.stealFocus = False
def focus(self): def focus(self):
self.web.setFocus() self.web.setFocus()
@ -560,9 +553,6 @@ class Editor(object):
if not self.note: if not self.note:
return return
self.saveTags() self.saveTags()
if self.mw.app.focusWidget() != self.web:
# if no fields are focused, there's nothing to save
return
# move focus out of fields and save tags # move focus out of fields and save tags
self.parentWindow.setFocus() self.parentWindow.setFocus()
# and process events so any focus-lost hooks fire # and process events so any focus-lost hooks fire
@ -606,8 +596,7 @@ class Editor(object):
d = QDialog(self.widget) d = QDialog(self.widget)
form = aqt.forms.edithtml.Ui_Dialog() form = aqt.forms.edithtml.Ui_Dialog()
form.setupUi(d) form.setupUi(d)
d.connect(form.buttonBox, SIGNAL("helpRequested()"), form.buttonBox.helpRequested.connect(lambda: openHelp("editor"))
lambda: openHelp("editor"))
form.textEdit.setPlainText(self.note.fields[self.currentField]) form.textEdit.setPlainText(self.note.fields[self.currentField])
form.textEdit.moveCursor(QTextCursor.End) form.textEdit.moveCursor(QTextCursor.End)
d.exec_() d.exec_()
@ -630,13 +619,12 @@ class Editor(object):
g.setFlat(True) g.setFlat(True)
tb = QGridLayout() tb = QGridLayout()
tb.setSpacing(12) tb.setSpacing(12)
tb.setMargin(6) tb.setContentsMargins(6,6,6,6)
# tags # tags
l = QLabel(_("Tags")) l = QLabel(_("Tags"))
tb.addWidget(l, 1, 0) tb.addWidget(l, 1, 0)
self.tags = aqt.tagedit.TagEdit(self.widget) self.tags = aqt.tagedit.TagEdit(self.widget)
self.tags.connect(self.tags, SIGNAL("lostFocus"), self.tags.lostFocus.connect(self.saveTags)
self.saveTags)
self.tags.setToolTip(shortcut(_("Jump to tags with Ctrl+Shift+T"))) self.tags.setToolTip(shortcut(_("Jump to tags with Ctrl+Shift+T")))
tb.addWidget(self.tags, 1, 1) tb.addWidget(self.tags, 1, 1)
g.setLayout(tb) g.setLayout(tb)
@ -724,7 +712,7 @@ to a cloze type first, via Edit>Change Note Type."""))
self.onColourChanged() self.onColourChanged()
hbox = QHBoxLayout() hbox = QHBoxLayout()
hbox.addWidget(self.foregroundFrame) hbox.addWidget(self.foregroundFrame)
hbox.setMargin(5) hbox.setContentsMargins(5,5,5,5)
but.setLayout(hbox) but.setLayout(hbox)
# use last colour # use last colour
@ -912,7 +900,7 @@ to a cloze type first, via Edit>Change Note Type."""))
# from missing media # from missing media
pass pass
# strip all other attributes, including implicit max-width # strip all other attributes, including implicit max-width
for attr, val in tag.attrs: for attr, val in tag.attrs.items():
if attr != "src": if attr != "src":
del tag[attr] del tag[attr]
# strip superfluous elements # strip superfluous elements
@ -928,17 +916,13 @@ to a cloze type first, via Edit>Change Note Type."""))
def onAdvanced(self): def onAdvanced(self):
m = QMenu(self.mw) m = QMenu(self.mw)
a = m.addAction(_("LaTeX")) a = m.addAction(_("LaTeX"))
a.setShortcut(QKeySequence("Ctrl+T, T")) a.triggered.connect(self.insertLatex)
a.connect(a, SIGNAL("triggered()"), self.insertLatex)
a = m.addAction(_("LaTeX equation")) a = m.addAction(_("LaTeX equation"))
a.setShortcut(QKeySequence("Ctrl+T, E")) a.triggered.connect(self.insertLatexEqn)
a.connect(a, SIGNAL("triggered()"), self.insertLatexEqn)
a = m.addAction(_("LaTeX math env.")) a = m.addAction(_("LaTeX math env."))
a.setShortcut(QKeySequence("Ctrl+T, M")) a.triggered.connect(self.insertLatexMathEnv)
a.connect(a, SIGNAL("triggered()"), self.insertLatexMathEnv)
a = m.addAction(_("Edit HTML")) a = m.addAction(_("Edit HTML"))
a.setShortcut(QKeySequence("Ctrl+Shift+X")) a.triggered.connect(self.onHtmlEdit)
a.connect(a, SIGNAL("triggered()"), self.onHtmlEdit)
m.exec_(QCursor.pos()) m.exec_(QCursor.pos())
# LaTeX # LaTeX
@ -953,118 +937,65 @@ to a cloze type first, via Edit>Change Note Type."""))
def insertLatexMathEnv(self): def insertLatexMathEnv(self):
self.web.eval("wrap('[$$]', '[/$$]');") self.web.eval("wrap('[$$]', '[/$$]');")
# Keyboard layout
######################################################################
def setupKeyboard(self):
if isWin and self.mw.pm.profile['preserveKeyboard']:
a = ctypes.windll.user32.ActivateKeyboardLayout
a.restype = ctypes.c_void_p
a.argtypes = [ctypes.c_void_p, ctypes.c_uint]
g = ctypes.windll.user32.GetKeyboardLayout
g.restype = ctypes.c_void_p
g.argtypes = [ctypes.c_uint]
else:
a = g = None
self.activateKeyboard = a
self.getKeyboard = g
def updateKeyboard(self):
self.keyboardLayouts = {}
def saveKeyboard(self):
if not self.getKeyboard:
return
self.keyboardLayouts[self.currentField] = self.getKeyboard(0)
def restoreKeyboard(self):
if not self.getKeyboard:
return
if self.currentField in self.keyboardLayouts:
self.activateKeyboard(self.keyboardLayouts[self.currentField], 0)
# Pasting, drag & drop, and keyboard layouts # Pasting, drag & drop, and keyboard layouts
###################################################################### ######################################################################
# fixme: drag & drop
# fixme: middle click to paste
class EditorWebView(AnkiWebView): class EditorWebView(AnkiWebView):
def __init__(self, parent, editor): def __init__(self, parent, editor):
AnkiWebView.__init__(self) AnkiWebView.__init__(self)
self.editor = editor self.editor = editor
self.strip = self.editor.mw.pm.profile['stripHTML'] self.strip = self.editor.mw.pm.profile['stripHTML']
self.setAcceptDrops(True)
def keyPressEvent(self, evt):
if evt.matches(QKeySequence.Paste):
self.onPaste()
return evt.accept()
elif evt.matches(QKeySequence.Copy):
self.onCopy()
return evt.accept()
elif evt.matches(QKeySequence.Cut):
self.onCut()
return evt.accept()
QWebView.keyPressEvent(self, evt)
def onCut(self): def onCut(self):
self.triggerPageAction(QWebPage.Cut) self.triggerPageAction(QWebEnginePage.Cut)
self._flagAnkiText() self._flagAnkiText()
def onCopy(self): def onCopy(self):
self.triggerPageAction(QWebPage.Copy) self.triggerPageAction(QWebEnginePage.Copy)
self._flagAnkiText() self._flagAnkiText()
def onPaste(self): def onPaste(self):
mime = self.mungeClip() mime = self.mungeClip()
self.triggerPageAction(QWebPage.Paste) self.triggerPageAction(QWebEnginePage.Paste)
self.restoreClip() self.restoreClip()
def mouseReleaseEvent(self, evt): # def mouseReleaseEvent(self, evt):
if not isMac and not isWin and evt.button() == Qt.MidButton: # if not isMac and not isWin and evt.button() == Qt.MidButton:
# middle click on x11; munge the clipboard before standard # # middle click on x11; munge the clipboard before standard
# handling # # handling
mime = self.mungeClip(mode=QClipboard.Selection) # mime = self.mungeClip(mode=QClipboard.Selection)
AnkiWebView.mouseReleaseEvent(self, evt) # AnkiWebView.mouseReleaseEvent(self, evt)
self.restoreClip(mode=QClipboard.Selection) # self.restoreClip(mode=QClipboard.Selection)
else: # else:
AnkiWebView.mouseReleaseEvent(self, evt) # AnkiWebView.mouseReleaseEvent(self, evt)
#
def focusInEvent(self, evt): # def dropEvent(self, evt):
window = False # oldmime = evt.mimeData()
if evt.reason() in (Qt.ActiveWindowFocusReason, Qt.PopupFocusReason): # # coming from this program?
# editor area got focus again; need to tell js not to adjust cursor # if evt.source():
self.eval("mouseDown++;") # if oldmime.hasHtml():
window = True # mime = QMimeData()
AnkiWebView.focusInEvent(self, evt) # mime.setHtml(self.editor._filterHTML(oldmime.html()))
if evt.reason() == Qt.TabFocusReason: # else:
self.eval("focusField(0);") # # old qt on linux won't give us html when dragging an image;
elif evt.reason() == Qt.BacktabFocusReason: # # in that case just do the default action (which is to ignore
n = len(self.editor.note.fields) - 1 # # the drag)
self.eval("focusField(%d);" % n) # return AnkiWebView.dropEvent(self, evt)
elif window: # else:
self.eval("mouseDown--;") # mime = self._processMime(oldmime)
# # create a new event with the new mime data and run it
def dropEvent(self, evt): # new = QDropEvent(evt.pos(), evt.possibleActions(), mime,
oldmime = evt.mimeData() # evt.mouseButtons(), evt.keyboardModifiers())
# coming from this program? # evt.accept()
if evt.source(): # AnkiWebView.dropEvent(self, new)
if oldmime.hasHtml(): # # tell the drop target to take focus so the drop contents are saved
mime = QMimeData() # self.eval("dropTarget.focus();")
mime.setHtml(self.editor._filterHTML(oldmime.html())) # self.setFocus()
else:
# old qt on linux won't give us html when dragging an image;
# in that case just do the default action (which is to ignore
# the drag)
return AnkiWebView.dropEvent(self, evt)
else:
mime = self._processMime(oldmime)
# create a new event with the new mime data and run it
new = QDropEvent(evt.pos(), evt.possibleActions(), mime,
evt.mouseButtons(), evt.keyboardModifiers())
evt.accept()
QWebView.dropEvent(self, new)
# tell the drop target to take focus so the drop contents are saved
self.eval("dropTarget.focus();")
self.setFocus()
def mungeClip(self, mode=QClipboard.Clipboard): def mungeClip(self, mode=QClipboard.Clipboard):
clip = self.editor.mw.app.clipboard() clip = self.editor.mw.app.clipboard()
@ -1207,10 +1138,10 @@ class EditorWebView(AnkiWebView):
def contextMenuEvent(self, evt): def contextMenuEvent(self, evt):
m = QMenu(self) m = QMenu(self)
a = m.addAction(_("Cut")) a = m.addAction(_("Cut"))
a.connect(a, SIGNAL("triggered()"), self.onCut) a.triggered.connect(self.onCut)
a = m.addAction(_("Copy")) a = m.addAction(_("Copy"))
a.connect(a, SIGNAL("triggered()"), self.onCopy) a.triggered.connect(self.onCopy)
a = m.addAction(_("Paste")) a = m.addAction(_("Paste"))
a.connect(a, SIGNAL("triggered()"), self.onPaste) a.triggered.connect(self.onPaste)
runHook("EditorWebView.contextMenuEvent", self, m) runHook("EditorWebView.contextMenuEvent", self, m)
m.popup(QCursor.pos()) m.popup(QCursor.pos())

View File

@ -44,7 +44,6 @@ class Reviewer(object):
self.web.resetHandlers() self.web.resetHandlers()
self.mw.keyHandler = self._keyHandler self.mw.keyHandler = self._keyHandler
self.web.onBridgeCmd = self._linkHandler self.web.onBridgeCmd = self._linkHandler
self.web.setKeyHandler(self._catchEsc)
if isMac: if isMac:
self.bottom.web.setFixedHeight(46) self.bottom.web.setFixedHeight(46)
else: else:
@ -273,11 +272,6 @@ The front of this card is empty. Please run Tools>Empty Cards.""")
# Handlers # Handlers
############################################################ ############################################################
def _catchEsc(self, evt):
if evt.key() == Qt.Key_Escape:
self.web.eval("$('#typeans').blur();")
return True
def _keyHandler(self, evt): def _keyHandler(self, evt):
key = str(evt.text()) key = str(evt.text())
if key == "e": if key == "e":

View File

@ -76,26 +76,43 @@ class AnkiWebView(QWebEngineView):
self.setPage(self._page) self.setPage(self._page)
self.resetHandlers() self.resetHandlers()
self.allowDrops = False self.allowDrops = False
# reset each time new html is set; used to detect if still in same state
self.key = None
self.setCanFocus(canFocus) self.setCanFocus(canFocus)
self.installEventFilter(self)
def keyPressEvent(self, evt): def eventFilter(self, obj, evt):
if not isinstance(evt, QKeyEvent) or obj != self:
return False
if evt.matches(QKeySequence.Copy): if evt.matches(QKeySequence.Copy):
self.triggerPageAction(QWebEnginePage.Copy) self.onCopy()
evt.accept() return True
# work around a bug with windows qt where shift triggers buttons if evt.matches(QKeySequence.Cut):
if isWin and evt.modifiers() & Qt.ShiftModifier and not evt.text(): self.onCut()
evt.accept() return True
return if evt.matches(QKeySequence.Paste):
QWebEngineView.keyPressEvent(self, evt) self.onPaste()
return True
if evt.matches(QKeySequence.Cancel):
# cheap hack to work around webengine swallowing escape key that
# usually closes dialogs
w = self.parent()
while w:
if isinstance(w, QDialog) or isinstance(w, QMainWindow):
from aqt import mw
if w != mw:
w.close()
break
w = w.parent()
return True
return False
def keyReleaseEvent(self, evt): def onCopy(self):
if self._keyHandler: self.triggerPageAction(QWebEnginePage.Copy)
if self._keyHandler(evt):
evt.accept() def onCut(self):
return self.triggerPageAction(QWebEnginePage.Cut)
QWebEngineView.keyReleaseEvent(self, evt)
def onPaste(self):
self.triggerPageAction(QWebEnginePage.Paste)
def contextMenuEvent(self, evt): def contextMenuEvent(self, evt):
if not self._canFocus: if not self._canFocus:
@ -109,12 +126,7 @@ class AnkiWebView(QWebEngineView):
def dropEvent(self, evt): def dropEvent(self, evt):
pass pass
def setKeyHandler(self, handler=None):
# handler should return true if event should be swallowed
self._keyHandler = handler
def setHtml(self, html): def setHtml(self, html):
self.key = None
app = QApplication.instance() app = QApplication.instance()
oldFocus = app.focusWidget() oldFocus = app.focusWidget()
self._page.setHtml(html) self._page.setHtml(html)
@ -176,6 +188,5 @@ button {
pass pass
def resetHandlers(self): def resetHandlers(self):
self.setKeyHandler(None)
self.onBridgeCmd = self.defaultOnBridgeCmd self.onBridgeCmd = self.defaultOnBridgeCmd
self.onLoadFinished = self.defaultOnLoadFinished self.onLoadFinished = self.defaultOnLoadFinished