Skip to content

Commit

Permalink
Don't copy text if there's no selection (#2446)
Browse files Browse the repository at this point in the history
This commit also transitions our keybinding events and event handlers to a
TypedEventHandler model with an "event args" class, as specified in the
keybinding arguments specification (#1349). In short, every event can be marked
Handled independently, and a Handled event will stop bubbling out to the
terminal. An unhandled event will be passed off to the terminal as a standard
keypress.

This unifies our keybinding event model and provides a convenient place for
binding arguments to live.

Fixes #2285.
Related to #1349, #1142.
  • Loading branch information
zadjii-msft authored and DHowett committed Aug 16, 2019
1 parent c70fb49 commit 734fc1d
Show file tree
Hide file tree
Showing 14 changed files with 773 additions and 237 deletions.
13 changes: 13 additions & 0 deletions src/cascadia/TerminalApp/ActionArgs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"

#include "ActionArgs.h"

#include "ActionEventArgs.g.cpp"
#include "CopyTextArgs.g.cpp"
#include "NewTabWithProfileArgs.g.cpp"
#include "SwitchToTabArgs.g.cpp"
#include "ResizePaneArgs.g.cpp"
#include "MoveFocusArgs.g.cpp"
69 changes: 69 additions & 0 deletions src/cascadia/TerminalApp/ActionArgs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

// HEY YOU: When adding ActionArgs types, make sure to add the corresponding
// *.g.cpp to ActionArgs.cpp!
#include "ActionEventArgs.g.h"
#include "CopyTextArgs.g.h"
#include "NewTabWithProfileArgs.g.h"
#include "SwitchToTabArgs.g.h"
#include "ResizePaneArgs.g.h"
#include "MoveFocusArgs.g.h"

#include "../../cascadia/inc/cppwinrt_utils.h"

// Notes on defining ActionArgs and ActionEventArgs:
// * All properties specific to an action should be defined as an ActionArgs
// class that implements IActionArgs
// * ActionEventArgs holds a single IActionArgs. For events that don't need
// additional args, this can be nullptr.

namespace winrt::TerminalApp::implementation
{
struct ActionEventArgs : public ActionEventArgsT<ActionEventArgs>
{
ActionEventArgs() = default;
ActionEventArgs(const TerminalApp::IActionArgs& args) :
_ActionArgs{ args } {};
GETSET_PROPERTY(IActionArgs, ActionArgs, nullptr);
GETSET_PROPERTY(bool, Handled, false);
};

struct CopyTextArgs : public CopyTextArgsT<CopyTextArgs>
{
CopyTextArgs() = default;
GETSET_PROPERTY(bool, TrimWhitespace, false);
};

struct NewTabWithProfileArgs : public NewTabWithProfileArgsT<NewTabWithProfileArgs>
{
NewTabWithProfileArgs() = default;
GETSET_PROPERTY(int32_t, ProfileIndex, 0);
};

struct SwitchToTabArgs : public SwitchToTabArgsT<SwitchToTabArgs>
{
SwitchToTabArgs() = default;
GETSET_PROPERTY(int32_t, TabIndex, 0);
};

struct ResizePaneArgs : public ResizePaneArgsT<ResizePaneArgs>
{
ResizePaneArgs() = default;
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::Left);
};

struct MoveFocusArgs : public MoveFocusArgsT<MoveFocusArgs>
{
MoveFocusArgs() = default;
GETSET_PROPERTY(TerminalApp::Direction, Direction, TerminalApp::Direction::Left);
};

}

namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(ActionEventArgs);
}
54 changes: 54 additions & 0 deletions src/cascadia/TerminalApp/ActionArgs.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace TerminalApp
{
// An empty interface must specify an explicit [uuid] to ensure uniqueness.
// We also manually have to specify a "version" attribute to make the compiler happy.
[uuid("191C2BDE-1A60-4BAB-9765-D850F0EF2CAC")][version(1)] interface IActionArgs{};

interface IActionEventArgs
{
Boolean Handled;
IActionArgs ActionArgs { get; };
};

enum Direction
{
Left = 0,
Right,
Up,
Down
};

[default_interface] runtimeclass ActionEventArgs : IActionEventArgs
{
ActionEventArgs(IActionArgs args);
};

[default_interface] runtimeclass CopyTextArgs : IActionArgs
{
Boolean TrimWhitespace { get; };
};

[default_interface] runtimeclass NewTabWithProfileArgs : IActionArgs
{
Int32 ProfileIndex { get; };
};

[default_interface] runtimeclass SwitchToTabArgs : IActionArgs
{
Int32 TabIndex { get; };
};

[default_interface] runtimeclass ResizePaneArgs : IActionArgs
{
Direction Direction { get; };
};

[default_interface] runtimeclass MoveFocusArgs : IActionArgs
{
Direction Direction { get; };
};

}
56 changes: 32 additions & 24 deletions src/cascadia/TerminalApp/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,26 +655,27 @@ namespace winrt::TerminalApp::implementation
// Hook up the KeyBinding object's events to our handlers.
// They should all be hooked up here, regardless of whether or not
// there's an actual keychord for them.
bindings.NewTab([this]() { _OpenNewTab(std::nullopt); });
bindings.OpenNewTabDropdown([this]() { _OpenNewTabDropdown(); });
bindings.DuplicateTab([this]() { _DuplicateTabViewItem(); });
bindings.CloseTab([this]() { _CloseFocusedTab(); });
bindings.ClosePane([this]() { _CloseFocusedPane(); });
bindings.NewTabWithProfile([this](const auto index) { _OpenNewTab({ index }); });
bindings.ScrollUp([this]() { _Scroll(-1); });
bindings.ScrollDown([this]() { _Scroll(1); });
bindings.NextTab([this]() { _SelectNextTab(true); });
bindings.PrevTab([this]() { _SelectNextTab(false); });
bindings.SplitVertical([this]() { _SplitVertical(std::nullopt); });
bindings.SplitHorizontal([this]() { _SplitHorizontal(std::nullopt); });
bindings.ScrollUpPage([this]() { _ScrollPage(-1); });
bindings.ScrollDownPage([this]() { _ScrollPage(1); });
bindings.SwitchToTab([this](const auto index) { _SelectTab({ index }); });
bindings.OpenSettings([this]() { _OpenSettings(); });
bindings.ResizePane([this](const auto direction) { _ResizePane(direction); });
bindings.MoveFocus([this](const auto direction) { _MoveFocus(direction); });
bindings.CopyText([this](const auto trimWhitespace) { _CopyText(trimWhitespace); });
bindings.PasteText([this]() { _PasteText(); });

