Skip to content

Commit

Permalink
Adds SGR-Pixels support (VT sequence SM ? 1016 h / RM ? 1016 l). C…
Browse files Browse the repository at this point in the history
…loses #574.
  • Loading branch information
christianparpart committed Jan 9, 2022
1 parent 0b67a61 commit 37f22a3
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 72 deletions.
3 changes: 2 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
- Adds new configuration option `platform_plugin`.
- Adds new configuration option `renderer` for explicitly setting renderer to one of: `OpenGL`, `software`, `default`.
- Adds `mock` font locator.
- Adds VT sequence `SM ? 8452 h` and `RM ? 8452 l` for enabling/disabling sixel cursor placement conformance (xterm extension).
- Adds VT sequence `SM ? 8452 h` / `RM ? 8452 l` for enabling/disabling sixel cursor placement conformance (xterm extension).
- Adds SGR-Pixels support, VT sequence `SM ? 1016 h` / `RM ? 1016 l` (#574).
- Fixes VT sequence OSC 4's response.
- Fixes an assertion in text renderer.
- Fixes wrongly advertising DEC locator mode (it is not supported).
Expand Down
30 changes: 18 additions & 12 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,15 @@ void TerminalSession::sendCharPressEvent(char32_t _value, Modifier _modifier, Ti
terminal().sendCharPressEvent(_value, _modifier, _now); // TODO: get rid of Event{} struct here, too!
}

void TerminalSession::sendMousePressEvent(MouseButton _button, Modifier _modifier, Timestamp _now)
void TerminalSession::sendMousePressEvent(Modifier _modifier,
MouseButton _button,
MousePixelPosition _pixelPosition,
Timestamp _now)
{
// LOGSTORE(InputLog)("sendMousePressEvent: {} {} at {}", _button, _modifier, currentMousePosition_);

// First try to pass the mouse event to the application, as it might have requested that.
if (terminal().sendMousePressEvent(_button, _modifier, _now))
if (terminal().sendMousePressEvent(_modifier, _button, _pixelPosition, _now))
{
scheduleRedraw();
return;
Expand All @@ -460,34 +463,37 @@ void TerminalSession::sendMousePressEvent(MouseButton _button, Modifier _modifie
scheduleRedraw();
}

void TerminalSession::sendMouseMoveEvent(terminal::Coordinate _pos,
terminal::Modifier _modifier,
void TerminalSession::sendMouseMoveEvent(terminal::Modifier _modifier,
terminal::Coordinate _pos,
terminal::MousePixelPosition _pixelPosition,
Timestamp _now)
{
auto const handled = terminal().sendMouseMoveEvent(_modifier, _pos, _pixelPosition, _now);

if (_pos == currentMousePosition_)
return;

currentMousePosition_ = _pos;

auto const handled = terminal().sendMouseMoveEvent(_pos, _modifier, _now);

bool const mouseHoveringHyperlink = terminal().isMouseHoveringHyperlink();
currentMousePosition_ = _pos;
if (mouseHoveringHyperlink)
display_->setMouseCursorShape(MouseCursorShape::PointingHand);
else
setDefaultCursor();

if (mouseHoveringHyperlink || handled
|| terminal().isSelectionInProgress()) // && only if selection has changed!
// TODO: enter this if only if: `&& only if selection has changed!`
if (mouseHoveringHyperlink || handled || terminal().isSelectionInProgress())
{
terminal().breakLoopAndRefreshRenderBuffer();
scheduleRedraw();
}
}

void TerminalSession::sendMouseReleaseEvent(MouseButton _button, Modifier _modifier, Timestamp _now)
void TerminalSession::sendMouseReleaseEvent(Modifier _modifier,
MouseButton _button,
MousePixelPosition _pixelPosition,
Timestamp _now)
{
terminal().sendMouseReleaseEvent(_button, _modifier, _now);
terminal().sendMouseReleaseEvent(_modifier, _button, _pixelPosition, _now);
scheduleRedraw();
}

Expand Down
17 changes: 14 additions & 3 deletions src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,20 @@ class TerminalSession: public terminal::Terminal::Events
using Timestamp = std::chrono::steady_clock::time_point;
void sendKeyPressEvent(terminal::Key _key, terminal::Modifier _modifier, Timestamp _now);
void sendCharPressEvent(char32_t _value, terminal::Modifier _modifier, Timestamp _now);
void sendMousePressEvent(terminal::MouseButton _button, terminal::Modifier _modifier, Timestamp _now);
void sendMouseMoveEvent(terminal::Coordinate _pos, terminal::Modifier _modifier, Timestamp _now);
void sendMouseReleaseEvent(terminal::MouseButton _button, terminal::Modifier _modifier, Timestamp _now);

void sendMousePressEvent(terminal::Modifier _modifier,
terminal::MouseButton _button,
terminal::MousePixelPosition _pixelPosition,
Timestamp _now);
void sendMouseMoveEvent(terminal::Modifier _modifier,
terminal::Coordinate _pos,
terminal::MousePixelPosition _pixelPosition,
Timestamp _now);
void sendMouseReleaseEvent(terminal::Modifier _modifier,
terminal::MouseButton _button,
terminal::MousePixelPosition _pixelPosition,
Timestamp _now);

void sendFocusInEvent();
void sendFocusOutEvent();

Expand Down
37 changes: 31 additions & 6 deletions src/contour/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,32 @@ using crispy::Zero;

using terminal::Height;
using terminal::ImageSize;
using terminal::MousePixelPosition;
using terminal::PageSize;
using terminal::Width;

namespace contour
{

namespace
{

MousePixelPosition makeMousePixelPosition(QMouseEvent* _event) noexcept
{
// TODO: apply margin once supported
return MousePixelPosition { MousePixelPosition::X { _event->x() },
MousePixelPosition::Y { _event->y() } };
}

MousePixelPosition makeMousePixelPosition(QWheelEvent* _event) noexcept
{
// TODO: apply margin once supported
return MousePixelPosition { MousePixelPosition::X { _event->x() },
MousePixelPosition::Y { _event->y() } };
}

} // namespace

QScreen* screenOf(QWidget const* _widget)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
Expand Down Expand Up @@ -225,21 +245,25 @@ void sendWheelEvent(QWheelEvent* _event, TerminalSession& _session)

auto const modifier = makeModifier(_event->modifiers());

_session.sendMousePressEvent(button, modifier, steady_clock::now());
_session.sendMousePressEvent(modifier, button, makeMousePixelPosition(_event), steady_clock::now());
}
}

void sendMousePressEvent(QMouseEvent* _event, TerminalSession& _session)
{
_session.sendMousePressEvent(
makeMouseButton(_event->button()), makeModifier(_event->modifiers()), steady_clock::now());
_session.sendMousePressEvent(makeModifier(_event->modifiers()),
makeMouseButton(_event->button()),
makeMousePixelPosition(_event),
steady_clock::now());
_event->accept();
}

void sendMouseReleaseEvent(QMouseEvent* _event, TerminalSession& _session)
{
_session.sendMouseReleaseEvent(
makeMouseButton(_event->button()), makeModifier(_event->modifiers()), steady_clock::now());
_session.sendMouseReleaseEvent(makeModifier(_event->modifiers()),
makeMouseButton(_event->button()),
makeMousePixelPosition(_event),
steady_clock::now());
_event->accept();
}

Expand All @@ -258,7 +282,8 @@ void sendMouseMoveEvent(QMouseEvent* _event, TerminalSession& _session)
clamp((_event->pos().x() - MarginLeft) / cellSize.width.as<int>(), 0, *pageSize.columns - 1));
auto const pos = terminal::Coordinate { row, col };

_session.sendMouseMoveEvent(pos, makeModifier(_event->modifiers()), steady_clock::now());
_session.sendMouseMoveEvent(
makeModifier(_event->modifiers()), pos, makeMousePixelPosition(_event), steady_clock::now());
}

void spawnNewTerminal(string const& _programPath,
Expand Down
72 changes: 42 additions & 30 deletions src/terminal/InputGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,10 +521,11 @@ namespace
}
} // namespace

