Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OSC 52 (copy-to-clipboard) #5823

Merged
14 commits merged into from
Jun 30, 2020
2 changes: 1 addition & 1 deletion src/cascadia/TerminalCore/TerminalDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ try
}
CATCH_LOG_RETURN_FALSE()

bool TerminalDispatch::CopyToClipboard(std::wstring_view content) noexcept
bool TerminalDispatch::SetClipboard(std::wstring_view content) noexcept
try
{
return _terminalApi.CopyToClipboard(content);
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalCore/TerminalDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc
bool SetColorTableEntry(const size_t tableIndex, const DWORD color) noexcept override;
bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept override;

bool CopyToClipboard(std::wstring_view content) noexcept override;
bool SetClipboard(std::wstring_view content) noexcept override;

bool SetDefaultForeground(const DWORD color) noexcept override;
bool SetDefaultBackground(const DWORD color) noexcept override;
Expand Down
13 changes: 0 additions & 13 deletions src/host/VtIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,16 +484,3 @@ bool VtIo::IsResizeQuirkEnabled() const
}
return S_OK;
}

// Method Description:
// - Process operating system control sequence.
// Arguments:
// - parameter: identifier of the OSC action to perform.
// - string: OSC string.
// Return Value:
// - S_OK if we successfully processed OSC or did nothing, else an
// appropriate HRESULT
[[nodiscard]] HRESULT VtIo::ProcessOsc(const size_t parameter, const std::wstring_view string)
{
return _pVtRenderEngine->ProcessOsc(parameter, string);
}
2 changes: 0 additions & 2 deletions src/host/VtIo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ namespace Microsoft::Console::VirtualTerminal
[[nodiscard]] HRESULT SuppressResizeRepaint();
[[nodiscard]] HRESULT SetCursorPosition(const COORD coordCursor);

[[nodiscard]] HRESULT ProcessOsc(const size_t parameter, const std::wstring_view string);

void CloseInput() override;
void CloseOutput() override;

Expand Down
18 changes: 0 additions & 18 deletions src/host/outputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

using namespace Microsoft::Console;
using Microsoft::Console::Interactivity::ServiceLocator;
using Microsoft::Console::Render::VtEngine;

WriteBuffer::WriteBuffer(_In_ Microsoft::Console::IIoProvider& io) :
_io{ io },
Expand Down Expand Up @@ -729,20 +728,3 @@ bool ConhostInternalGetSet::PrivateIsVtInputEnabled() const
{
return _io.GetActiveInputBuffer()->IsInVirtualTerminalInputMode();
}

// Routine Description:
// - Process copy-to-clipboard OSC.
// Arguments:
// - content - The content to copy to clipboard.
// Return Value:
// - true if not in VT mode or OSC was processed successfully, false otherwise.
bool ConhostInternalGetSet::CopyToClipboard(std::wstring_view content)
{
HRESULT hr = S_OK;
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (gci.IsInVtIoMode())
{
hr = gci.GetVtIo()->ProcessOsc(VtEngine::OscActionCodes::CopyToClipboard, content);
}
return SUCCEEDED(hr);
}
2 changes: 0 additions & 2 deletions src/host/outputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::

bool PrivateIsVtInputEnabled() const override;

bool CopyToClipboard(const std::wstring_view content) override;

private:
Microsoft::Console::IIoProvider& _io;
};
30 changes: 0 additions & 30 deletions src/renderer/vt/VtSequences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "precomp.h"
#include "vtrenderer.hpp"
#include "../../inc/conattrs.hpp"
#include "../../types/inc/convert.hpp"

#pragma hdrstop
using namespace Microsoft::Console::Render;
Expand Down Expand Up @@ -437,32 +436,3 @@ using namespace Microsoft::Console::Render;
{
return _Write("\x1b[29m");
}

// Method Description:
// - Writes operating system control sequence
// Arguments:
// - parameter: identifier of the OSC action to perform
// - string: OSC string
// Return Value:
// - S_OK if we succeeded or OSC code was ignored, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT VtEngine::ProcessOsc(const size_t parameter, const std::wstring_view string) noexcept
{
HRESULT hr = S_OK;
std::string contentFormat;

switch (parameter)
{
case OscActionCodes::CopyToClipboard:
contentFormat = "\x1b]" + std::to_string(parameter) + ";" + ConvertToA(CP_UTF8, string) + "\x07";
break;
default:
break;
}

if (!contentFormat.empty())
{
hr = _Write(contentFormat);
}

return hr;
}
7 changes: 0 additions & 7 deletions src/renderer/vt/vtrenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ namespace Microsoft::Console::Render

[[nodiscard]] virtual HRESULT WriteTerminalW(const std::wstring_view str) noexcept = 0;

[[nodiscard]] HRESULT ProcessOsc(const size_t parameter, const std::wstring_view string) noexcept;

void SetTerminalOwner(Microsoft::Console::ITerminalOwner* const terminalOwner);
void BeginResizeRequest();
void EndResizeRequest();
Expand All @@ -112,11 +110,6 @@ namespace Microsoft::Console::Render

[[nodiscard]] virtual HRESULT ManuallyClearScrollback() noexcept;

