Merge pull request #103 from Swordfish90/improvemouse

Improved mouse behavior. Enabled mouse support for applications.
This commit is contained in:
Filippo Scognamiglio 2014-08-30 01:38:58 +02:00
commit 98b2511660
8 changed files with 1003 additions and 561 deletions

View File

@ -133,41 +133,34 @@ Item{
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
anchors.fill: parent
onWheel:{
var coord = correctDistortion(wheel.x, wheel.y);
var lines = wheel.angleDelta.y > 0 ? -2 : 2;
kterminal.scrollWheel(coord.width, coord.height, lines);
}
onClicked: {
if (mouse.button == Qt.RightButton){
contextmenu.popup();
} else if (mouse.button == Qt.MiddleButton){
kterminal.pasteSelection();
if(wheel.modifiers & Qt.ControlModifier){
wheel.angleDelta.y > 0 ? zoomIn.trigger() : zoomOut.trigger();
} else {
var coord = correctDistortion(wheel.x, wheel.y);
var lines = wheel.angleDelta.y > 0 ? -1 : 1;
kterminal.scrollWheelEvent(coord, lines);
}
}
onDoubleClicked: {
if (mouse.button == Qt.LeftButton){
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseDoubleClick(coord.width, coord.height);
}
}
onPositionChanged: {
if (pressedButtons & Qt.LeftButton){
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseMove(coord.width, coord.height);
}
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseDoubleClickEvent(coord, mouse.button, mouse.modifiers);
}
onPressed: {
if (mouse.button == Qt.LeftButton){
if((!kterminal.usesMouse || mouse.modifiers & Qt.ShiftModifier) && mouse.button == Qt.RightButton) {
contextmenu.popup();
} else {
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mousePress(coord.width, coord.height);
kterminal.mousePressEvent(coord, mouse.button, mouse.modifiers)
}
}
onReleased: {
if (mouse.button == Qt.LeftButton){
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseRelease(coord.width, coord.height);
}
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseReleaseEvent(coord, mouse.button, mouse.modifiers);
}
onPositionChanged: {
var coord = correctDistortion(mouse.x, mouse.y);
kterminal.mouseMoveEvent(coord, mouse.button, mouse.buttons, mouse.modifiers);
}
//Frame displacement properties
property real dtop: frame.item.displacementTop
@ -185,7 +178,7 @@ Item{
var cc = Qt.size(0.5 - x, 0.5 - y);
var distortion = (cc.height * cc.height + cc.width * cc.width) * shadersettings.screen_distortion;
return Qt.size((x - cc.width * (1+distortion) * distortion) * width,
return Qt.point((x - cc.width * (1+distortion) * distortion) * width,
(y - cc.height * (1+distortion) * distortion) * height)
}
}

View File

@ -376,6 +376,12 @@ signals:
*/
void imageSizeChanged(int lineCount , int columnCount);
/**
* Emitted after receiving the escape sequence which asks to change
* the terminal emulator's size
*/
void imageResizeRequest(const QSize& sizz);
/**
* Emitted when the terminal program requests to change various properties
* of the terminal display.

View File

@ -48,9 +48,10 @@
#include "ShellCommand.h" // REUSE THIS
#include "Vt102Emulation.h" // REUSE THIS
int Session::lastSessionId = 0;
using namespace Konsole;
Session::Session() :
_shellProcess(0)
, _emulation(0)
@ -199,14 +200,9 @@ void Session::addView(KTerminalDisplay * widget)
// allow emulation to notify view when the foreground process
// indicates whether or not it is interested in mouse signals
// TODO Disabled since at the moment it is not working properly.
// Remember to reenable that once it' is's working.
//connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
// SLOT(setUsesMouse(bool)) );
//widget->setUsesMouse( _emulation->programUsesMouse() );
connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget ,
SLOT(setUsesMouse(bool)) );
widget->setUsesMouse( _emulation->programUsesMouse() );
widget->setScreenWindow(_emulation->createWindow());
}

View File

@ -447,92 +447,377 @@ QStringList KTerminalDisplay::availableColorSchemes()
return ret;
}
void KTerminalDisplay::scrollWheel(qreal x, qreal y, int lines){
void KTerminalDisplay::scrollWheelEvent(QPoint position, int lines){
if(_mouseMarks){
int charLine;
int charColumn;
getCharacterPosition(QPoint(x,y) , charLine , charColumn);
emit mouseSignal(lines > 0 ? 5 : 4,
charColumn + 1,
charLine + 1,
0);
} else {
if(_screenWindow->lineCount() == _screenWindow->windowLines()){
const int keyCode = lines > 0 ? Qt::Key_Down : Qt::Key_Up;
QKeyEvent keyEvent(QEvent::KeyPress, keyCode, Qt::NoModifier);
emit keyPressedSignal(&keyEvent);
emit keyPressedSignal(&keyEvent);
} else {
_screenWindow->scrollBy( ScreenWindow::ScrollLines, lines );
_screenWindow->scrollCount();
updateImage();
}
} else {
int charLine;
int charColumn;
getCharacterPosition(position, charLine, charColumn);
emit mouseSignal(lines > 0 ? 5 : 4,
charColumn + 1,
charLine + 1,
0);
}
}
void KTerminalDisplay::mousePress(qreal x, qreal y){
if (m_focusOnClick) forcedFocus();
if (m_showVKBonClick) ShowVKB(true);
void KTerminalDisplay::doPaste(QString text, bool appendReturn)
{
if (!_screenWindow)
return;
if (appendReturn)
text.append("\r");
if (!text.isEmpty()) {
text.replace('\n', '\r');
// if (bracketedPasteMode()) {
// text.prepend("\e[200~");
// text.append("\e[201~");
// }
// perform paste by simulating keypress events
QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
emit keyPressedSignal(&e);
}
}
void KTerminalDisplay::pasteFromClipboard(bool appendEnter)
{
QString text = QGuiApplication::clipboard()->text(QClipboard::Clipboard);
doPaste(text, appendEnter);
}
void KTerminalDisplay::pasteFromX11Selection(bool appendEnter)
{
QString text = QGuiApplication::clipboard()->text(QClipboard::Selection);
doPaste(text, appendEnter);
}
void KTerminalDisplay::processMidButtonClick(QPoint &position, Qt::KeyboardModifier modifiers)
{
if (_mouseMarks || (modifiers & Qt::ShiftModifier)) {
const bool appendEnter = modifiers & Qt::ControlModifier;
if (true /*_middleClickPasteMode == Enum::PasteFromX11Selection*/) {
pasteFromX11Selection(appendEnter);
} else if (false /*_middleClickPasteMode == Enum::PasteFromClipboard*/) {
pasteFromClipboard(appendEnter);
} else {
Q_ASSERT(false);
}
} else {
int charLine = 0;
int charColumn = 0;
getCharacterPosition(position, charLine, charColumn);
emit mouseSignal(1, charColumn + 1, charLine + 1, 0);
//emit mouseSignal(1, charColumn + 1, charLine + 1 + _scrollBar->value() - _scrollBar->maximum() , 0);
}
}
void KTerminalDisplay::mousePressEvent(QPoint position, int but, int mod)
{
Qt::MouseButton button = (Qt::MouseButton) but;
Qt::KeyboardModifier modifiers = (Qt::KeyboardModifier) mod;
// if (_possibleTripleClick && (ev->button() == Qt::LeftButton)) {
// mouseTripleClickEvent(ev);
// return;
// }
if (!_screenWindow) return;
int charLine;
int charColumn;
getCharacterPosition(QPoint(x,y), charLine, charColumn);
getCharacterPosition(position, charLine, charColumn);
QPoint pos = QPoint(charColumn, charLine);
_wordSelectionMode = false;
_lineSelectionMode = false;
if (button == Qt::LeftButton) {
_lineSelectionMode = false;
_wordSelectionMode = false;
if(_mouseMarks){
emit mouseSignal(0, charColumn + 1, charLine + 1, 0);
} else {
QPoint pos = QPoint(charColumn, charLine);
_preserveLineBreaks = !((modifiers & Qt::ControlModifier) && !(modifiers & Qt::AltModifier));
_columnSelectionMode = (modifiers & Qt::AltModifier) && (modifiers & Qt::ControlModifier);
_screenWindow->clearSelection();
_iPntSel = _pntSel = pos;
_actSel = 1; // left mouse button pressed but nothing selected yet.
if (_mouseMarks || (modifiers == Qt::ShiftModifier)) {
// Only extend selection for programs not interested in mouse
if (_mouseMarks && (modifiers == Qt::ShiftModifier)) {
extendSelection(position);
} else {
_screenWindow->clearSelection();
//pos.ry() += _scrollBar->value();
_iPntSel = _pntSel = pos;
_actSel = 1; // left mouse button pressed but nothing selected yet.
}
} else {
emit mouseSignal(0, charColumn + 1, charLine + 1, 0);
}
} else if (button == Qt::MidButton) {
processMidButtonClick(position, modifiers);
} else if (button == Qt::RightButton) {
if (!_mouseMarks)
emit mouseSignal(2, charColumn + 1, charLine + 1, 0);
}
}
void KTerminalDisplay::mouseMove(qreal x, qreal y){
QPoint pos(x, y);
void KTerminalDisplay::mouseMoveEvent(QPoint position, int but, int buts, int mod)
{
Qt::MouseButton button = (Qt::MouseButton) but;
Qt::KeyboardModifier modifiers = (Qt::KeyboardModifier) mod;
Qt::MouseButtons buttons = (Qt::MouseButtons) buts;
if(_mouseMarks){
int charLine;
int charColumn;
getCharacterPosition(pos, charLine, charColumn);
int charLine = 0;
int charColumn = 0;
getCharacterPosition(position, charLine, charColumn);
emit mouseSignal(0, charColumn + 1, charLine + 1, 1);
} else {
extendSelection(pos);
// for auto-hiding the cursor, we need mouseTracking
if (buttons == Qt::NoButton) return;
// if the terminal is interested in mouse movements
// then emit a mouse movement signal, unless the shift
// key is being held down, which overrides this.
if (!_mouseMarks && !(modifiers & Qt::ShiftModifier)) {
int button = 3;
if (buttons & Qt::LeftButton)
button = 0;
if (buttons & Qt::MidButton)
button = 1;
if (buttons & Qt::RightButton)
button = 2;
emit mouseSignal(button, charColumn + 1, charLine + 1, 1);
return;
}
if (_actSel == 0) return;
// don't extend selection while pasting
if (buttons & Qt::MidButton) return;
extendSelection(position);
}
void KTerminalDisplay::mouseDoubleClick(qreal x, qreal y){
QPoint pos(x, y);
if(_mouseMarks){
int charLine;
int charColumn;
getCharacterPosition(pos, charLine, charColumn);
QPoint KTerminalDisplay::findWordEnd(const QPoint &pnt)
{
const int regSize = qMax(_screenWindow->windowLines(), 10);
const int curLine = _screenWindow->currentLine();
int i = pnt.y();
int x = pnt.x();
int y = i + curLine;
int j = loc(x, i);
QVector<LineProperty> lineProperties = _lineProperties;
Screen *screen = _screenWindow->screen();
Character *image = _image;
Character *tmp_image = NULL;
const QChar selClass = charClass(image[j]);
const int imageSize = regSize * _columns;
const int maxY = _screenWindow->lineCount() - 1;
const int maxX = _columns - 1;
emit mouseSignal(0, charColumn + 1, charLine + 1, 0);
//emit mouseSignal(0, charColumn + 1, charLine + 1, 0);
} else {
_wordSelectionMode = true;
extendSelection(pos);
while (true) {
const int lineCount = lineProperties.count();
for (;;j++, x++) {
if (x < maxX) {
if (charClass(image[j + 1]) == selClass)
continue;
goto out;
} else if (i < lineCount - 1) {
if (lineProperties[i] & LINE_WRAPPED &&
charClass(image[j + 1]) == selClass) {
x = -1;
i++;
y++;
continue;
}
goto out;
} else if (y < maxY) {
if (i < lineCount && !(lineProperties[i] & LINE_WRAPPED))
goto out;
break;
} else {
goto out;
}
}
int newRegEnd = qMin(y + regSize - 1, maxY);
lineProperties = screen->getLineProperties(y, newRegEnd);
i = 0;
if (!tmp_image) {
tmp_image = new Character[imageSize];
image = tmp_image;
}
screen->getImage(tmp_image, imageSize, y, newRegEnd);
x--;
j = loc(x, i);
}
out:
y -= curLine;
// In word selection mode don't select @ (64) if at end of word.
if (((image[j].rendition & RE_EXTENDED_CHAR) == 0) &&
(QChar(image[j].character) == '@') &&
(y > pnt.y() || x > pnt.x())) {
if (x > 0) {
x--;
} else {
y--;
}
}
if (tmp_image) {
delete[] tmp_image;
}
return QPoint(x, y);
}
void KTerminalDisplay::mouseRelease(qreal x, qreal y){
_actSel = 0;
QPoint KTerminalDisplay::findWordStart(const QPoint &pnt)
{
const int regSize = qMax(_screenWindow->windowLines(), 10);
const int curLine = _screenWindow->currentLine();
int i = pnt.y();
int x = pnt.x();
int y = i + curLine;
int j = loc(x, i);
QVector<LineProperty> lineProperties = _lineProperties;
Screen *screen = _screenWindow->screen();
Character *image = _image;
Character *tmp_image = NULL;
const QChar selClass = charClass(image[j]);
const int imageSize = regSize * _columns;
if(_mouseMarks){
int charLine;
int charColumn;
getCharacterPosition(QPoint(x,y), charLine, charColumn);
while (true) {
for (;;j--, x--) {
if (x > 0) {
if (charClass(image[j - 1]) == selClass)
continue;
goto out;
} else if (i > 0) {
if (lineProperties[i - 1] & LINE_WRAPPED &&
charClass(image[j - 1]) == selClass) {
x = _columns;
i--;
y--;
continue;
}
goto out;
} else if (y > 0) {
break;
} else {
goto out;
}
}
int newRegStart = qMax(0, y - regSize);
lineProperties = screen->getLineProperties(newRegStart, y - 1);
i = y - newRegStart;
if (!tmp_image) {
tmp_image = new Character[imageSize];
image = tmp_image;
}
screen->getImage(tmp_image, imageSize, newRegStart, y - 1);
j = loc(x, i);
}
out:
if (tmp_image) {
delete[] tmp_image;
}
return QPoint(x, y - curLine);
}
emit mouseSignal(0, charColumn + 1, charLine + 1, 2);
void KTerminalDisplay::mouseDoubleClickEvent(QPoint position, int but, int mod)
{
Qt::MouseButton button = (Qt::MouseButton) but;
Qt::KeyboardModifier modifiers = (Qt::KeyboardModifier) mod;
if (button != Qt::LeftButton) return;
if (!_screenWindow) return;
int charLine = 0;
int charColumn = 0;
getCharacterPosition(position, charLine, charColumn);
// If the application is interested in mouse events. They have already been forwarded.
if (!_mouseMarks && !(modifiers & Qt::ShiftModifier))
return;
_screenWindow->clearSelection();
_wordSelectionMode = true;
_actSel = 2; // within selection
_iPntSel = QPoint(charColumn, charLine);
const QPoint bgnSel = findWordStart(_iPntSel);
const QPoint endSel = findWordEnd(_iPntSel);
_screenWindow->setSelectionStart(bgnSel.x() , bgnSel.y() , false);
_screenWindow->setSelectionEnd(endSel.x() , endSel.y());
copyToX11Selection();
//TODO implement triple click.
// _possibleTripleClick = true;
// QTimer::singleShot(QApplication::doubleClickInterval(), this,
// SLOT(tripleClickTimeout()));
}
void KTerminalDisplay::copyToX11Selection()
{
if (!_screenWindow)
return;
QString text = _screenWindow->selectedText(_preserveLineBreaks);
if (text.isEmpty())
return;
QGuiApplication::clipboard()->setText(text, QClipboard::Selection);
}
void KTerminalDisplay::mouseReleaseEvent(QPoint position, int but, int mod)
{
Qt::MouseButton button = (Qt::MouseButton) but;
Qt::KeyboardModifier modifiers = (Qt::KeyboardModifier) mod;
if (!_screenWindow)
return;
int charLine;
int charColumn;
getCharacterPosition(position, charLine, charColumn);
if (button == Qt::LeftButton) {
if (_actSel > 1) {
copyToX11Selection();
}
_actSel = 0;
//FIXME: emits a release event even if the mouse is
// outside the range. The procedure used in `mouseMoveEvent'
// applies here, too.
if (!_mouseMarks && !(modifiers & Qt::ShiftModifier))
emit mouseSignal(0, charColumn + 1, charLine + 1 , 2);
}
if (!_mouseMarks &&
(button == Qt::RightButton || button == Qt::MidButton) &&
!(modifiers & Qt::ShiftModifier)) {
emit mouseSignal(button == Qt::MidButton ? 1 : 2, charColumn + 1, charLine + 1, 2);
}
}
@ -546,7 +831,12 @@ void KTerminalDisplay::scrollScreenWindow(enum ScreenWindow::RelativeScrollMode
void KTerminalDisplay::setUsesMouse(bool usesMouse){
_mouseMarks = !usesMouse;
_mouseMarks = usesMouse;
emit usesMouseChanged();
}
bool KTerminalDisplay::getUsesMouse(){
return !_mouseMarks;
}
void KTerminalDisplay::setAutoFocus(bool au)
@ -1361,16 +1651,33 @@ void KTerminalDisplay::updateLineProperties()
_lineProperties = _screenWindow->getLineProperties();
}
QChar KTerminalDisplay::charClass(QChar qch) const
QChar KTerminalDisplay::charClass(const Character& ch) const
{
if ( qch.isSpace() ) return ' ';
if (ch.rendition & RE_EXTENDED_CHAR) {
ushort extendedCharLength = 0;
const ushort* chars = ExtendedCharTable::instance.lookupExtendedChar(ch.character, extendedCharLength);
if (chars && extendedCharLength > 0) {
const QString s = QString::fromUtf16(chars, extendedCharLength);
if (_wordCharacters.contains(s, Qt::CaseInsensitive))
return 'a';
bool allLetterOrNumber = true;
for (int i = 0; allLetterOrNumber && i < s.size(); ++i)
allLetterOrNumber = s.at(i).isLetterOrNumber();
return allLetterOrNumber ? 'a' : s.at(0);
}
return 0;
} else {
const QChar qch(ch.character);
if (qch.isSpace()) return ' ';
if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
return 'a';
if (qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive))
return 'a';
return qch;
return qch;
}
}
void KTerminalDisplay::setWordCharacters(const QString& wc)
{
_wordCharacters = wc;

View File

@ -70,6 +70,7 @@ class KONSOLEPRIVATE_EXPORT KTerminalDisplay : public QQuickPaintedItem
Q_PROPERTY(bool ShowIMEOnClick READ autoVKB WRITE setAutoVKB NOTIFY changedAutoVKB)
Q_PROPERTY(QSize terminalSize READ getTerminalSize NOTIFY terminalSizeChanged)
Q_PROPERTY(QSize paintedFontSize READ getFontSize NOTIFY paintedFontSizeChanged)
Q_PROPERTY(bool usesMouse READ getUsesMouse NOTIFY usesMouseChanged)
public:
@ -311,15 +312,10 @@ public slots:
void setColorScheme(const QString &name);
QStringList availableColorSchemes();
void scrollWheel(qreal x, qreal y, int lines);
void mousePress(qreal x, qreal y);
void mouseMove(qreal x, qreal y);
void mouseDoubleClick(qreal x, qreal y);
void mouseRelease(qreal x, qreal y);
void scrollScreenWindow(enum ScreenWindow::RelativeScrollMode mode, int amount);
void setUsesMouse(bool usesMouse);
bool getUsesMouse(void);
bool autoFocus() { return m_focusOnClick; }
void setAutoFocus(bool au);
@ -425,6 +421,8 @@ signals:
void mouseSignal(int,int,int,int);
void usesMouseChanged();
void terminalSizeChanged();
void paintedFontSizeChanged();
@ -477,7 +475,11 @@ protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QRect geometryRound(const QRectF &r) const;
//void mousePressEvent(QMouseEvent*ev);
Q_INVOKABLE void mousePressEvent(QPoint position, int but, int mod);
Q_INVOKABLE void mouseReleaseEvent(QPoint position, int but, int mod);
Q_INVOKABLE void mouseDoubleClickEvent(QPoint position, int but, int mod);
Q_INVOKABLE void mouseMoveEvent(QPoint position, int but, int buts, int mod);
Q_INVOKABLE void scrollWheelEvent(QPoint position, int lines);
//void mouseReleaseEvent( QMouseEvent* );
//void mouseMoveEvent( QMouseEvent* );
@ -497,7 +499,7 @@ protected:
// - A space (returns ' ')
// - Part of a word (returns 'a')
// - Other characters (returns the input character)
QChar charClass(QChar ch) const;
QChar charClass(const Character& ch) const;
void clearImage();
@ -594,6 +596,14 @@ private:
// redraws the cursor
void updateCursor();
QPoint findWordStart(const QPoint &pnt);
QPoint findWordEnd(const QPoint &pnt);
void processMidButtonClick(QPoint &position, Qt::KeyboardModifier modifiers);
void copyToX11Selection();
void pasteFromClipboard(bool appendEnter);
void pasteFromX11Selection(bool appendEnter);
void doPaste(QString text, bool appendReturn);
bool handleShortcutOverrideEvent(QKeyEvent* event);
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

View File

@ -23,47 +23,57 @@
// Own
#include "Vt102Emulation.h"
// XKB
//#include <config-konsole.h>
// this allows konsole to be compiled without XKB and XTEST extensions
// even though it might be available on a particular system.
#if defined(AVOID_XKB)
#undef HAVE_XKB
#endif
#if defined(HAVE_XKB)
void scrolllock_set_off();
void scrolllock_set_on();
#endif
// Standard
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
// Qt
#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtCore/QByteRef>
// KDE
//#include <kdebug.h>
//#include <klocale.h>
//#include <KLocalizedString>
//#include <KDebug>
// Konsole
#include "KeyboardTranslator.h"
#include "Screen.h"
#include "TerminalDisplay.h"
using Konsole::Vt102Emulation;
/*
The VT100 has 32 special graphical characters. The usual vt100 extended
xterm fonts have these at 0x00..0x1f.
QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals
come in here as proper unicode characters.
We treat non-iso10646 fonts as VT100 extended and do the required mapping
from unicode to 0x00..0x1f. The remaining translation is then left to the
QCodec.
*/
// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
unsigned short Konsole::vt100_graphics[32] = {
// 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15
0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534,
0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7
};
Vt102Emulation::Vt102Emulation()
: Emulation(),
_titleUpdateTimer(new QTimer(this))
_titleUpdateTimer(new QTimer(this))
{
_titleUpdateTimer->setSingleShot(true);
QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle()));
_titleUpdateTimer->setSingleShot(true);
QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle()));
initTokenizer();
reset();
initTokenizer();
reset();
}
Vt102Emulation::~Vt102Emulation()
@ -71,21 +81,29 @@ Vt102Emulation::~Vt102Emulation()
void Vt102Emulation::clearEntireScreen()
{
_currentScreen->clearEntireScreen();
bufferedUpdate();
_currentScreen->clearEntireScreen();
bufferedUpdate();
}
void Vt102Emulation::reset()
{
resetTokenizer();
resetModes();
resetCharset(0);
_screen[0]->reset();
resetCharset(1);
_screen[1]->reset();
setCodec(LocaleCodec);
// Save the current codec so we can set it later.
// Ideally we would want to use the profile setting
const QTextCodec* currentCodec = codec();
bufferedUpdate();
resetTokenizer();
resetModes();
resetCharset(0);
_screen[0]->reset();
resetCharset(1);
_screen[1]->reset();
if (currentCodec)
setCodec(currentCodec);
else
setCodec(LocaleCodec);
bufferedUpdate();
}
/* ------------------------------------------------------------------------- */
@ -142,7 +160,7 @@ void Vt102Emulation::reset()
The last two forms allow list of arguments. Since the elements of
the lists are treated individually the same way, they are passed
as individual tokens to the interpretation. Further, because the
meaning of the parameters are names (althought represented as numbers),
meaning of the parameters are names (although represented as numbers),
they are includes within the token ('N').
*/
@ -162,7 +180,7 @@ void Vt102Emulation::reset()
#define TY_CSI_PG(A) TY_CONSTRUCT(9,A,0)
#define TY_CSI_PE(A) TY_CONSTRUCT(10,A,0)
#define MAX_ARGUMENT 4096
const int MAX_ARGUMENT = 4096;
// Tokenizer --------------------------------------------------------------- --
@ -175,64 +193,62 @@ void Vt102Emulation::reset()
void Vt102Emulation::resetTokenizer()
{
tokenBufferPos = 0;
argc = 0;
argv[0] = 0;
argv[1] = 0;
tokenBufferPos = 0;
argc = 0;
argv[0] = 0;
argv[1] = 0;
}
void Vt102Emulation::addDigit(int digit)
{
if (argv[argc] < MAX_ARGUMENT)
argv[argc] = 10*argv[argc] + digit;
if (argv[argc] < MAX_ARGUMENT)
argv[argc] = 10 * argv[argc] + digit;
}
void Vt102Emulation::addArgument()
{
argc = qMin(argc+1,MAXARGS-1);
argv[argc] = 0;
argc = qMin(argc + 1, MAXARGS - 1);
argv[argc] = 0;
}
void Vt102Emulation::addToCurrentToken(int cc)
{
tokenBuffer[tokenBufferPos] = cc;
tokenBufferPos = qMin(tokenBufferPos+1,MAX_TOKEN_LENGTH-1);
tokenBuffer[tokenBufferPos] = cc;
tokenBufferPos = qMin(tokenBufferPos + 1, MAX_TOKEN_LENGTH - 1);
}
// Character Class flags used while decoding
#define CTL 1 // Control character
#define CHR 2 // Printable character
#define CPN 4 // TODO: Document me
#define DIG 8 // Digit
#define SCS 16 // TODO: Document me
#define GRP 32 // TODO: Document me
#define CPS 64 // Character which indicates end of window resize
// escape sequence '\e[8;<row>;<col>t'
const int CTL = 1; // Control character
const int CHR = 2; // Printable character
const int CPN = 4; // TODO: Document me
const int DIG = 8; // Digit
const int SCS = 16; // Select Character Set
const int GRP = 32; // TODO: Document me
const int CPS = 64; // Character which indicates end of window resize
void Vt102Emulation::initTokenizer()
{
int i;
quint8* s;
for(i = 0;i < 256; ++i)
charClass[i] = 0;
for(i = 0;i < 32; ++i)
charClass[i] |= CTL;
for(i = 32;i < 256; ++i)
charClass[i] |= CHR;
for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s)
charClass[*s] |= CPN;
// resize = \e[8;<row>;<col>t
for(s = (quint8*)"t"; *s; ++s)
charClass[*s] |= CPS;
for(s = (quint8*)"0123456789"; *s; ++s)
charClass[*s] |= DIG;
for(s = (quint8*)"()+*%"; *s; ++s)
charClass[*s] |= SCS;
for(s = (quint8*)"()+*#[]%"; *s; ++s)
charClass[*s] |= GRP;
int i;
quint8* s;
for (i = 0; i < 256; ++i)
charClass[i] = 0;
for (i = 0; i < 32; ++i)
charClass[i] |= CTL;
for (i = 32; i < 256; ++i)
charClass[i] |= CHR;
for (s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s)
charClass[*s] |= CPN;
// resize = \e[8;<row>;<col>t
for (s = (quint8*)"t"; *s; ++s)
charClass[*s] |= CPS;
for (s = (quint8*)"0123456789"; *s; ++s)
charClass[*s] |= DIG;
for (s = (quint8*)"()+*%"; *s; ++s)
charClass[*s] |= SCS;
for (s = (quint8*)"()+*#[]%"; *s; ++s)
charClass[*s] |= GRP;
resetTokenizer();
resetTokenizer();
}
/* Ok, here comes the nasty part of the decoder.
@ -267,13 +283,14 @@ void Vt102Emulation::initTokenizer()
#define Xte (Xpe && cc == 7 )
#define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte)
#define ESC 27
#define CNTL(c) ((c)-'@')
const int ESC = 27;
const int DEL = 127;
// process an incoming unicode character
void Vt102Emulation::receiveChar(int cc)
{
if (cc == 127)
if (cc == DEL)
return; //VT100: ignore.
if (ces(CTL))
@ -294,7 +311,7 @@ void Vt102Emulation::receiveChar(int cc)
addToCurrentToken(cc);
int* s = tokenBuffer;
int p = tokenBufferPos;
const int p = tokenBufferPos;
if (getMode(MODE_Ansi))
{
@ -323,27 +340,27 @@ void Vt102Emulation::receiveChar(int cc)
if (epe( )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; }
if (ees(DIG)) { addDigit(cc-'0'); return; }
if (eec(';')) { addArgument(); return; }
for (int i=0;i<=argc;i++)
for (int i = 0; i <= argc; i++)
{
if (epp())
processToken( TY_CSI_PR(cc,argv[i]), 0, 0);
processToken(TY_CSI_PR(cc,argv[i]), 0, 0);
else if (egt())
processToken( TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c
processToken(TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c
else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2)
{
// ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
i += 2;
processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
processToken(TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
i += 2;
}
else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5)
{
// ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
i += 2;
processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
processToken(TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
}
else
processToken( TY_CSI_PS(cc,argv[i]), 0, 0);
processToken(TY_CSI_PS(cc,argv[i]), 0, 0);
}
resetTokenizer();
}
@ -364,11 +381,11 @@ void Vt102Emulation::receiveChar(int cc)
return;
if (p < 4)
{
processToken( TY_VT52(s[1] ), 0, 0);
processToken(TY_VT52(s[1] ), 0, 0);
resetTokenizer();
return;
}
processToken( TY_VT52(s[1]), s[2], s[3]);
processToken(TY_VT52(s[1]), s[2], s[3]);
resetTokenizer();
return;
}
@ -418,7 +435,7 @@ void Vt102Emulation::updateTitle()
meaning is assigned to them. These are either operations of
the current _screen, or of the emulation class itself.
The token to be interpreteted comes in as a machine word
The token to be interpreted comes in as a machine word
possibly accompanied by two parameters.
Likewise, the operations assigned to, come with up to two
@ -433,7 +450,6 @@ void Vt102Emulation::processToken(int token, int p, int q)
{
switch (token)
{
case TY_CHR( ) : _currentScreen->displayCharacter (p ); break; //UTF16
// 127 DEL : ignored on input
@ -528,7 +544,9 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_ESC_DE('8' ) : _currentScreen->helpAlign ( ); break;
// resize = \e[8;<row>;<col>t
case TY_CSI_PS('t', 8) : setImageSize( q /* columns */, p /* lines */ ); break;
case TY_CSI_PS('t', 8) : setImageSize( p /*lines */, q /* columns */ );
emit imageResizeRequest(QSize(q, p));
break;
// change tab text color : \e[28;<color>t color: 0-16,777,215
case TY_CSI_PS('t', 28) : emit changeTabTextColorRequest ( p ); break;
@ -552,6 +570,7 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PS('m', 0) : _currentScreen->setDefaultRendition ( ); break;
case TY_CSI_PS('m', 1) : _currentScreen-> setRendition (RE_BOLD ); break; //VT100
//case TY_CSI_PS('m', 3) : _currentScreen-> setRendition (RE_ITALIC ); break; //VT100
case TY_CSI_PS('m', 4) : _currentScreen-> setRendition (RE_UNDERLINE); break; //VT100
case TY_CSI_PS('m', 5) : _currentScreen-> setRendition (RE_BLINK ); break; //VT100
case TY_CSI_PS('m', 7) : _currentScreen-> setRendition (RE_REVERSE ); break;
@ -559,6 +578,7 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX
case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX
case TY_CSI_PS('m', 22) : _currentScreen->resetRendition (RE_BOLD ); break;
//case TY_CSI_PS('m', 23) : _currentScreen->resetRendition (RE_ITALIC ); break; //VT100
case TY_CSI_PS('m', 24) : _currentScreen->resetRendition (RE_UNDERLINE); break;
case TY_CSI_PS('m', 25) : _currentScreen->resetRendition (RE_BLINK ); break;
case TY_CSI_PS('m', 27) : _currentScreen->resetRendition (RE_REVERSE ); break;
@ -622,6 +642,8 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PN('B' ) : _currentScreen->cursorDown (p ); break; //VT100
case TY_CSI_PN('C' ) : _currentScreen->cursorRight (p ); break; //VT100
case TY_CSI_PN('D' ) : _currentScreen->cursorLeft (p ); break; //VT100
case TY_CSI_PN('E' ) : /* Not implemented: cursor next p lines */ break; //VT100
case TY_CSI_PN('F' ) : /* Not implemented: cursor preceding p lines */ break; //VT100
case TY_CSI_PN('G' ) : _currentScreen->setCursorX (p ); break; //LINUX
case TY_CSI_PN('H' ) : _currentScreen->setCursorYX (p, q); break; //VT100
case TY_CSI_PN('I' ) : _currentScreen->tab (p ); break;
@ -645,8 +667,8 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100
case TY_CSI_PR('h', 3) : setMode (MODE_132Columns);break; //VT100
case TY_CSI_PR('l', 3) : resetMode (MODE_132Columns);break; //VT100
case TY_CSI_PR('h', 3) : setMode (MODE_132Columns); break; //VT100
case TY_CSI_PR('l', 3) : resetMode (MODE_132Columns); break; //VT100
case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100
case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100
@ -736,6 +758,21 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PR('s', 1003) : saveMode (MODE_Mouse1003); break; //XTERM
case TY_CSI_PR('r', 1003) : restoreMode (MODE_Mouse1003); break; //XTERM
case TY_CSI_PR('h', 1005) : setMode (MODE_Mouse1005); break; //XTERM
case TY_CSI_PR('l', 1005) : resetMode (MODE_Mouse1005); break; //XTERM
case TY_CSI_PR('s', 1005) : saveMode (MODE_Mouse1005); break; //XTERM
case TY_CSI_PR('r', 1005) : restoreMode (MODE_Mouse1005); break; //XTERM
case TY_CSI_PR('h', 1006) : setMode (MODE_Mouse1006); break; //XTERM
case TY_CSI_PR('l', 1006) : resetMode (MODE_Mouse1006); break; //XTERM
case TY_CSI_PR('s', 1006) : saveMode (MODE_Mouse1006); break; //XTERM
case TY_CSI_PR('r', 1006) : restoreMode (MODE_Mouse1006); break; //XTERM
case TY_CSI_PR('h', 1015) : setMode (MODE_Mouse1015); break; //URXVT
case TY_CSI_PR('l', 1015) : resetMode (MODE_Mouse1015); break; //URXVT
case TY_CSI_PR('s', 1015) : saveMode (MODE_Mouse1015); break; //URXVT
case TY_CSI_PR('r', 1015) : restoreMode (MODE_Mouse1015); break; //URXVT
case TY_CSI_PR('h', 1034) : /* IGNORED: 8bitinput activation */ break; //XTERM
case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM
@ -754,6 +791,11 @@ void Vt102Emulation::processToken(int token, int p, int q)
case TY_CSI_PR('h', 1049) : saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); break; //XTERM
case TY_CSI_PR('l', 1049) : resetMode(MODE_AppScreen); restoreCursor(); break; //XTERM
case TY_CSI_PR('h', 2004) : setMode (MODE_BracketedPaste); break; //XTERM
case TY_CSI_PR('l', 2004) : resetMode (MODE_BracketedPaste); break; //XTERM
case TY_CSI_PR('s', 2004) : saveMode (MODE_BracketedPaste); break; //XTERM
case TY_CSI_PR('r', 2004) : restoreMode (MODE_BracketedPaste); break; //XTERM
//FIXME: weird DEC reset sequence
case TY_CSI_PE('p' ) : /* IGNORED: reset ( ) */ break;
@ -797,13 +839,13 @@ void Vt102Emulation::sendString(const char* s , int length)
if ( length >= 0 )
emit sendData(s,length);
else
emit sendData(s,strlen(s));
emit sendData(s,qstrlen(s));
}
void Vt102Emulation::reportCursorPosition()
{
char tmp[20];
sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1);
snprintf(tmp, sizeof(tmp), "\033[%d;%dR", _currentScreen->getCursorY()+1, _currentScreen->getCursorX()+1);
sendString(tmp);
}
@ -822,7 +864,7 @@ void Vt102Emulation::reportTerminalType()
void Vt102Emulation::reportSecondaryAttributes()
{
// Seconday device attribute response (Request was: ^[[>0c or ^[[>c)
// Secondary device attribute response (Request was: ^[[>0c or ^[[>c)
if (getMode(MODE_Ansi))
sendString("\033[>0;115;0c"); // Why 115? ;)
else
@ -830,96 +872,137 @@ void Vt102Emulation::reportSecondaryAttributes()
// konsoles backward compatibility.
}
/* DECREPTPARM Report Terminal Parameters
ESC [ <sol>; <par>; <nbits>; <xspeed>; <rspeed>; <clkmul>; <flags> x
http://vt100.net/docs/vt100-ug/chapter3.html
*/
void Vt102Emulation::reportTerminalParms(int p)
// DECREPTPARM
{
char tmp[100];
sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true.
/*
sol=1: This message is a request; report in response to a request.
par=1: No parity set
nbits=1: 8 bits per character
xspeed=112: 9600
rspeed=112: 9600
clkmul=1: The bit rate multiplier is 16.
flags=0: None
*/
snprintf(tmp, sizeof(tmp), "\033[%d;1;1;112;112;1;0x", p); // not really true.
sendString(tmp);
}
void Vt102Emulation::reportStatus()
{
sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
}
void Vt102Emulation::reportAnswerBack()
{
// FIXME - Test this with VTTEST
// This is really obsolete VT100 stuff.
const char* ANSWER_BACK = "";
sendString(ANSWER_BACK);
// FIXME - Test this with VTTEST
// This is really obsolete VT100 stuff.
const char* ANSWER_BACK = "";
sendString(ANSWER_BACK);
}
/*!
`cx',`cy' are 1-based.
`eventType' indicates the button pressed (0-2)
or a general mouse release (3).
`cb' indicates the button pressed or released (0-2) or scroll event (4-5).
eventType represents the kind of mouse action that occurred:
0 = Mouse button press or release
0 = Mouse button press
1 = Mouse drag
2 = Mouse button release
*/
void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType )
void Vt102Emulation::sendMouseEvent(int cb, int cx, int cy , int eventType)
{
if (cx < 1 || cy < 1)
return;
if (cx < 1 || cy < 1)
return;
// normal buttons are passed as 0x20 + button,
// mouse wheel (buttons 4,5) as 0x5c + button
if (cb >= 4)
cb += 0x3c;
// With the exception of the 1006 mode, button release is encoded in cb.
// Note that if multiple extensions are enabled, the 1006 is used, so it's okay to check for only that.
if (eventType == 2 && !getMode(MODE_Mouse1006))
cb = 3;
//Mouse motion handling
if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1)
cb += 0x20; //add 32 to signify motion event
// normal buttons are passed as 0x20 + button,
// mouse wheel (buttons 4,5) as 0x5c + button
if (cb >= 4)
cb += 0x3c;
char command[20];
sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20);
sendString(command);
//Mouse motion handling
if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1)
cb += 0x20; //add 32 to signify motion event
char command[32];
command[0] = '\0';
// Check the extensions in decreasing order of preference. Encoding the release event above assumes that 1006 comes first.
if (getMode(MODE_Mouse1006)) {
snprintf(command, sizeof(command), "\033[<%d;%d;%d%c", cb, cx, cy, eventType == 2 ? 'm' : 'M');
} else if (getMode(MODE_Mouse1015)) {
snprintf(command, sizeof(command), "\033[%d;%d;%dM", cb + 0x20, cx, cy);
} else if (getMode(MODE_Mouse1005)) {
if (cx <= 2015 && cy <= 2015) {
// The xterm extension uses UTF-8 (up to 2 bytes) to encode
// coordinate+32, no matter what the locale is. We could easily
// convert manually, but QString can also do it for us.
QChar coords[2];
coords[0] = cx + 0x20;
coords[1] = cy + 0x20;
QString coordsStr = QString(coords, 2);
QByteArray utf8 = coordsStr.toUtf8();
snprintf(command, sizeof(command), "\033[M%c%s", cb + 0x20, (const char *)utf8);
}
} else if (cx <= 223 && cy <= 223) {
snprintf(command, sizeof(command), "\033[M%c%c%c", cb + 0x20, cx + 0x20, cy + 0x20);
}
sendString(command);
}
void Vt102Emulation::sendText( const QString& text )
void Vt102Emulation::sendText(const QString& text)
{
if (!text.isEmpty())
{
QKeyEvent event(QEvent::KeyPress,
0,
Qt::NoModifier,
text);
sendKeyEvent(&event); // expose as a big fat keypress event
}
if (!text.isEmpty()) {
QKeyEvent event(QEvent::KeyPress,
0,
Qt::NoModifier,
text);
sendKeyEvent(&event); // expose as a big fat keypress event
}
}
void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
void Vt102Emulation::sendKeyEvent(QKeyEvent* event)
{
Qt::KeyboardModifiers modifiers = event->modifiers();
const Qt::KeyboardModifiers modifiers = event->modifiers();
KeyboardTranslator::States states = KeyboardTranslator::NoState;
// get current states
if (getMode(MODE_NewLine) ) states |= KeyboardTranslator::NewLineState;
if (getMode(MODE_Ansi) ) states |= KeyboardTranslator::AnsiState;
if (getMode(MODE_NewLine)) states |= KeyboardTranslator::NewLineState;
if (getMode(MODE_Ansi)) states |= KeyboardTranslator::AnsiState;
if (getMode(MODE_AppCuKeys)) states |= KeyboardTranslator::CursorKeysState;
if (getMode(MODE_AppScreen)) states |= KeyboardTranslator::AlternateScreenState;
if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier))
states |= KeyboardTranslator::ApplicationKeypadState;
// check flow control state
if (modifiers & Qt::ControlModifier)
{
if (event->key() == Qt::Key_S)
if (modifiers & Qt::ControlModifier) {
switch (event->key()) {
case Qt::Key_S:
emit flowControlKeyPressed(true);
else if (event->key() == Qt::Key_Q)
break;
case Qt::Key_Q:
case Qt::Key_C: // cancel flow control
emit flowControlKeyPressed(false);
break;
}
}
// lookup key binding
if ( _keyTranslator )
{
KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
event->key() ,
modifiers,
states );
// look up key binding
if (_keyTranslator) {
KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
event->key() ,
modifiers,
states);
// send result to terminal
QByteArray textToSend;
@ -928,8 +1011,9 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
// Alt+[Character] results in Esc+[Character] being sent
// (unless there is an entry defined for this particular combination
// in the keyboard modifier)
bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier;
bool wantsAnyModifier = entry.state() &
const bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier;
const bool wantsMetaModifier = entry.modifiers() & entry.modifierMask() & Qt::MetaModifier;
const bool wantsAnyModifier = entry.state() &
entry.stateMask() & KeyboardTranslator::AnyModifierState;
if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier)
@ -937,13 +1021,18 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
{
textToSend.prepend("\033");
}
if ( modifiers & Qt::MetaModifier && !(wantsMetaModifier || wantsAnyModifier)
&& !event->text().isEmpty() )
{
textToSend.prepend("\030@s");
}
if ( entry.command() != KeyboardTranslator::NoCommand )
{
KTerminalDisplay* currentView = _currentScreen->currentTerminalDisplay();
if (entry.command() & KeyboardTranslator::EraseCommand)
KTerminalDisplay * currentView = _currentScreen->currentTerminalDisplay();
if (entry.command() & KeyboardTranslator::EraseCommand) {
textToSend += eraseChar();
else if (entry.command() & KeyboardTranslator::ScrollPageUpCommand)
} else if (entry.command() & KeyboardTranslator::ScrollPageUpCommand)
currentView->scrollScreenWindow(ScreenWindow::ScrollPages, -1);
else if (entry.command() & KeyboardTranslator::ScrollPageDownCommand)
currentView->scrollScreenWindow(ScreenWindow::ScrollPages, 1);
@ -951,28 +1040,31 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
currentView->scrollScreenWindow(ScreenWindow::ScrollLines, -1);
else if (entry.command() & KeyboardTranslator::ScrollLineDownCommand)
currentView->scrollScreenWindow(ScreenWindow::ScrollLines, 1);
// TODO command handling
// else if (entry.command() & KeyboardTranslator::ScrollUpToTopCommand)
// currentView->scrollScreenWindow(ScreenWindow::ScrollLines,
// - currentView->screenWindow()->currentLine());
// else if (entry.command() & KeyboardTranslator::ScrollDownToBottomCommand)
// currentView->scrollScreenWindow(ScreenWindow::ScrollLines, lineCount());
}
else if ( !entry.text().isEmpty() )
else if (!entry.text().isEmpty())
{
textToSend += _codec->fromUnicode(entry.text(true,modifiers));
}
else
textToSend += _codec->fromUnicode(event->text());
sendData( textToSend.constData() , textToSend.length() );
sendData(textToSend.constData(), textToSend.length());
}
else
{
// print an error message to the terminal if no key translator has been
// set
QString translatorError = tr("No keyboard translator available. "
"The information needed to convert key presses "
"into characters to send to the terminal "
"is missing.");
// 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() );
// receiveData(translatorError.toAscii().constData(), translatorError.count());
}
}
@ -1006,9 +1098,9 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
unsigned short Vt102Emulation::applyCharset(unsigned short c)
{
if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f];
if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete
return c;
if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c - 0x5f];
if (CHARSET.pound && c == '#') return 0xa3; //This mode is obsolete
return c;
}
/*
@ -1021,31 +1113,31 @@ unsigned short Vt102Emulation::applyCharset(unsigned short c)
void Vt102Emulation::resetCharset(int scrno)
{
_charset[scrno].cu_cs = 0;
strncpy(_charset[scrno].charset,"BBBB",4);
_charset[scrno].sa_graphic = false;
_charset[scrno].sa_pound = false;
_charset[scrno].graphic = false;
_charset[scrno].pound = false;
_charset[scrno].cu_cs = 0;
qstrncpy(_charset[scrno].charset, "BBBB", 4);
_charset[scrno].sa_graphic = false;
_charset[scrno].sa_pound = false;
_charset[scrno].graphic = false;
_charset[scrno].pound = false;
}
void Vt102Emulation::setCharset(int n, int cs) // on both screens.
{
_charset[0].charset[n&3] = cs; useCharset(_charset[0].cu_cs);
_charset[1].charset[n&3] = cs; useCharset(_charset[1].cu_cs);
_charset[0].charset[n & 3] = cs; useCharset(_charset[0].cu_cs);
_charset[1].charset[n & 3] = cs; useCharset(_charset[1].cu_cs);
}
void Vt102Emulation::setAndUseCharset(int n, int cs)
{
CHARSET.charset[n&3] = cs;
useCharset(n&3);
CHARSET.charset[n & 3] = cs;
useCharset(n & 3);
}
void Vt102Emulation::useCharset(int n)
{
CHARSET.cu_cs = n&3;
CHARSET.graphic = (CHARSET.charset[n&3] == '0');
CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete
CHARSET.cu_cs = n & 3;
CHARSET.graphic = (CHARSET.charset[n & 3] == '0');
CHARSET.pound = (CHARSET.charset[n & 3] == 'A'); //This mode is obsolete
}
void Vt102Emulation::setDefaultMargins()
@ -1056,25 +1148,25 @@ void Vt102Emulation::setDefaultMargins()
void Vt102Emulation::setMargins(int t, int b)
{
_screen[0]->setMargins(t, b);
_screen[1]->setMargins(t, b);
_screen[0]->setMargins(t, b);
_screen[1]->setMargins(t, b);
}
void Vt102Emulation::saveCursor()
{
CHARSET.sa_graphic = CHARSET.graphic;
CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete
// we are not clear about these
//sa_charset = charsets[cScreen->_charset];
//sa_charset_num = cScreen->_charset;
_currentScreen->saveCursor();
CHARSET.sa_graphic = CHARSET.graphic;
CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete
// we are not clear about these
//sa_charset = charsets[cScreen->_charset];
//sa_charset_num = cScreen->_charset;
_currentScreen->saveCursor();
}
void Vt102Emulation::restoreCursor()
{
CHARSET.graphic = CHARSET.sa_graphic;
CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete
_currentScreen->restoreCursor();
CHARSET.graphic = CHARSET.sa_graphic;
CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete
_currentScreen->restoreCursor();
}
/* ------------------------------------------------------------------------- */
@ -1099,27 +1191,30 @@ void Vt102Emulation::restoreCursor()
void Vt102Emulation::resetModes()
{
// MODE_Allow132Columns is not reset here
// to match Xterm's behaviour (see Xterm's VTReset() function)
// MODE_Allow132Columns is not reset here
// to match Xterm's behavior (see Xterm's VTReset() function)
resetMode(MODE_132Columns); saveMode(MODE_132Columns);
resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000);
resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001);
resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002);
resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003);
resetMode(MODE_132Columns); saveMode(MODE_132Columns);
resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000);
resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001);
resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002);
resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003);
resetMode(MODE_Mouse1005); saveMode(MODE_Mouse1005);
resetMode(MODE_Mouse1006); saveMode(MODE_Mouse1006);
resetMode(MODE_Mouse1015); saveMode(MODE_Mouse1015);
resetMode(MODE_BracketedPaste); saveMode(MODE_BracketedPaste);
resetMode(MODE_AppScreen); saveMode(MODE_AppScreen);
resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys);
resetMode(MODE_AppKeyPad); saveMode(MODE_AppKeyPad);
resetMode(MODE_NewLine);
setMode(MODE_Ansi);
resetMode(MODE_AppScreen); saveMode(MODE_AppScreen);
resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys);
resetMode(MODE_AppKeyPad); saveMode(MODE_AppKeyPad);
resetMode(MODE_NewLine);
setMode(MODE_Ansi);
}
void Vt102Emulation::setMode(int m)
{
_currentModes.mode[m] = true;
switch (m)
{
_currentModes.mode[m] = true;
switch (m) {
case MODE_132Columns:
if (getMode(MODE_Allow132Columns))
clearScreenAndSetColumns(132);
@ -1130,25 +1225,30 @@ void Vt102Emulation::setMode(int m)
case MODE_Mouse1001:
case MODE_Mouse1002:
case MODE_Mouse1003:
emit programUsesMouseChanged(false);
break;
emit programUsesMouseChanged(false);
break;
case MODE_AppScreen : _screen[1]->clearSelection();
setScreen(1);
break;
}
if (m < MODES_SCREEN || m == MODE_NewLine)
{
_screen[0]->setMode(m);
_screen[1]->setMode(m);
}
case MODE_BracketedPaste:
//emit programBracketedPasteModeChanged(true);
break;
case MODE_AppScreen :
_screen[1]->clearSelection();
setScreen(1);
break;
}
// FIXME: Currently this has a redundant condition as MODES_SCREEN is 6
// and MODE_NewLine is 5
if (m < MODES_SCREEN || m == MODE_NewLine) {
_screen[0]->setMode(m);
_screen[1]->setMode(m);
}
}
void Vt102Emulation::resetMode(int m)
{
_currentModes.mode[m] = false;
switch (m)
{
_currentModes.mode[m] = false;
switch (m) {
case MODE_132Columns:
if (getMode(MODE_Allow132Columns))
clearScreenAndSetColumns(80);
@ -1158,73 +1258,102 @@ void Vt102Emulation::resetMode(int m)
case MODE_Mouse1002 :
case MODE_Mouse1003 :
emit programUsesMouseChanged(true);
break;
break;
case MODE_BracketedPaste:
//emit programBracketedPasteModeChanged(false);
break;
case MODE_AppScreen :
_screen[0]->clearSelection();
setScreen(0);
break;
}
if (m < MODES_SCREEN || m == MODE_NewLine)
{
_screen[0]->resetMode(m);
_screen[1]->resetMode(m);
}
break;
}
// FIXME: Currently this has a redundant condition as MODES_SCREEN is 6
// and MODE_NewLine is 5
if (m < MODES_SCREEN || m == MODE_NewLine) {
_screen[0]->resetMode(m);
_screen[1]->resetMode(m);
}
}
void Vt102Emulation::saveMode(int m)
{
_savedModes.mode[m] = _currentModes.mode[m];
_savedModes.mode[m] = _currentModes.mode[m];
}
void Vt102Emulation::restoreMode(int m)
{
if (_savedModes.mode[m])
setMode(m);
else
resetMode(m);
if (_savedModes.mode[m])
setMode(m);
else
resetMode(m);
}
bool Vt102Emulation::getMode(int m)
{
return _currentModes.mode[m];
return _currentModes.mode[m];
}
char Vt102Emulation::eraseChar() const
{
KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
Qt::Key_Backspace,
0,
0);
if ( entry.text().count() > 0 )
return entry.text()[0];
else
return '\b';
KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
Qt::Key_Backspace,
0,
0);
if (entry.text().count() > 0)
return entry.text()[0];
else
return '\b';
}
#if 0
// print contents of the scan buffer
static void hexdump(int* s, int len)
{ int i;
for (i = 0; i < len; i++)
{
if (s[i] == '\\')
printf("\\\\");
else
if ((s[i]) > 32 && s[i] < 127)
printf("%c",s[i]);
else
printf("\\%04x(hex)",s[i]);
}
{
int i;
for (i = 0; i < len; i++) {
if (s[i] == '\\')
printf("\\\\");
else if ((s[i]) > 32 && s[i] < 127)
printf("%c", s[i]);
else
printf("\\%04x(hex)", s[i]);
}
}
#endif
// return contents of the scan buffer
static QString hexdump2(int* s, int len)
{
int i;
char dump[128];
QString returnDump;
for (i = 0; i < len; i++) {
if (s[i] == '\\')
snprintf(dump, sizeof(dump), "%s", "\\\\");
else if ((s[i]) > 32 && s[i] < 127)
snprintf(dump, sizeof(dump), "%c", s[i]);
else
snprintf(dump, sizeof(dump), "\\%04x(hex)", s[i]);
returnDump.append(QString(dump));
}
return returnDump;
}
void Vt102Emulation::reportDecodingError()
{
if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) )
return;
printf("Undecodable sequence: ");
hexdump(tokenBuffer,tokenBufferPos);
printf("\n");
if (tokenBufferPos == 0 || (tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32))
return;
// printf("Undecodable sequence: ");
// hexdump(tokenBuffer, tokenBufferPos);
// printf("\n");
QString outputError = QString("Undecodable sequence: ");
outputError.append(hexdump2(tokenBuffer, tokenBufferPos));
//kDebug() << outputError;
}
//#include "Vt102Emulation.moc"