bool InputGenerator::generateMouse(MouseButton _button,
bool InputGenerator::generateMouse(MouseEventType _eventType,
Modifier _modifier,
MouseButton _button,
Coordinate _pos,
MouseEventType _eventType)
MousePixelPosition _pixelPosition)
{
if (!mouseProtocol_.has_value())
return false;
Expand All @@ -537,15 +538,15 @@ bool InputGenerator::generateMouse(MouseButton _button,
{
case MouseProtocol::X10: // Old X10 mouse protocol
if (_eventType == MouseEventType::Press)
mouseTransport(buttonX10(_button), modifierBits(_modifier), _pos, _eventType);
mouseTransport(_eventType, buttonX10(_button), modifierBits(_modifier), _pos, _pixelPosition);
return true;
case MouseProtocol::NormalTracking: // Normal tracking mode, that's X10 with mouse release events and
// modifiers
if (_eventType == MouseEventType::Press || _eventType == MouseEventType::Release)
{
auto const button = mouseTransport_ != MouseTransport::SGR ? buttonNormal(_button, _eventType)
: buttonX10(_button);
mouseTransport(button, modifierBits(_modifier), _pos, _eventType);
mouseTransport(_eventType, button, modifierBits(_modifier), _pos, _pixelPosition);
}
return true;
case MouseProtocol::ButtonTracking: // Button-event tracking protocol.
Expand All @@ -558,7 +559,7 @@ bool InputGenerator::generateMouse(MouseButton _button,

uint8_t const draggableButton = _eventType == MouseEventType::Drag ? button + 0x20 : button;

mouseTransport(draggableButton, modifierBits(_modifier), _pos, _eventType);
mouseTransport(_eventType, draggableButton, modifierBits(_modifier), _pos, _pixelPosition);
return true;
}
return false;
Expand All @@ -570,7 +571,7 @@ bool InputGenerator::generateMouse(MouseButton _button,

uint8_t const draggableButton = _eventType == MouseEventType::Drag ? button + 0x20 : button;

mouseTransport(draggableButton, modifierBits(_modifier), _pos, _eventType);
mouseTransport(_eventType, draggableButton, modifierBits(_modifier), _pos, _pixelPosition);
}
return true;
case MouseProtocol::HighlightTracking: // Highlight mouse tracking
Expand All @@ -580,10 +581,11 @@ bool InputGenerator::generateMouse(MouseButton _button,
return false;
}

bool InputGenerator::mouseTransport(uint8_t _button,
bool InputGenerator::mouseTransport(MouseEventType _eventType,
uint8_t _button,
uint8_t _modifier,
Coordinate _pos,
MouseEventType _eventType)
MousePixelPosition _pixelPosition)
{
switch (mouseTransport_)
{
Expand All @@ -594,9 +596,12 @@ bool InputGenerator::mouseTransport(uint8_t _button,
// TODO (like Default but with UTF-8 encoded coords)
return false;
case MouseTransport::SGR: // mode: 1006
return mouseTransportSGR(_button, _modifier, _pos, _eventType);
return mouseTransportSGR(_eventType, _button, _modifier, *_pos.column + 1, *_pos.line + 1);
case MouseTransport::URXVT: // mode: 1015
return mouseTransportURXVT(_button, _modifier, _pos, _eventType);
return mouseTransportURXVT(_eventType, _button, _modifier, _pos);
case MouseTransport::SGRPixels: // mode: 1016
return mouseTransportSGR(
_eventType, _button, _modifier, _pixelPosition.x.value, _pixelPosition.y.value);
}

return false;
Expand All @@ -622,26 +627,24 @@ bool InputGenerator::mouseTransportX10(uint8_t _button, uint8_t _modifier, Coord
return false;
}

bool InputGenerator::mouseTransportSGR(uint8_t _button,
uint8_t _modifier,
Coordinate _pos,
MouseEventType _eventType)
bool InputGenerator::mouseTransportSGR(
MouseEventType _eventType, uint8_t _button, uint8_t _modifier, int x, int y)
{
append("\033[<");
append(static_cast<unsigned>(_button | _modifier));
append(';');
append(static_cast<unsigned>(*_pos.column + 1));
append(static_cast<unsigned>(x));
append(';');
append(static_cast<unsigned>(*_pos.line + 1));
append(static_cast<unsigned>(y));
append(_eventType != MouseEventType::Release ? 'M' : 'm');

return true;
}

bool InputGenerator::mouseTransportURXVT(uint8_t _button,
bool InputGenerator::mouseTransportURXVT(MouseEventType _eventType,
uint8_t _button,
uint8_t _modifier,
Coordinate _pos,
MouseEventType _eventType)
Coordinate _pos)
{
if (_eventType == MouseEventType::Press)
{
Expand All @@ -656,7 +659,10 @@ bool InputGenerator::mouseTransportURXVT(uint8_t _button,
return true;
}

bool InputGenerator::generateMousePress(MouseButton _button, Modifier _modifier, Coordinate _pos)
bool InputGenerator::generateMousePress(Modifier _modifier,
MouseButton _button,
Coordinate _pos,
MousePixelPosition _pixelPosition)
{
auto const logged = [=](bool success) -> bool {
if (success)
Expand Down Expand Up @@ -694,10 +700,14 @@ bool InputGenerator::generateMousePress(MouseButton _button, Modifier _modifier,
if (!currentlyPressedMouseButtons_.count(_button))
currentlyPressedMouseButtons_.insert(_button);

return logged(generateMouse(_button, _modifier, currentMousePosition_, MouseEventType::Press));
return logged(
generateMouse(MouseEventType::Press, _modifier, _button, currentMousePosition_, _pixelPosition));
}

bool InputGenerator::generateMouseRelease(MouseButton _button, Modifier _modifier, Coordinate _pos)
bool InputGenerator::generateMouseRelease(Modifier _modifier,
MouseButton _button,
Coordinate _pos,
MousePixelPosition _pixelPosition)
{
auto const logged = [=](bool success) -> bool {
if (success)
Expand All @@ -710,20 +720,21 @@ bool InputGenerator::generateMouseRelease(MouseButton _button, Modifier _modifie
if (auto i = currentlyPressedMouseButtons_.find(_button); i != currentlyPressedMouseButtons_.end())
currentlyPressedMouseButtons_.erase(i);

return logged(generateMouse(_button, _modifier, currentMousePosition_, MouseEventType::Release));
return logged(
generateMouse(MouseEventType::Release, _modifier, _button, currentMousePosition_, _pixelPosition));
}

bool InputGenerator::generateMouseMove(Coordinate _pos, Modifier _modifier)
bool InputGenerator::generateMouseMove(Modifier _modifier, Coordinate _pos, MousePixelPosition _pixelPosition)
{
auto const logged = [=](bool success) -> bool {
if (success)
LOGSTORE(InputLog)("Sending mouse move at {} {}.", _pos, _modifier);
LOGSTORE(InputLog)("[{}:{}] Sending mouse move at {} ({}:{}).",
mouseProtocol_.value(),
mouseTransport_,
_pos, _pixelPosition.x.value, _pixelPosition.y.value);
return success;
};

if (_pos == currentMousePosition_)
return false;

currentMousePosition_ = _pos;

if (!mouseProtocol_.has_value())
Expand All @@ -736,11 +747,12 @@ bool InputGenerator::generateMouseMove(Coordinate _pos, Modifier _modifier)

if (report)
return logged(generateMouse(
MouseEventType::Drag,
_modifier,
buttonsPressed ? *currentlyPressedMouseButtons_.begin() // what if multiple are pressed?
: MouseButton::Release,
_modifier,
_pos,
MouseEventType::Drag));
_pixelPosition));

return false;
}
Expand Down
Loading

0 comments on commit 37f22a3

Please sign in to comment.