enum OscActionCodes : unsigned int
{
CopyToClipboard = 52,
};

protected:
wil::unique_hfile _hFile;
std::string _buffer;
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/ITermDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
virtual bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) = 0; // DECSCUSR
virtual bool SetCursorColor(const COLORREF color) = 0; // OSCSetCursorColor, OSCResetCursorColor

virtual bool CopyToClipboard(std::wstring_view content) = 0; // OscCopyToClipboard
virtual bool SetClipboard(std::wstring_view content) = 0; // OscSetClipboard
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
virtual bool SetClipboard(std::wstring_view content) = 0; // OscSetClipboard
virtual bool SetClipboard(std::wstring_view content) = 0; // OSCSetClipboard

for naming consistency (when we inevitably get a tool that parses these comments)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Which is in the works back on the first page of pull requests :P)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


// DTTERM_WindowManipulation
virtual bool WindowManipulation(const DispatchTypes::WindowManipulationType function,
Expand Down
4 changes: 2 additions & 2 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2076,9 +2076,9 @@ bool AdaptDispatch::SetCursorColor(const COLORREF cursorColor)
// - content - The content to copy to clipboard. Must be null terminated.
// Return Value:
// - True if handled successfully. False otherwise.
bool AdaptDispatch::CopyToClipboard(const std::wstring_view content)
bool AdaptDispatch::SetClipboard(const std::wstring_view /*content*/)
{
return _pConApi->CopyToClipboard(content);
return false;
}

// Method Description:
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/adaptDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ namespace Microsoft::Console::VirtualTerminal
bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) override; // DECSCUSR
bool SetCursorColor(const COLORREF cursorColor) override;

bool CopyToClipboard(const std::wstring_view content) override; // OscCopyToClipboard
bool SetClipboard(const std::wstring_view content) override; // OscSetClipboard

bool SetColorTableEntry(const size_t tableIndex,
const DWORD color) override; // OscColorTable
Expand Down
2 changes: 0 additions & 2 deletions src/terminal/adapter/conGetSet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,5 @@ namespace Microsoft::Console::VirtualTerminal
const std::optional<SMALL_RECT> clipRect,
const COORD destinationOrigin,
const bool standardFillAttrs) = 0;

virtual bool CopyToClipboard(const std::wstring_view content) = 0;
};
}
2 changes: 1 addition & 1 deletion src/terminal/adapter/termDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons
bool SetCursorStyle(const DispatchTypes::CursorStyle /*cursorStyle*/) noexcept override { return false; } // DECSCUSR
bool SetCursorColor(const COLORREF /*color*/) noexcept override { return false; } // OSCSetCursorColor, OSCResetCursorColor

bool CopyToClipboard(std::wstring_view /*content*/) noexcept override { return false; } // OscCopyToClipboard
bool SetClipboard(std::wstring_view /*content*/) noexcept override { return false; } // OscSetClipboard

// DTTERM_WindowManipulation
bool WindowManipulation(const DispatchTypes::WindowManipulationType /*function*/,
Expand Down
5 changes: 0 additions & 5 deletions src/terminal/adapter/ut_adapter/adapterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,11 +690,6 @@ class TestGetSet final : public ConGetSet
_expectedScrollRegion.Bottom = (bottom > 0) ? rect->Bottom - 1 : rect->Bottom;
}

bool CopyToClipboard(const std::wstring_view /*content*/)
{
return true;
}

~TestGetSet()
{
}
Expand Down
76 changes: 63 additions & 13 deletions src/terminal/parser/OutputStateMachineEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@

#include "precomp.h"

#include <winrt/Windows.Security.Cryptography.h>
#include <winrt/Windows.Storage.Streams.h>

#include "stateMachine.hpp"
#include "OutputStateMachineEngine.hpp"

#include "ascii.hpp"
using namespace Microsoft::Console;
using namespace Microsoft::Console::VirtualTerminal;
using namespace winrt::Windows::Security::Cryptography;
using namespace winrt::Windows::Storage::Streams;

