mirror of
https://github.com/Swordfish90/cool-retro-term.git
synced 2025-02-07 13:41:27 +00:00
959 lines
23 KiB
C++
959 lines
23 KiB
C++
/**************************************************************************************************
|
|
* Copyright (c) 2012 Jørgen Lind
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
* associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all copies or
|
|
* substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
|
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
***************************************************************************************************/
|
|
|
|
#include "screen.h"
|
|
|
|
#include "line.h"
|
|
|
|
#include "controll_chars.h"
|
|
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QSocketNotifier>
|
|
#include <QtGui/QGuiApplication>
|
|
|
|
#include <QtQuick/QQuickItem>
|
|
#include <QtQuick/QQuickView>
|
|
#include <QtQml/QQmlComponent>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <float.h>
|
|
|
|
Screen::Screen(QObject *parent)
|
|
: QObject(parent)
|
|
, m_parser(this)
|
|
, m_timer_event_id(0)
|
|
, m_cursor_visible(true)
|
|
, m_cursor_visible_changed(false)
|
|
, m_cursor_blinking(true)
|
|
, m_cursor_blinking_changed(false)
|
|
, m_insert_mode(Replace)
|
|
, m_selection_valid(false)
|
|
, m_selection_moved(0)
|
|
, m_flash(false)
|
|
, m_cursor_changed(false)
|
|
, m_reset(false)
|
|
, m_application_cursor_key_mode(false)
|
|
{
|
|
connect(&m_pty, &YatPty::readyRead, this, &Screen::readData);
|
|
|
|
m_screen_stack.reserve(2);
|
|
|
|
m_cursor_stack << QPoint(0,0);
|
|
|
|
m_current_text_style.style = TextStyle::Normal;
|
|
m_current_text_style.forground = ColorPalette::DefaultForground;
|
|
m_current_text_style.background = ColorPalette::DefaultBackground;
|
|
|
|
connect(&m_pty, SIGNAL(hangupReceived()),qGuiApp, SLOT(quit()));
|
|
}
|
|
|
|
Screen::~Screen()
|
|
{
|
|
for (int i = 0; i < m_screen_stack.size(); i++) {
|
|
delete m_screen_stack.at(i);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
QColor Screen::screenBackground()
|
|
{
|
|
return QColor(Qt::black);
|
|
}
|
|
|
|
QColor Screen::defaultForgroundColor() const
|
|
{
|
|
return m_palette.normalColor(ColorPalette::DefaultForground);
|
|
}
|
|
|
|
QColor Screen::defaultBackgroundColor() const
|
|
{
|
|
return QColor(Qt::transparent);
|
|
}
|
|
|
|
void Screen::setHeight(int height)
|
|
{
|
|
if (!m_screen_stack.size()) {
|
|
m_screen_stack << new ScreenData(this);
|
|
}
|
|
|
|
ScreenData *data = current_screen_data();
|
|
int size_difference = data->height() - height;
|
|
|
|
if (!size_difference)
|
|
return;
|
|
|
|
data->setHeight(height);
|
|
|
|
if (size_difference > 0) {
|
|
if (current_cursor_y() > 0)
|
|
current_cursor_pos().ry()--;
|
|
}
|
|
|
|
m_pty.setHeight(height, height * 10);
|
|
dispatchChanges();
|
|
}
|
|
|
|
void Screen::setWidth(int width)
|
|
{
|
|
if (!m_screen_stack.size())
|
|
m_screen_stack << new ScreenData(this);
|
|
|
|
current_screen_data()->setWidth(width);
|
|
m_pty.setWidth(width, width * 10);
|
|
|
|
}
|
|
|
|
int Screen::width() const
|
|
{
|
|
return m_pty.size().width();
|
|
}
|
|
|
|
void Screen::saveScreenData()
|
|
{
|
|
ScreenData *new_data = new ScreenData(this);
|
|
QSize pty_size = m_pty.size();
|
|
new_data->setHeight(pty_size.height());
|
|
new_data->setWidth(pty_size.width());
|
|
|
|
for (int i = 0; i < new_data->height(); i++) {
|
|
current_screen_data()->at(i)->setVisible(false);
|
|
}
|
|
|
|
m_screen_stack << new_data;
|
|
|
|
setSelectionEnabled(false);
|
|
|
|
}
|
|
|
|
void Screen::restoreScreenData()
|
|
{
|
|
ScreenData *data = current_screen_data();
|
|
m_screen_stack.remove(m_screen_stack.size()-1);
|
|
delete data;
|
|
|
|
QSize pty_size = m_pty.size();
|
|
current_screen_data()->setHeight(pty_size.height());
|
|
current_screen_data()->setWidth(pty_size.width());
|
|
|
|
for (int i = 0; i < current_screen_data()->height(); i++) {
|
|
current_screen_data()->at(i)->setVisible(true);
|
|
}
|
|
|
|
setSelectionEnabled(false);
|
|
}
|
|
|
|
int Screen::height() const
|
|
{
|
|
return current_screen_data()->height();
|
|
}
|
|
|
|
void Screen::setInsertMode(InsertMode mode)
|
|
{
|
|
m_insert_mode = mode;
|
|
}
|
|
|
|
void Screen::setTextStyle(TextStyle::Style style, bool add)
|
|
{
|
|
if (add) {
|
|
m_current_text_style.style |= style;
|
|
} else {
|
|
m_current_text_style.style &= !style;
|
|
}
|
|
}
|
|
|
|
void Screen::resetStyle()
|
|
{
|
|
m_current_text_style.background = ColorPalette::DefaultBackground;
|
|
m_current_text_style.forground = ColorPalette::DefaultForground;
|
|
m_current_text_style.style = TextStyle::Normal;
|
|
}
|
|
|
|
TextStyle Screen::currentTextStyle() const
|
|
{
|
|
return m_current_text_style;
|
|
}
|
|
|
|
TextStyle Screen::defaultTextStyle() const
|
|
{
|
|
TextStyle style;
|
|
style.style = TextStyle::Normal;
|
|
style.forground = ColorPalette::DefaultForground;
|
|
style.background = ColorPalette::DefaultBackground;
|
|
return style;
|
|
}
|
|
|
|
QPoint Screen::cursorPosition() const
|
|
{
|
|
return QPoint(current_cursor_x(),current_cursor_y());
|
|
}
|
|
|
|
void Screen::moveCursorHome()
|
|
{
|
|
current_cursor_pos().setX(0);
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorTop()
|
|
{
|
|
current_cursor_pos().setY(0);
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorUp(int n_positions)
|
|
{
|
|
if (!current_cursor_pos().y())
|
|
return;
|
|
|
|
if (n_positions <= current_cursor_pos().y()) {
|
|
current_cursor_pos().ry() -= n_positions;
|
|
} else {
|
|
current_cursor_pos().ry() = 0;
|
|
}
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorDown()
|
|
{
|
|
current_cursor_pos().ry() += 1;
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorLeft()
|
|
{
|
|
current_cursor_pos().rx() -= 1;
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorRight(int n_positions)
|
|
{
|
|
current_cursor_pos().rx() += n_positions;
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursor(int x, int y)
|
|
{
|
|
if (x != 0)
|
|
x--;
|
|
if (y != 0)
|
|
y--;
|
|
current_cursor_pos().setX(x);
|
|
int height = this->height();
|
|
if (y >= height) {
|
|
current_cursor_pos().setY(height-1);
|
|
} else {
|
|
current_cursor_pos().setY(y);
|
|
}
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorToLine(int line)
|
|
{
|
|
current_cursor_pos().setY(line-1);
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::moveCursorToCharacter(int character)
|
|
{
|
|
current_cursor_pos().setX(character-1);
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::deleteCharacters(int characters)
|
|
{
|
|
switch (m_insert_mode) {
|
|
case Insert:
|
|
current_screen_data()->clearCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + characters -1);
|
|
break;
|
|
case Replace:
|
|
current_screen_data()->deleteCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + characters -1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Screen::setCursorVisible(bool visible)
|
|
{
|
|
m_cursor_visible = visible;
|
|
m_cursor_visible_changed = true;
|
|
}
|
|
|
|
bool Screen::cursorVisible()
|
|
{
|
|
return m_cursor_visible;
|
|
}
|
|
|
|
void Screen::setCursorBlinking(bool blinking)
|
|
{
|
|
m_cursor_blinking = blinking;
|
|
m_cursor_blinking_changed = true;
|
|
}
|
|
|
|
bool Screen::cursorBlinking()
|
|
{
|
|
return m_cursor_blinking;
|
|
}
|
|
|
|
void Screen::saveCursor()
|
|
{
|
|
QPoint point = current_cursor_pos();
|
|
m_cursor_stack << point;
|
|
}
|
|
|
|
void Screen::restoreCursor()
|
|
{
|
|
if (m_cursor_stack.size() <= 1)
|
|
return;
|
|
|
|
m_cursor_stack.remove(m_screen_stack.size()-1);
|
|
}
|
|
|
|
void Screen::replaceAtCursor(const QString &text)
|
|
{
|
|
if (m_selection_valid ) {
|
|
if (current_cursor_y() >= m_selection_start.y() && current_cursor_y() <= m_selection_end.y())
|
|
//don't need to schedule as event since it will only happen once
|
|
setSelectionEnabled(false);
|
|
}
|
|
|
|
if (current_cursor_x() + text.size() <= width()) {
|
|
Line *line = current_screen_data()->at(current_cursor_y());
|
|
line->replaceAtPos(current_cursor_x(), text, m_current_text_style);
|
|
current_cursor_pos().rx() += text.size();
|
|
} else {
|
|
for (int i = 0; i < text.size();) {
|
|
if (current_cursor_x() == width()) {
|
|
current_cursor_pos().setX(0);
|
|
lineFeed();
|
|
}
|
|
QString toLine = text.mid(i,current_screen_data()->width() - current_cursor_x());
|
|
Line *line = current_screen_data()->at(current_cursor_y());
|
|
line->replaceAtPos(current_cursor_x(),toLine, m_current_text_style);
|
|
i+= toLine.size();
|
|
current_cursor_pos().rx() += toLine.size();
|
|
}
|
|
}
|
|
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::insertEmptyCharsAtCursor(int len)
|
|
{
|
|
if (m_selection_valid) {
|
|
if (current_cursor_y() >= m_selection_start.y() && current_cursor_y() <= m_selection_end.y())
|
|
//don't need to schedule as event since it will only happen once
|
|
setSelectionEnabled(false);
|
|
}
|
|
|
|
Line *line = current_screen_data()->at(current_cursor_y());
|
|
QString empty(len, QChar(' '));
|
|
line->insertAtPos(current_cursor_x(), empty, defaultTextStyle());
|
|
}
|
|
|
|
void Screen::backspace()
|
|
{
|
|
current_cursor_pos().rx()--;
|
|
m_cursor_changed = true;
|
|
}
|
|
|
|
void Screen::eraseLine()
|
|
{
|
|
current_screen_data()->clearLine(current_cursor_y());
|
|
}
|
|
|
|
void Screen::eraseFromCursorPositionToEndOfLine()
|
|
{
|
|
current_screen_data()->clearToEndOfLine(current_cursor_y(), current_cursor_x());
|
|
}
|
|
|
|
void Screen::eraseFromCursorPosition(int n_chars)
|
|
{
|
|
current_screen_data()->clearCharacters(current_cursor_y(), current_cursor_x(), current_cursor_x() + n_chars - 1);
|
|
}
|
|
|
|
void Screen::eraseFromCurrentLineToEndOfScreen()
|
|
{
|
|
current_screen_data()->clearToEndOfScreen(current_cursor_y());
|
|
}
|
|
|
|
void Screen::eraseFromCurrentLineToBeginningOfScreen()
|
|
{
|
|
current_screen_data()->clearToBeginningOfScreen(current_cursor_y());
|
|
|
|
}
|
|
|
|
void Screen::eraseToCursorPosition()
|
|
{
|
|
qDebug() << "eraseToCursorPosition NOT IMPLEMENTED!";
|
|
}
|
|
|
|
void Screen::eraseScreen()
|
|
{
|
|
current_screen_data()->clear();
|
|
}
|
|
|
|
void Screen::setTextStyleColor(ushort color)
|
|
{
|
|
Q_ASSERT(color >= 30 && color < 50);
|
|
if (color < 38) {
|
|
m_current_text_style.forground = ColorPalette::Color(color - 30);
|
|
} else if (color == 39) {
|
|
m_current_text_style.forground = ColorPalette::DefaultForground;
|
|
} else if (color >= 40 && color < 48) {
|
|
m_current_text_style.background = ColorPalette::Color(color - 40);
|
|
} else if (color == 49) {
|
|
m_current_text_style.background = ColorPalette::DefaultBackground;
|
|
} else {
|
|
qDebug() << "Failed to set color";
|
|
}
|
|
}
|
|
|
|
const ColorPalette *Screen::colorPalette() const
|
|
{
|
|
return &m_palette;
|
|
}
|
|
|
|
void Screen::lineFeed()
|
|
{
|
|
int cursor_y = current_cursor_y();
|
|
if(cursor_y == current_screen_data()->scrollAreaEnd()) {
|
|
m_selection_start.ry()--;
|
|
m_selection_end.ry()--;
|
|
m_selection_moved = true;
|
|
moveLine(current_screen_data()->scrollAreaStart(),cursor_y);
|
|
} else {
|
|
current_cursor_pos().ry()++;
|
|
m_cursor_changed = true;
|
|
}
|
|
}
|
|
|
|
void Screen::reverseLineFeed()
|
|
{
|
|
int cursor_y = current_cursor_y();
|
|
if (cursor_y == current_screen_data()->scrollAreaStart()) {
|
|
m_selection_start.ry()++;
|
|
m_selection_end.ry()++;
|
|
m_selection_moved = true;
|
|
moveLine(current_screen_data()->scrollAreaEnd(), cursor_y);
|
|
} else {
|
|
current_cursor_pos().ry()--;
|
|
m_cursor_changed = true;
|
|
}
|
|
}
|
|
|
|
void Screen::insertLines(int count)
|
|
{
|
|
for (int i = 0; i < count; i++) {
|
|
moveLine(current_screen_data()->scrollAreaEnd(),current_cursor_y());
|
|
}
|
|
}
|
|
|
|
void Screen::deleteLines(int count)
|
|
{
|
|
for (int i = 0; i < count; i++) {
|
|
moveLine(current_cursor_y(),current_screen_data()->scrollAreaEnd());
|
|
}
|
|
|
|
}
|
|
|
|
void Screen::setScrollArea(int from, int to)
|
|
{
|
|
from--;
|
|
to--;
|
|
current_screen_data()->setScrollArea(from,to);
|
|
}
|
|
|
|
QPointF Screen::selectionAreaStart() const
|
|
{
|
|
return m_selection_start;
|
|
}
|
|
|
|
void Screen::setSelectionAreaStart(const QPointF &start)
|
|
{
|
|
bool emitChanged = m_selection_start != start;
|
|
m_selection_start = start;
|
|
setSelectionValidity();
|
|
if (emitChanged)
|
|
emit selectionAreaStartChanged();
|
|
}
|
|
|
|
QPointF Screen::selectionAreaEnd() const
|
|
{
|
|
return m_selection_end;
|
|
}
|
|
|
|
void Screen::setSelectionAreaEnd(const QPointF &end)
|
|
{
|
|
bool emitChanged = m_selection_end != end;
|
|
m_selection_end = end;
|
|
setSelectionValidity();
|
|
if (emitChanged)
|
|
emit selectionAreaEndChanged();
|
|
}
|
|
|
|
bool Screen::selectionEnabled() const
|
|
{
|
|
return m_selection_valid;
|
|
}
|
|
|
|
void Screen::setSelectionEnabled(bool enabled)
|
|
{
|
|
bool emitchanged = m_selection_valid != enabled;
|
|
m_selection_valid = enabled;
|
|
if (emitchanged)
|
|
emit selectionEnabledChanged();
|
|
}
|
|
|
|
void Screen::sendSelectionToClipboard() const
|
|
{
|
|
current_screen_data()->sendSelectionToClipboard(m_selection_start, m_selection_end, QClipboard::Clipboard);
|
|
}
|
|
|
|
void Screen::sendSelectionToSelection() const
|
|
{
|
|
current_screen_data()->sendSelectionToClipboard(m_selection_start, m_selection_end, QClipboard::Selection);
|
|
}
|
|
|
|
void Screen::pasteFromSelection()
|
|
{
|
|
m_pty.write(QGuiApplication::clipboard()->text(QClipboard::Selection).toUtf8());
|
|
}
|
|
|
|
void Screen::pasteFromClipboard()
|
|
{
|
|
m_pty.write(QGuiApplication::clipboard()->text(QClipboard::Clipboard).toUtf8());
|
|
}
|
|
|
|
void Screen::doubleClicked(const QPointF &clicked)
|
|
{
|
|
int start, end;
|
|
current_screen_data()->getDoubleClickSelectionArea(clicked, &start, &end);
|
|
setSelectionAreaStart(QPointF(start,clicked.y()));
|
|
setSelectionAreaEnd(QPointF(end,clicked.y()));
|
|
}
|
|
|
|
void Screen::setTitle(const QString &title)
|
|
{
|
|
m_title = title;
|
|
emit screenTitleChanged();
|
|
}
|
|
|
|
QString Screen::title() const
|
|
{
|
|
return m_title;
|
|
}
|
|
|
|
void Screen::scheduleFlash()
|
|
{
|
|
m_flash = true;
|
|
}
|
|
|
|
Line *Screen::at(int i) const
|
|
{
|
|
return current_screen_data()->at(i);
|
|
}
|
|
|
|
void Screen::printScreen() const
|
|
{
|
|
current_screen_data()->printStyleInformation();
|
|
}
|
|
|
|
void Screen::dispatchChanges()
|
|
{
|
|
if (m_reset) {
|
|
emit reset();
|
|
m_update_actions.clear();
|
|
m_reset = false;
|
|
} else {
|
|
qint16 begin_move = -1;
|
|
qint16 end_move = -1;
|
|
for (int i = 0; i < m_update_actions.size(); i++) {
|
|
UpdateAction action = m_update_actions.at(i);
|
|
switch(action.action) {
|
|
case UpdateAction::MoveLine: {
|
|
if (begin_move < 0) {
|
|
begin_move = qMin(action.to_line, action.from_line);
|
|
end_move = qMax(action.to_line, action.from_line);
|
|
} else
|
|
if (action.from_line > action.to_line) {
|
|
begin_move = qMin(action.to_line, begin_move);
|
|
end_move = qMax(action.from_line, end_move);
|
|
} else {
|
|
begin_move = qMin(action.from_line, begin_move);
|
|
end_move = qMax(action.to_line, end_move);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
qDebug() << "unhandeled UpdatAction in TerminalScreen";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (begin_move >= 0) {
|
|
current_screen_data()->updateIndexes(begin_move, end_move);
|
|
}
|
|
|
|
current_screen_data()->dispatchLineEvents();
|
|
emit dispatchTextSegmentChanges();
|
|
}
|
|
|
|
if (m_flash) {
|
|
m_flash = false;
|
|
emit flash();
|
|
}
|
|
|
|
if (m_cursor_changed) {
|
|
m_cursor_changed = false;
|
|
emit cursorPositionChanged(current_cursor_x(), current_cursor_y());
|
|
}
|
|
|
|
if (m_cursor_visible_changed) {
|
|
m_cursor_visible_changed = false;
|
|
emit cursorVisibleChanged();
|
|
}
|
|
|
|
if (m_cursor_blinking_changed) {
|
|
m_cursor_blinking_changed = false;
|
|
emit cursorBlinkingChanged();
|
|
|
|
}
|
|
|
|
if (m_selection_valid && m_selection_moved) {
|
|
if (m_selection_start.y() < 0 ||
|
|
m_selection_end.y() >= current_screen_data()->height()) {
|
|
setSelectionEnabled(false);
|
|
} else {
|
|
emit selectionAreaStartChanged();
|
|
emit selectionAreaEndChanged();
|
|
}
|
|
}
|
|
|
|
m_update_actions.clear();
|
|
}
|
|
|
|
void Screen::sendPrimaryDA()
|
|
{
|
|
m_pty.write(QByteArrayLiteral("\033[?6c"));
|
|
|
|
}
|
|
|
|
void Screen::sendSecondaryDA()
|
|
{
|
|
m_pty.write(QByteArrayLiteral("\033[>1;95;0c"));
|
|
}
|
|
|
|
void Screen::setCharacterMap(const QString &string)
|
|
{
|
|
m_character_map = string;
|
|
}
|
|
|
|
QString Screen::characterMap() const
|
|
{
|
|
return m_character_map;
|
|
}
|
|
|
|
void Screen::setApplicationCursorKeysMode(bool enable)
|
|
{
|
|
m_application_cursor_key_mode = enable;
|
|
}
|
|
|
|
bool Screen::applicationCursorKeyMode() const
|
|
{
|
|
return m_application_cursor_key_mode;
|
|
}
|
|
|
|
static bool hasControll(Qt::KeyboardModifiers modifiers)
|
|
{
|
|
#ifdef Q_OS_MAC
|
|
return modifiers & Qt::MetaModifier;
|
|
#else
|
|
return modifiers & Qt::ControlModifier;
|
|
#endif
|
|
}
|
|
|
|
static bool hasMeta(Qt::KeyboardModifiers modifiers)
|
|
{
|
|
#ifdef Q_OS_MAC
|
|
return modifiers & Qt::ControlModifier;
|
|
#else
|
|
return modifiers & Qt::MetaModifier;
|
|
#endif
|
|
}
|
|
|
|
void Screen::sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers)
|
|
{
|
|
/// UGH, this functions should be re-written
|
|
char escape = '\0';
|
|
char control = '\0';
|
|
char code = '\0';
|
|
QVector<ushort> parameters;
|
|
bool found = true;
|
|
|
|
switch(key) {
|
|
case Qt::Key_Up:
|
|
escape = C0::ESC;
|
|
if (m_application_cursor_key_mode)
|
|
control = C1_7bit::SS3;
|
|
else
|
|
control = C1_7bit::CSI;
|
|
|
|
code = 'A';
|
|
break;
|
|
case Qt::Key_Right:
|
|
escape = C0::ESC;
|
|
if (m_application_cursor_key_mode)
|
|
control = C1_7bit::SS3;
|
|
else
|
|
control = C1_7bit::CSI;
|
|
|
|
code = 'C';
|
|
break;
|
|
case Qt::Key_Down:
|
|
escape = C0::ESC;
|
|
if (m_application_cursor_key_mode)
|
|
control = C1_7bit::SS3;
|
|
else
|
|
control = C1_7bit::CSI;
|
|
|
|
code = 'B';
|
|
break;
|
|
case Qt::Key_Left:
|
|
escape = C0::ESC;
|
|
if (m_application_cursor_key_mode)
|
|
control = C1_7bit::SS3;
|
|
else
|
|
control = C1_7bit::CSI;
|
|
|
|
code = 'D';
|
|
break;
|
|
case Qt::Key_Insert:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(2);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_Delete:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(3);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_Home:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(1);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_End:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(4);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_PageUp:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(5);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_PageDown:
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
parameters.append(6);
|
|
code = '~';
|
|
break;
|
|
case Qt::Key_F1:
|
|
case Qt::Key_F2:
|
|
case Qt::Key_F3:
|
|
case Qt::Key_F4:
|
|
if (m_application_cursor_key_mode) {
|
|
parameters.append((key & 0xff) - 37);
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
code = '~';
|
|
}
|
|
break;
|
|
case Qt::Key_F5:
|
|
case Qt::Key_F6:
|
|
case Qt::Key_F7:
|
|
case Qt::Key_F8:
|
|
case Qt::Key_F9:
|
|
case Qt::Key_F10:
|
|
case Qt::Key_F11:
|
|
case Qt::Key_F12:
|
|
if (m_application_cursor_key_mode) {
|
|
parameters.append((key & 0xff) - 36);
|
|
escape = C0::ESC;
|
|
control = C1_7bit::CSI;
|
|
code = '~';
|
|
}
|
|
break;
|
|
case Qt::Key_Control:
|
|
case Qt::Key_Shift:
|
|
case Qt::Key_Alt:
|
|
case Qt::Key_AltGr:
|
|
return;
|
|
break;
|
|
default:
|
|
found = false;
|
|
}
|
|
|
|
if (found) {
|
|
int term_mods = 0;
|
|
if (modifiers & Qt::ShiftModifier)
|
|
term_mods |= 1;
|
|
if (modifiers & Qt::AltModifier)
|
|
term_mods |= 2;
|
|
if (modifiers & Qt::ControlModifier)
|
|
term_mods |= 4;
|
|
|
|
QByteArray toPty;
|
|
|
|
if (term_mods) {
|
|
term_mods++;
|
|
parameters.append(term_mods);
|
|
}
|
|
if (escape)
|
|
toPty.append(escape);
|
|
if (control)
|
|
toPty.append(control);
|
|
if (parameters.size()) {
|
|
for (int i = 0; i < parameters.size(); i++) {
|
|
if (i)
|
|
toPty.append(';');
|
|
toPty.append(QByteArray::number(parameters.at(i)));
|
|
}
|
|
}
|
|
if (code)
|
|
toPty.append(code);
|
|
m_pty.write(toPty);
|
|
|
|
} else {
|
|
QString verifiedText = text.simplified();
|
|
if (verifiedText.isEmpty()) {
|
|
switch (key) {
|
|
case Qt::Key_Return:
|
|
case Qt::Key_Enter:
|
|
verifiedText = "\r";
|
|
break;
|
|
case Qt::Key_Backspace:
|
|
verifiedText = "\010";
|
|
break;
|
|
case Qt::Key_Tab:
|
|
verifiedText = "\t";
|
|
break;
|
|
case Qt::Key_Control:
|
|
case Qt::Key_Meta:
|
|
case Qt::Key_Alt:
|
|
case Qt::Key_Shift:
|
|
return;
|
|
case Qt::Key_Space:
|
|
verifiedText = " ";
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
QByteArray to_pty;
|
|
QByteArray key_text;
|
|
if (hasControll(modifiers)) {
|
|
char key_char = verifiedText.toLocal8Bit().at(0);
|
|
key_text.append(key_char & 0x1F);
|
|
} else {
|
|
key_text = verifiedText.toUtf8();
|
|
}
|
|
|
|
if (modifiers & Qt::AltModifier) {
|
|
to_pty.append(C0::ESC);
|
|
}
|
|
|
|
if (hasMeta(modifiers)) {
|
|
to_pty.append(C0::ESC);
|
|
to_pty.append('@');
|
|
to_pty.append(FinalBytesNoIntermediate::Reserved3);
|
|
}
|
|
|
|
to_pty.append(key_text);
|
|
m_pty.write(to_pty);
|
|
}
|
|
}
|
|
|
|
YatPty *Screen::pty()
|
|
{
|
|
return &m_pty;
|
|
}
|
|
|
|
Line *Screen::line_at_cursor() const
|
|
{
|
|
return current_screen_data()->at(current_cursor_y());
|
|
}
|
|
|
|
void Screen::readData(const QByteArray &data)
|
|
{
|
|
m_parser.addData(data);
|
|
|
|
if (!m_timer_event_id)
|
|
m_timer_event_id = startTimer(3);
|
|
m_time_since_parsed.restart();
|
|
}
|
|
|
|
void Screen::moveLine(qint16 from, qint16 to)
|
|
{
|
|
current_screen_data()->moveLine(from,to);
|
|
scheduleMoveSignal(from,to);
|
|
}
|
|
|
|
void Screen::scheduleMoveSignal(qint16 from, qint16 to)
|
|
{
|
|
if (m_update_actions.size() &&
|
|
m_update_actions.last().action == UpdateAction::MoveLine &&
|
|
m_update_actions.last().from_line == from &&
|
|
m_update_actions.last().to_line == to) {
|
|
m_update_actions.last().count++;
|
|
} else {
|
|
m_update_actions << UpdateAction(UpdateAction::MoveLine, from, to, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void Screen::setSelectionValidity()
|
|
{
|
|
if (m_selection_end.y() > m_selection_start.y() ||
|
|
(m_selection_end.y() == m_selection_start.y() &&
|
|
m_selection_end.x() > m_selection_start.x())) {
|
|
setSelectionEnabled(true);
|
|
} else {
|
|
setSelectionEnabled(false);
|
|
}
|
|
}
|
|
|
|
|
|
void Screen::timerEvent(QTimerEvent *)
|
|
{
|
|
if (m_timer_event_id && m_time_since_parsed.elapsed() > 3) {
|
|
killTimer(m_timer_event_id);
|
|
m_timer_event_id = 0;
|
|
dispatchChanges();
|
|
}
|
|
}
|