mirror of
https://github.com/KDE/konsole.git
synced 2025-12-23 23:38:08 -05:00
Add dumb terminal emulation
A dumb terminal has only one control sequence: \r which moves the cursor to the start of the next line. Profile option `Emulation` selects which emulation to use. Any value other than `dumb` selects the standard Vt102 emulation. Updated version of !629
This commit is contained in:
committed by
Kurt Hindenburg
parent
8ab289866a
commit
774b655dd1
@@ -168,6 +168,7 @@ set(konsoleprivate_SRCS ${windowadaptors_SRCS}
|
|||||||
ViewManager.cpp
|
ViewManager.cpp
|
||||||
ViewProperties.cpp
|
ViewProperties.cpp
|
||||||
Vt102Emulation.cpp
|
Vt102Emulation.cpp
|
||||||
|
DumbEmulation.cpp
|
||||||
WindowSystemInfo.cpp
|
WindowSystemInfo.cpp
|
||||||
ZModemDialog.cpp
|
ZModemDialog.cpp
|
||||||
filterHotSpots/EscapeSequenceUrlFilter.cpp
|
filterHotSpots/EscapeSequenceUrlFilter.cpp
|
||||||
|
|||||||
199
src/DumbEmulation.cpp
Normal file
199
src/DumbEmulation.cpp
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robert.knight@gmail.com>
|
||||||
|
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
// Own
|
||||||
|
#include "DumbEmulation.h"
|
||||||
|
#include "config-konsole.h"
|
||||||
|
|
||||||
|
// Standard
|
||||||
|
#include <cstdio>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
// KDE
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
// Konsole
|
||||||
|
#include "keyboardtranslator/KeyboardTranslator.h"
|
||||||
|
#include "session/SessionController.h"
|
||||||
|
#include "terminalDisplay/TerminalDisplay.h"
|
||||||
|
|
||||||
|
using Konsole::DumbEmulation;
|
||||||
|
|
||||||
|
DumbEmulation::DumbEmulation()
|
||||||
|
: Emulation()
|
||||||
|
{
|
||||||
|
TERM = QStringLiteral("dumb");
|
||||||
|
}
|
||||||
|
|
||||||
|
DumbEmulation::~DumbEmulation()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::clearEntireScreen()
|
||||||
|
{
|
||||||
|
_currentScreen->clearEntireScreen();
|
||||||
|
bufferedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::reset([[maybe_unused]] bool softReset, [[maybe_unused]] bool preservePrompt)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Save the current codec so we can set it later.
|
||||||
|
// Ideally we would want to use the profile setting
|
||||||
|
const QByteArray currentCodec(encoder().name());
|
||||||
|
|
||||||
|
if (currentCodec != nullptr) {
|
||||||
|
setCodec(currentCodec);
|
||||||
|
} else {
|
||||||
|
setCodec(LocaleCodec);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_EMIT resetCursorStyleRequest();
|
||||||
|
|
||||||
|
bufferedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// process an incoming unicode character
|
||||||
|
void DumbEmulation::receiveChars(const QVector<uint> &chars)
|
||||||
|
{
|
||||||
|
for (uint cc : chars) {
|
||||||
|
if (cc == '\r') {
|
||||||
|
_currentScreen->nextLine();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_currentScreen->displayCharacter(cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::sendString(const QByteArray &s)
|
||||||
|
{
|
||||||
|
Q_EMIT sendData(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::sendText(const QString &text)
|
||||||
|
{
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, text);
|
||||||
|
sendKeyEvent(&event); // expose as a big fat keypress event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::sendKeyEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
const Qt::KeyboardModifiers modifiers = event->modifiers();
|
||||||
|
KeyboardTranslator::States states = KeyboardTranslator::NoState;
|
||||||
|
|
||||||
|
TerminalDisplay *currentView = _currentScreen->currentTerminalDisplay();
|
||||||
|
bool isReadOnly = false;
|
||||||
|
if (currentView != nullptr) {
|
||||||
|
isReadOnly = currentView->getReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isReadOnly) {
|
||||||
|
// check flow control state
|
||||||
|
if ((modifiers & Qt::ControlModifier) != 0U) {
|
||||||
|
switch (event->key()) {
|
||||||
|
case Qt::Key_S:
|
||||||
|
Q_EMIT flowControlKeyPressed(true);
|
||||||
|
break;
|
||||||
|
case Qt::Key_C:
|
||||||
|
// No Sixel support
|
||||||
|
case Qt::Key_Q: // cancel flow control
|
||||||
|
Q_EMIT flowControlKeyPressed(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// look up key binding
|
||||||
|
if (_keyTranslator != nullptr) {
|
||||||
|
KeyboardTranslator::Entry entry = _keyTranslator->findEntry(event->key(), modifiers, states);
|
||||||
|
|
||||||
|
// send result to terminal
|
||||||
|
QByteArray textToSend;
|
||||||
|
|
||||||
|
// special handling for the Alt (aka. Meta) modifier. pressing
|
||||||
|
// Alt+[Character] results in Esc+[Character] being sent
|
||||||
|
// (unless there is an entry defined for this particular combination
|
||||||
|
// in the keyboard modifier)
|
||||||
|
const bool wantsAltModifier = ((entry.modifiers() & entry.modifierMask() & Qt::AltModifier) != 0U);
|
||||||
|
const bool wantsMetaModifier = ((entry.modifiers() & entry.modifierMask() & Qt::MetaModifier) != 0U);
|
||||||
|
const bool wantsAnyModifier = ((entry.state() & entry.stateMask() & KeyboardTranslator::AnyModifierState) != 0);
|
||||||
|
|
||||||
|
if (((modifiers & Qt::AltModifier) != 0U) && !(wantsAltModifier || wantsAnyModifier) && !event->text().isEmpty()) {
|
||||||
|
textToSend.prepend("\033");
|
||||||
|
}
|
||||||
|
if (((modifiers & Qt::MetaModifier) != 0U) && !(wantsMetaModifier || wantsAnyModifier) && !event->text().isEmpty()) {
|
||||||
|
textToSend.prepend("\030@s");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.command() != KeyboardTranslator::NoCommand) {
|
||||||
|
if ((entry.command() & KeyboardTranslator::EraseCommand) != 0) {
|
||||||
|
textToSend += eraseChar();
|
||||||
|
}
|
||||||
|
} else if (!entry.text().isEmpty()) {
|
||||||
|
textToSend += entry.text(true, modifiers);
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(_encoder.isValid());
|
||||||
|
textToSend += _encoder.encode(event->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isReadOnly) {
|
||||||
|
Q_EMIT sendData(textToSend);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isReadOnly) {
|
||||||
|
// print an error message to the terminal if no key translator has been
|
||||||
|
// set
|
||||||
|
QString translatorError = i18n(
|
||||||
|
"No keyboard translator available. "
|
||||||
|
"The information needed to convert key presses "
|
||||||
|
"into characters to send to the terminal "
|
||||||
|
"is missing.");
|
||||||
|
reset();
|
||||||
|
receiveData(translatorError.toLatin1().constData(), translatorError.count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::setMode(int)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::resetMode(int)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::saveCursor()
|
||||||
|
{
|
||||||
|
_currentScreen->saveCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::restoreCursor()
|
||||||
|
{
|
||||||
|
_currentScreen->restoreCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::updateSessionAttributes()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char DumbEmulation::eraseChar() const
|
||||||
|
{
|
||||||
|
return '\b';
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::focusChanged([[maybe_unused]] bool focused)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumbEmulation::sendMouseEvent([[maybe_unused]] int cb, [[maybe_unused]] int cx, [[maybe_unused]] int cy, [[maybe_unused]] int eventType)
|
||||||
|
{
|
||||||
|
}
|
||||||
77
src/DumbEmulation.h
Normal file
77
src/DumbEmulation.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2007-2008 Robert Knight <robert.knight@gmail.com>
|
||||||
|
SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DUMBEMULATION_H
|
||||||
|
#define DUMBEMULATION_H
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
// Konsole
|
||||||
|
#include "Emulation.h"
|
||||||
|
#include "Screen.h"
|
||||||
|
|
||||||
|
class QTimer;
|
||||||
|
class QKeyEvent;
|
||||||
|
|
||||||
|
namespace Konsole
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provides a dumb terminal emulation.
|
||||||
|
* The only non printable character is \n
|
||||||
|
*/
|
||||||
|
class KONSOLEPRIVATE_EXPORT DumbEmulation : public Emulation
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructs a new emulation */
|
||||||
|
DumbEmulation();
|
||||||
|
~DumbEmulation() override;
|
||||||
|
|
||||||
|
// reimplemented from Emulation
|
||||||
|
void clearEntireScreen() override;
|
||||||
|
void reset(bool softReset = false, bool preservePrompt = false) override;
|
||||||
|
char eraseChar() const override;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
// reimplemented from Emulation
|
||||||
|
void sendString(const QByteArray &string) override;
|
||||||
|
void sendText(const QString &text) override;
|
||||||
|
void sendKeyEvent(QKeyEvent *) override;
|
||||||
|
void sendMouseEvent(int buttons, int column, int line, int eventType) override;
|
||||||
|
void focusChanged(bool focused) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// reimplemented from Emulation
|
||||||
|
void setMode(int mode) override;
|
||||||
|
void resetMode(int mode) override;
|
||||||
|
void receiveChars(const QVector<uint> &chars) override;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
// Causes sessionAttributeChanged() to be emitted for each (int,QString)
|
||||||
|
// pair in _pendingSessionAttributesUpdates.
|
||||||
|
// Used to buffer multiple attribute updates in the current session
|
||||||
|
void updateSessionAttributes();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int applyCharset(uint c);
|
||||||
|
void setCharset(int n, int cs);
|
||||||
|
void useCharset(int n);
|
||||||
|
void setAndUseCharset(int n, int cs);
|
||||||
|
void saveCursor();
|
||||||
|
void restoreCursor();
|
||||||
|
void resetCharset(int scrno);
|
||||||
|
|
||||||
|
// clears the screen and resizes it to the specified
|
||||||
|
// number of columns
|
||||||
|
void clearScreenAndSetColumns(int columnCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUMBEMULATION_H
|
||||||
@@ -89,6 +89,8 @@ public:
|
|||||||
Emulation();
|
Emulation();
|
||||||
~Emulation() override;
|
~Emulation() override;
|
||||||
|
|
||||||
|
QString TERM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new window onto the output from this emulation. The contents
|
* Creates a new window onto the output from this emulation. The contents
|
||||||
* of the window are then rendered by views which are set to use this window using the
|
* of the window are then rendered by views which are set to use this window using the
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ Vt102Emulation::Vt102Emulation()
|
|||||||
_sessionAttributesUpdateTimer->setSingleShot(true);
|
_sessionAttributesUpdateTimer->setSingleShot(true);
|
||||||
QObject::connect(_sessionAttributesUpdateTimer, &QTimer::timeout, this, &Konsole::Vt102Emulation::updateSessionAttributes);
|
QObject::connect(_sessionAttributesUpdateTimer, &QTimer::timeout, this, &Konsole::Vt102Emulation::updateSessionAttributes);
|
||||||
|
|
||||||
|
TERM = QStringLiteral("xterm-256color");
|
||||||
|
|
||||||
initTokenizer();
|
initTokenizer();
|
||||||
imageId = 0;
|
imageId = 0;
|
||||||
savedKeys = QMap<char, qint64>();
|
savedKeys = QMap<char, qint64>();
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ const std::vector<Profile::PropertyInfo> Profile::DefaultProperties = {
|
|||||||
{PeekPrimaryKeySequence, "PeekPrimaryKeySequence", TERMINAL_GROUP, QString()},
|
{PeekPrimaryKeySequence, "PeekPrimaryKeySequence", TERMINAL_GROUP, QString()},
|
||||||
{LineNumbers, "LineNumbers", TERMINAL_GROUP, 0},
|
{LineNumbers, "LineNumbers", TERMINAL_GROUP, 0},
|
||||||
{AutoSaveInterval, "AutoSaveInterval", TERMINAL_GROUP, 10000},
|
{AutoSaveInterval, "AutoSaveInterval", TERMINAL_GROUP, 10000},
|
||||||
|
{Emulation, "Emulation", TERMINAL_GROUP, QVariant::String},
|
||||||
|
|
||||||
// Cursor
|
// Cursor
|
||||||
{UseCustomCursorColor, "UseCustomCursorColor", CURSOR_GROUP, false},
|
{UseCustomCursorColor, "UseCustomCursorColor", CURSOR_GROUP, false},
|
||||||
|
|||||||
@@ -361,6 +361,8 @@ public:
|
|||||||
/** Shortcut for peeking primary screen */
|
/** Shortcut for peeking primary screen */
|
||||||
PeekPrimaryKeySequence,
|
PeekPrimaryKeySequence,
|
||||||
|
|
||||||
|
Emulation,
|
||||||
|
|
||||||
/** (bool) If true, text that matches a color in hex format
|
/** (bool) If true, text that matches a color in hex format
|
||||||
* when hovered by the mouse pointer.
|
* when hovered by the mouse pointer.
|
||||||
*/
|
*/
|
||||||
@@ -903,6 +905,11 @@ public:
|
|||||||
return property<bool>(Profile::SemanticInputClick);
|
return property<bool>(Profile::SemanticInputClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString emulation() const
|
||||||
|
{
|
||||||
|
return property<QString>(Profile::Emulation);
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a list of all properties names and their type
|
/** Return a list of all properties names and their type
|
||||||
* (for use with -p option).
|
* (for use with -p option).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include <sessionadaptor.h>
|
#include <sessionadaptor.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "DumbEmulation.h"
|
||||||
#include "Pty.h"
|
#include "Pty.h"
|
||||||
#include "SSHProcessInfo.h"
|
#include "SSHProcessInfo.h"
|
||||||
#include "SessionController.h"
|
#include "SessionController.h"
|
||||||
@@ -79,8 +80,12 @@ using namespace Konsole;
|
|||||||
static bool show_disallow_certain_dbus_methods_message = true;
|
static bool show_disallow_certain_dbus_methods_message = true;
|
||||||
|
|
||||||
static const int ZMODEM_BUFFER_SIZE = 1048576; // 1 Mb
|
static const int ZMODEM_BUFFER_SIZE = 1048576; // 1 Mb
|
||||||
|
|
||||||
Session::Session(QObject *parent)
|
Session::Session(QObject *parent)
|
||||||
|
{
|
||||||
|
Session(parent, Profile::Ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::Session(QObject *parent, Profile::Ptr profile)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
_uniqueIdentifier = QUuid::createUuid();
|
_uniqueIdentifier = QUuid::createUuid();
|
||||||
@@ -101,7 +106,11 @@ Session::Session(QObject *parent)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// create emulation backend
|
// create emulation backend
|
||||||
_emulation = new Vt102Emulation();
|
if (profile->emulation() == QStringLiteral("dumb")) {
|
||||||
|
_emulation = new DumbEmulation();
|
||||||
|
} else {
|
||||||
|
_emulation = new Vt102Emulation();
|
||||||
|
}
|
||||||
_emulation->reset();
|
_emulation->reset();
|
||||||
|
|
||||||
connect(_emulation, &Konsole::Emulation::sessionAttributeChanged, this, &Konsole::Session::setSessionAttribute);
|
connect(_emulation, &Konsole::Emulation::sessionAttributeChanged, this, &Konsole::Session::setSessionAttribute);
|
||||||
@@ -552,6 +561,7 @@ void Session::run()
|
|||||||
addEnvironmentEntry(QStringLiteral("SHELL_SESSION_ID=%1").arg(shellSessionId()));
|
addEnvironmentEntry(QStringLiteral("SHELL_SESSION_ID=%1").arg(shellSessionId()));
|
||||||
|
|
||||||
addEnvironmentEntry(QStringLiteral("WINDOWID=%1").arg(QString::number(windowId())));
|
addEnvironmentEntry(QStringLiteral("WINDOWID=%1").arg(QString::number(windowId())));
|
||||||
|
addEnvironmentEntry(QStringLiteral("TERM=%1").arg(_emulation->TERM));
|
||||||
|
|
||||||
#if HAVE_DBUS
|
#if HAVE_DBUS
|
||||||
const QString dbusService = QDBusConnection::sessionBus().baseService();
|
const QString dbusService = QDBusConnection::sessionBus().baseService();
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "Shortcut_p.h"
|
#include "Shortcut_p.h"
|
||||||
#include "config-konsole.h"
|
#include "config-konsole.h"
|
||||||
#include "konsoleprivate_export.h"
|
#include "konsoleprivate_export.h"
|
||||||
|
#include "profile/Profile.h"
|
||||||
|
|
||||||
class QColor;
|
class QColor;
|
||||||
class QTextCodec;
|
class QTextCodec;
|
||||||
@@ -76,6 +77,7 @@ public:
|
|||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
explicit Session(QObject *parent = nullptr);
|
explicit Session(QObject *parent = nullptr);
|
||||||
|
explicit Session(QObject *parent, Profile::Ptr profile);
|
||||||
~Session() override;
|
~Session() override;
|
||||||
|
|
||||||
/* Returns the process info so the plugins can peek at it's name */
|
/* Returns the process info so the plugins can peek at it's name */
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Session *SessionManager::createSession(Profile::Ptr profile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// configuration information found, create a new session based on this
|
// configuration information found, create a new session based on this
|
||||||
auto session = new Session();
|
auto session = new Session(nullptr, profile);
|
||||||
Q_ASSERT(session);
|
Q_ASSERT(session);
|
||||||
applyProfile(session, profile, false);
|
applyProfile(session, profile, false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user