bindings.NewTab({ this, &App::_HandleNewTab });
bindings.OpenNewTabDropdown({ this, &App::_HandleOpenNewTabDropdown });
bindings.DuplicateTab({ this, &App::_HandleDuplicateTab });
bindings.CloseTab({ this, &App::_HandleCloseTab });
bindings.ClosePane({ this, &App::_HandleClosePane });
bindings.ScrollUp({ this, &App::_HandleScrollUp });
bindings.ScrollDown({ this, &App::_HandleScrollDown });
bindings.NextTab({ this, &App::_HandleNextTab });
bindings.PrevTab({ this, &App::_HandlePrevTab });
bindings.SplitVertical({ this, &App::_HandleSplitVertical });
bindings.SplitHorizontal({ this, &App::_HandleSplitHorizontal });
bindings.ScrollUpPage({ this, &App::_HandleScrollUpPage });
bindings.ScrollDownPage({ this, &App::_HandleScrollDownPage });
bindings.OpenSettings({ this, &App::_HandleOpenSettings });
bindings.PasteText({ this, &App::_HandlePasteText });
bindings.NewTabWithProfile({ this, &App::_HandleNewTabWithProfile });
bindings.SwitchToTab({ this, &App::_HandleSwitchToTab });
bindings.ResizePane({ this, &App::_HandleResizePane });
bindings.MoveFocus({ this, &App::_HandleMoveFocus });
bindings.CopyText({ this, &App::_HandleCopyText });
}

// Method Description:
Expand Down Expand Up @@ -1233,10 +1234,12 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - trimTrailingWhitespace: enable removing any whitespace from copied selection
// and get text to appear on separate lines.
void App::_CopyText(const bool trimTrailingWhitespace)
// Return Value:
// - true iff we we able to copy text (if a selection was active)
bool App::_CopyText(const bool trimTrailingWhitespace)
{
const auto control = _GetFocusedControl();
control.CopySelectionToClipboard(trimTrailingWhitespace);
return control.CopySelectionToClipboard(trimTrailingWhitespace);
}

// Method Description:
Expand All @@ -1261,13 +1264,18 @@ namespace winrt::TerminalApp::implementation
}

// Method Description:
// - Sets focus to the desired tab.
void App::_SelectTab(const int tabIndex)
// - Sets focus to the desired tab. Returns false if the provided tabIndex
// is greater than the number of tabs we have.
// Return Value:
// true iff we were able to select that tab index, false otherwise
bool App::_SelectTab(const int tabIndex)
{
if (tabIndex >= 0 && tabIndex < gsl::narrow_cast<decltype(tabIndex)>(_tabs.size()))
{
_SetFocusedTabIndex(tabIndex);
return true;
}
return false;
}

// Method Description:
Expand Down
28 changes: 26 additions & 2 deletions src/cascadia/TerminalApp/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ namespace winrt::TerminalApp::implementation
void _CloseFocusedTab();
void _CloseFocusedPane();
void _SelectNextTab(const bool bMoveRight);
void _SelectTab(const int tabIndex);
bool _SelectTab(const int tabIndex);

void _SetFocusedTabIndex(int tabIndex);
int _GetFocusedTabIndex() const;

void _Scroll(int delta);
void _CopyText(const bool trimTrailingWhitespace);
bool _CopyText(const bool trimTrailingWhitespace);
void _PasteText();
void _SplitVertical(const std::optional<GUID>& profileGuid);
void _SplitHorizontal(const std::optional<GUID>& profileGuid);
Expand Down Expand Up @@ -150,6 +150,30 @@ namespace winrt::TerminalApp::implementation
void _PasteFromClipboardHandler(const IInspectable& sender, const Microsoft::Terminal::TerminalControl::PasteFromClipboardEventArgs& eventArgs);

static void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Settings::KeyChord& keyChord);

#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
void _HandleNewTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleOpenNewTabDropdown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleDuplicateTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleCloseTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleClosePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleScrollUp(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleScrollDown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleNextTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandlePrevTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleSplitVertical(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleSplitHorizontal(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleScrollUpPage(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleScrollDownPage(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleOpenSettings(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandlePasteText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleNewTabWithProfile(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleSwitchToTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
#pragma endregion
};
}

Expand Down
Loading

0 comments on commit 734fc1d

Please sign in to comment.