Terminal: lock/unlock keyboard

We copied QShortCutMap into Qtc to allow us tight control over which shortcuts
are "enabled" while the focus is inside a terminal, and the keyboard is "locked"
to the Terminal. Locked here means that except for a select few, all key presses
are send directly to the terminal and cannot be used to activate other actions.

Change-Id: I96cddf753033c0f4e7d806b20085bb4755853117
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-06-06 09:37:13 +02:00
parent ad5e8392fe
commit 217b03c1ac
10 changed files with 711 additions and 45 deletions

View File

@@ -252,10 +252,37 @@ void TerminalWidget::setupColors()
update();
}
static RegisteredAction registerAction(Id commandId, const Context &context)
static bool contextMatcher(QObject *, Qt::ShortcutContext)
{
return true;
}
void TerminalWidget::registerShortcut(Command *cmd)
{
QTC_ASSERT(cmd, return);
auto addShortCut = [this, cmd] {
for (const auto &keySequence : cmd->keySequences()) {
m_shortcutMap.addShortcut(cmd->action(),
keySequence,
Qt::ShortcutContext::WindowShortcut,
contextMatcher);
}
};
auto removeShortCut = [this, cmd] { m_shortcutMap.removeShortcut(0, cmd->action()); };
addShortCut();
connect(cmd, &Command::keySequenceChanged, this, [addShortCut, removeShortCut]() {
removeShortCut();
addShortCut();
});
}
RegisteredAction TerminalWidget::registerAction(Id commandId, const Context &context)
{
QAction *action = new QAction;
ActionManager::registerAction(action, commandId, context);
Command *cmd = ActionManager::registerAction(action, commandId, context);
registerShortcut(cmd);
return RegisteredAction(action, [commandId](QAction *a) {
ActionManager::unregisterAction(a, commandId);
@@ -287,10 +314,10 @@ void TerminalWidget::setupActions()
this,
&TerminalWidget::moveCursorWordRight);
m_exit = unlockGlobalAction(Core::Constants::EXIT, m_context);
m_options = unlockGlobalAction(Core::Constants::OPTIONS, m_context);
m_settings = unlockGlobalAction("Preferences.Terminal.General", m_context);
m_findInDocument = unlockGlobalAction(Core::Constants::FIND_IN_DOCUMENT, m_context);
unlockGlobalAction(Core::Constants::EXIT);
unlockGlobalAction(Core::Constants::OPTIONS);
unlockGlobalAction("Preferences.Terminal.General");
unlockGlobalAction(Core::Constants::FIND_IN_DOCUMENT);
}
void TerminalWidget::closeTerminal()
@@ -1506,6 +1533,11 @@ void TerminalWidget::showEvent(QShowEvent *event)
bool TerminalWidget::event(QEvent *event)
{
if (TerminalSettings::instance().lockKeyboard() && event->type() == QEvent::ShortcutOverride) {
event->accept();
return true;
}
if (event->type() == QEvent::Paint) {
QPainter p(this);
p.fillRect(QRect(QPoint(0, 0), size()), m_currentColors[ColorIndex::Background]);
@@ -1513,12 +1545,16 @@ bool TerminalWidget::event(QEvent *event)
}
if (event->type() == QEvent::KeyPress) {
QKeyEvent *k = (QKeyEvent *) event;
auto k = static_cast<QKeyEvent *>(event);
if (TerminalSettings::instance().lockKeyboard() && m_shortcutMap.tryShortcut(k))
return true;
keyPressEvent(k);
return true;
}
if (event->type() == QEvent::KeyRelease) {
QKeyEvent *k = (QKeyEvent *) event;
auto k = static_cast<QKeyEvent *>(event);
keyReleaseEvent(k);
return true;
}
@@ -1565,21 +1601,11 @@ void TerminalWidget::initActions()
ActionManager::registerAction(&clearTerminal, Constants::CLEAR_TERMINAL, context);
}
UnlockedGlobalAction TerminalWidget::unlockGlobalAction(const Utils::Id &commandId,
const Context &context)
void TerminalWidget::unlockGlobalAction(const Utils::Id &commandId)
{
QAction *srcAction = ActionManager::command(commandId)->actionForContext(
Core::Constants::C_GLOBAL);
ProxyAction *proxy = ProxyAction::proxyActionWithIcon(srcAction, srcAction->icon());
ActionManager::registerAction(proxy, commandId, context);
UnlockedGlobalAction registeredAction(proxy, [commandId](QAction *a) {
ActionManager::unregisterAction(a, commandId);
delete a;
});
return registeredAction;
Command *cmd = ActionManager::command(commandId);
QTC_ASSERT(cmd, return);
registerShortcut(cmd);
}
} // namespace Terminal