View File

@ -23,19 +23,16 @@
#ifndef VT102EMULATION_H
#define VT102EMULATION_H
// Standard Library
#include <stdio.h>
// Qt
#include <QtGui/QKeyEvent>
#include <QtCore/QHash>
#include <QtCore/QTimer>
// Konsole
#include "Emulation.h"
#include "Screen.h"
#include "ScreenWindow.h"
#include "TerminalDisplay.h"
class QTimer;
class QKeyEvent;
#define MODE_AppScreen (MODES_SCREEN+0) // Mode #1
#define MODE_AppCuKeys (MODES_SCREEN+1) // Application cursor keys (DECCKM)
@ -44,21 +41,27 @@
#define MODE_Mouse1001 (MODES_SCREEN+4) // Use Hilight mouse tracking
#define MODE_Mouse1002 (MODES_SCREEN+5) // Use cell motion mouse tracking
#define MODE_Mouse1003 (MODES_SCREEN+6) // Use all motion mouse tracking
#define MODE_Ansi (MODES_SCREEN+7) // Use US Ascii for character sets G0-G3 (DECANM)
#define MODE_132Columns (MODES_SCREEN+8) // 80 <-> 132 column mode switch (DECCOLM)
#define MODE_Allow132Columns (MODES_SCREEN+9) // Allow DECCOLM mode
#define MODE_total (MODES_SCREEN+10)
#define MODE_Mouse1005 (MODES_SCREEN+7) // Xterm-style extended coordinates
#define MODE_Mouse1006 (MODES_SCREEN+8) // 2nd Xterm-style extended coordinates
#define MODE_Mouse1015 (MODES_SCREEN+9) // Urxvt-style extended coordinates
#define MODE_Ansi (MODES_SCREEN+10) // Use US Ascii for character sets G0-G3 (DECANM)
#define MODE_132Columns (MODES_SCREEN+11) // 80 <-> 132 column mode switch (DECCOLM)
#define MODE_Allow132Columns (MODES_SCREEN+12) // Allow DECCOLM mode
#define MODE_BracketedPaste (MODES_SCREEN+13) // Xterm-style bracketed paste mode
#define MODE_total (MODES_SCREEN+14)
struct CharCodes
namespace Konsole
{
// coding info
char charset[4]; //
int cu_cs; // actual charset.
bool graphic; // Some VT100 tricks
bool pound ; // Some VT100 tricks
bool sa_graphic; // saved graphic
bool sa_pound; // saved pound
extern unsigned short vt100_graphics[32];
struct CharCodes {
// coding info
char charset[4]; //
int cu_cs; // actual charset.
bool graphic; // Some VT100 tricks
bool pound; // Some VT100 tricks
bool sa_graphic; // saved graphic
bool sa_pound; // saved pound
};
/**
@ -73,118 +76,116 @@ struct CharCodes
*/
class Vt102Emulation : public Emulation
{
Q_OBJECT
Q_OBJECT
public:
/** Constructs a new emulation */
Vt102Emulation();
~Vt102Emulation();
/** Constructs a new emulation */
Vt102Emulation();
~Vt102Emulation();
// reimplemented from Emulation
virtual void clearEntireScreen();
virtual void reset();
virtual char eraseChar() const;
// reimplemented from Emulation
virtual void clearEntireScreen();
virtual void reset();
virtual char eraseChar() const;
public slots:
// reimplemented from Emulation
virtual void sendString(const char*,int length = -1);
virtual void sendText(const QString& text);
virtual void sendKeyEvent(QKeyEvent*);
virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
// reimplemented from Emulation
virtual void sendString(const char*, int length = -1);
virtual void sendText(const QString& text);
virtual void sendKeyEvent(QKeyEvent*);
virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
protected:
// reimplemented from Emulation
virtual void setMode(int mode);
virtual void resetMode(int mode);
virtual void receiveChar(int cc);
// reimplemented from Emulation
virtual void setMode(int mode);
virtual void resetMode(int mode);
virtual void receiveChar(int cc);
private slots:
//causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
//used to buffer multiple title updates
void updateTitle();
//causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
//used to buffer multiple title updates
void updateTitle();
private:
unsigned short applyCharset(unsigned short 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);
unsigned short applyCharset(unsigned short 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);
void setMargins(int top, int bottom);
//set margins for all screens back to their defaults
void setDefaultMargins();
void setMargins(int top, int bottom);
//set margins for all screens back to their defaults
void setDefaultMargins();
// returns true if 'mode' is set or false otherwise
bool getMode (int mode);
// saves the current boolean value of 'mode'
void saveMode (int mode);
// restores the boolean value of 'mode'
void restoreMode(int mode);
// resets all modes
// (except MODE_Allow132Columns)
void resetModes();
// returns true if 'mode' is set or false otherwise
bool getMode(int mode);
// saves the current boolean value of 'mode'
void saveMode(int mode);
// restores the boolean value of 'mode'
void restoreMode(int mode);
// resets all modes
// (except MODE_Allow132Columns)
void resetModes();
void resetTokenizer();
#define MAX_TOKEN_LENGTH 80
void addToCurrentToken(int cc);
int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow?
int tokenBufferPos;
void resetTokenizer();
#define MAX_TOKEN_LENGTH 256 // Max length of tokens (e.g. window title)
void addToCurrentToken(int cc);
int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow?
int tokenBufferPos;
#define MAXARGS 15
void addDigit(int dig);
void addArgument();
int argv[MAXARGS];
int argc;
void initTokenizer();
void addDigit(int dig);
void addArgument();
int argv[MAXARGS];
int argc;
void initTokenizer();
// Set of flags for each of the ASCII characters which indicates
// what category they fall into (printable character, control, digit etc.)
// for the purposes of decoding terminal output
int charClass[256];
// Set of flags for each of the ASCII characters which indicates
// what category they fall into (printable character, control, digit etc.)
// for the purposes of decoding terminal output
int charClass[256];
void reportDecodingError();
void reportDecodingError();
void processToken(int code, int p, int q);
void processWindowAttributeChange();
void processToken(int code, int p, int q);
void processWindowAttributeChange();
void reportTerminalType();
void reportSecondaryAttributes();
void reportStatus();
void reportAnswerBack();
void reportCursorPosition();
void reportTerminalParms(int p);
void reportTerminalType();
void reportSecondaryAttributes();
void reportStatus();
void reportAnswerBack();
void reportCursorPosition();
void reportTerminalParms(int p);
void onScrollLock();
void scrollLock(const bool lock);
// clears the screen and resizes it to the specified
// number of columns
void clearScreenAndSetColumns(int columnCount);
// clears the screen and resizes it to the specified
// number of columns
void clearScreenAndSetColumns(int columnCount);
CharCodes _charset[2];
CharCodes _charset[2];
class TerminalState
{
public:
// Initializes all modes to false
TerminalState() {
memset(&mode, false, MODE_total * sizeof(bool));
}
class TerminalState
{
public:
// Initializes all modes to false
TerminalState()
{ memset(&mode,false,MODE_total * sizeof(bool)); }
bool mode[MODE_total];
};
bool mode[MODE_total];
};
TerminalState _currentModes;
TerminalState _savedModes;
TerminalState _currentModes;
TerminalState _savedModes;
//hash table and timer for buffering calls to the session instance
//to update the name of the session
//or window title.
//these calls occur when certain escape sequences are seen in the
//output from the terminal
QHash<int,QString> _pendingTitleUpdates;
QTimer* _titleUpdateTimer;
//hash table and timer for buffering calls to the session instance
//to update the name of the session
//or window title.
//these calls occur when certain escape sequences are seen in the
//output from the terminal
QHash<int, QString> _pendingTitleUpdates;
QTimer* _titleUpdateTimer;
};
}
#endif // VT102EMULATION_H