// takes ownership of pDispatch
OutputStateMachineEngine::OutputStateMachineEngine(std::unique_ptr<ITermDispatch> pDispatch) :
Expand Down Expand Up @@ -726,7 +731,8 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
{
bool success = false;
std::wstring title;
std::wstring copyContent;
std::wstring setClipboardContent;
bool queryClipboard = false;
size_t tableIndex = 0;
DWORD color = 0;

Expand All @@ -735,7 +741,7 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
case OscActionCodes::SetIconAndWindowTitle:
case OscActionCodes::SetWindowIcon:
case OscActionCodes::SetWindowTitle:
success = _GetOscString(string, title);
success = _GetOscTitle(string, title);
break;
case OscActionCodes::SetColor:
success = _GetOscSetColorTable(string, tableIndex, color);
Expand All @@ -745,8 +751,8 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
case OscActionCodes::SetCursorColor:
success = _GetOscSetColor(string, color);
break;
case OscActionCodes::CopyToClipboard:
success = _GetOscString(string, copyContent);
case OscActionCodes::SetClipboard:
success = _GetOscSetClipboard(string, setClipboardContent, queryClipboard);
break;
case OscActionCodes::ResetCursorColor:
// the console uses 0xffffffff as an "invalid color" value
Expand Down Expand Up @@ -784,8 +790,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
success = _dispatch->SetCursorColor(color);
TermTelemetry::Instance().Log(TermTelemetry::Codes::OSCSCC);
break;
case OscActionCodes::CopyToClipboard:
success = _dispatch->CopyToClipboard(copyContent);
case OscActionCodes::SetClipboard:
if (!queryClipboard)
{
success = _dispatch->SetClipboard(setClipboardContent);
}
TermTelemetry::Instance().Log(TermTelemetry::Codes::OSCSCC);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be the wrong TermTelemetry code!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked http://inwap.com/pdp10/ansicode.txt to find a proper name for that code, but failed. So I named it as OSCSCB where SCB means set clipboard. I didn't use SC because it's too generic and may cause conflict.

break;
case OscActionCodes::ResetCursorColor:
Expand Down Expand Up @@ -1197,16 +1206,16 @@ bool OutputStateMachineEngine::_VerifyDeviceAttributesParams(const std::basic_st
// Routine Description:
// - Null terminates, then returns, the string that we've collected as part of the OSC string.
// Arguments:
// - inString - Osc String input.
// - outString - Where to place the Osc String.
// - string - Osc String input
// - title - Where to place the Osc String to use as a title.
// Return Value:
// - True if there was a string to output.
bool OutputStateMachineEngine::_GetOscString(const std::wstring_view inString,
std::wstring& outString) const
// - True if there was a title to output. (a title with length=0 is still valid)
bool OutputStateMachineEngine::_GetOscTitle(const std::wstring_view string,
std::wstring& title) const
{
outString = inString;
title = string;

return !inString.empty();
return !string.empty();
}

// Routine Description:
Expand Down Expand Up @@ -1739,6 +1748,47 @@ bool OutputStateMachineEngine::_GetRepeatCount(std::basic_string_view<size_t> pa
return success;
}

// Routine Description:
// - Parse OscSetClipboard parameters with the format `Pc;Pd`. Currently the first parameter `Pc` is
// ignored. The second parameter `Pd` should be a valid base64 string or character `?`.
// Arguments:
// - string - Osc String input.
// - content - Content to set to clipboard.
// - queryClipboard - Whether to get clipboard content and return it to terminal with base64 encoded.
// Return Value:
// - True if there was a valid base64 string or the passed parameter was `?`.
bool OutputStateMachineEngine::_GetOscSetClipboard(const std::wstring_view string,
std::wstring& content,
bool& queryClipboard) const noexcept
{
bool success = false;
size_t pos = string.find(';');
if (pos != std::wstring_view::npos)
{
std::wstring_view substr = string.substr(pos + 1);
if (substr == L"?")
{
queryClipboard = true;
success = true;
}
else
{
try
{
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::hstring(substr));
auto reader = DataReader::FromBuffer(buffer);
content = reader.ReadString(buffer.Length());
success = true;
}
catch (...)
{
}
}
}

return success;
}

// Method Description:
// - Clears our last stored character. The last stored character is the last
// graphical character we printed, which is reset if any other action is
Expand Down
10 changes: 7 additions & 3 deletions src/terminal/parser/OutputStateMachineEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ namespace Microsoft::Console::VirtualTerminal
SetForegroundColor = 10,
SetBackgroundColor = 11,
SetCursorColor = 12,
CopyToClipboard = 52,
SetClipboard = 52,
ResetForegroundColor = 110, // Not implemented
ResetBackgroundColor = 111, // Not implemented
ResetCursorColor = 112,
Expand Down Expand Up @@ -192,8 +192,8 @@ namespace Microsoft::Console::VirtualTerminal
size_t& topMargin,
size_t& bottomMargin) const noexcept;

bool _GetOscString(const std::wstring_view inString,
std::wstring& outString) const;
bool _GetOscTitle(const std::wstring_view string,
std::wstring& title) const;

static constexpr size_t DefaultTabDistance = 1;
bool _GetTabDistance(const std::basic_string_view<size_t> parameters,
Expand Down Expand Up @@ -231,6 +231,10 @@ namespace Microsoft::Console::VirtualTerminal
bool _GetRepeatCount(const std::basic_string_view<size_t> parameters,
size_t& repeatCount) const noexcept;

bool OutputStateMachineEngine::_GetOscSetClipboard(const std::wstring_view string,
std::wstring& title,
bool& queryClipboard) const noexcept;

void _ClearLastChar() noexcept;
};
}
2 changes: 1 addition & 1 deletion src/terminal/parser/stateMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ static constexpr bool _isOscTerminationInitiator(const wchar_t wch) noexcept
// - True if it is. False if it isn't.
static constexpr bool _isOscInvalid(const wchar_t wch) noexcept
{
return (wch <= L'\x17' && wch != L'\x0a' && wch != L'\x0d') ||
return wch <= L'\x17' ||
wch == L'\x19' ||
(wch >= L'\x1c' && wch <= L'\x1f');
}
Expand Down
Loading