Move CharToKeyEvents (and friends) into InteractivityBase (#9106)
These functions have a dependency on the "VT Redirected" versions of VkKeyScanW, MapVirtualKeyW and GetKeyState. Those implementations depend on the service locator and therefore the entire interactivity stack. This meant that anybody depending on just Types had to pull in **the entire host** worth of dependencies (!). Since these functions are only used in places where we have or are testing interactivity, it makes sense to consolidate them here.
This commit is contained in:
parent
42511265e5
commit
8f73145d9d
210
src/interactivity/base/EventSynthesis.cpp
Normal file
210
src/interactivity/base/EventSynthesis.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "../inc/EventSynthesis.hpp"
|
||||
#include "../../types/inc/convert.hpp"
|
||||
|
||||
#ifdef BUILD_ONECORE_INTERACTIVITY
|
||||
#include "../inc/VtApiRedirection.hpp"
|
||||
#endif
|
||||
|
||||
#pragma hdrstop
|
||||
|
||||
// TODO: MSFT 14150722 - can these const values be generated at
|
||||
// runtime without breaking compatibility?
|
||||
static constexpr WORD altScanCode = 0x38;
|
||||
static constexpr WORD leftShiftScanCode = 0x2A;
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> Microsoft::Console::Interactivity::CharToKeyEvents(const wchar_t wch,
|
||||
const unsigned int codepage)
|
||||
{
|
||||
const short invalidKey = -1;
|
||||
short keyState = VkKeyScanW(wch);
|
||||
|
||||
if (keyState == invalidKey)
|
||||
{
|
||||
// Determine DBCS character because these character does not know by VkKeyScan.
|
||||
// GetStringTypeW(CT_CTYPE3) & C3_ALPHA can determine all linguistic characters. However, this is
|
||||
// not include symbolic character for DBCS.
|
||||
WORD CharType = 0;
|
||||
GetStringTypeW(CT_CTYPE3, &wch, 1, &CharType);
|
||||
|
||||
if (WI_IsFlagSet(CharType, C3_ALPHA) || GetQuickCharWidth(wch) == CodepointWidth::Wide)
|
||||
{
|
||||
keyState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents;
|
||||
if (keyState == invalidKey)
|
||||
{
|
||||
// if VkKeyScanW fails (char is not in kbd layout), we must
|
||||
// emulate the key being input through the numpad
|
||||
convertedEvents = SynthesizeNumpadEvents(wch, codepage);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedEvents = SynthesizeKeyboardEvents(wch, keyState);
|
||||
}
|
||||
|
||||
return convertedEvents;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - converts a wchar_t into a series of KeyEvents as if it was typed
|
||||
// using the keyboard
|
||||
// Arguments:
|
||||
// - wch - the wchar_t to convert
|
||||
// Return Value:
|
||||
// - deque of KeyEvents that represent the wchar_t being typed
|
||||
// Note:
|
||||
// - will throw exception on error
|
||||
std::deque<std::unique_ptr<KeyEvent>> Microsoft::Console::Interactivity::SynthesizeKeyboardEvents(const wchar_t wch, const short keyState)
|
||||
{
|
||||
const byte modifierState = HIBYTE(keyState);
|
||||
|
||||
bool altGrSet = false;
|
||||
bool shiftSet = false;
|
||||
std::deque<std::unique_ptr<KeyEvent>> keyEvents;
|
||||
|
||||
// add modifier key event if necessary
|
||||
if (WI_AreAllFlagsSet(modifierState, VkKeyScanModState::CtrlAndAltPressed))
|
||||
{
|
||||
altGrSet = true;
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
(ENHANCED_KEY | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED)));
|
||||
}
|
||||
else if (WI_IsFlagSet(modifierState, VkKeyScanModState::ShiftPressed))
|
||||
{
|
||||
shiftSet = true;
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_SHIFT),
|
||||
leftShiftScanCode,
|
||||
UNICODE_NULL,
|
||||
SHIFT_PRESSED));
|
||||
}
|
||||
|
||||
const auto vk = LOBYTE(keyState);
|
||||
const WORD virtualScanCode = gsl::narrow<WORD>(MapVirtualKeyW(vk, MAPVK_VK_TO_VSC));
|
||||
KeyEvent keyEvent{ true, 1, LOBYTE(keyState), virtualScanCode, wch, 0 };
|
||||
|
||||
// add modifier flags if necessary
|
||||
if (WI_IsFlagSet(modifierState, VkKeyScanModState::ShiftPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::Shift);
|
||||
}
|
||||
if (WI_IsFlagSet(modifierState, VkKeyScanModState::CtrlPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::LeftCtrl);
|
||||
}
|
||||
if (WI_AreAllFlagsSet(modifierState, VkKeyScanModState::CtrlAndAltPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::RightAlt);
|
||||
}
|
||||
|
||||
// add key event down and up
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(keyEvent));
|
||||
keyEvent.SetKeyDown(false);
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(keyEvent));
|
||||
|
||||
// add modifier key up event
|
||||
if (altGrSet)
|
||||
{
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
ENHANCED_KEY));
|
||||
}
|
||||
else if (shiftSet)
|
||||
{
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_SHIFT),
|
||||
leftShiftScanCode,
|
||||
UNICODE_NULL,
|
||||
0));
|
||||
}
|
||||
|
||||
return keyEvents;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - converts a wchar_t into a series of KeyEvents as if it was typed
|
||||
// using Alt + numpad
|
||||
// Arguments:
|
||||
// - wch - the wchar_t to convert
|
||||
// Return Value:
|
||||
// - deque of KeyEvents that represent the wchar_t being typed using
|
||||
// alt + numpad
|
||||
// Note:
|
||||
// - will throw exception on error
|
||||
std::deque<std::unique_ptr<KeyEvent>> Microsoft::Console::Interactivity::SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage)
|
||||
{
|
||||
std::deque<std::unique_ptr<KeyEvent>> keyEvents;
|
||||
|
||||
//alt keydown
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
|
||||
const int radix = 10;
|
||||
std::wstring wstr{ wch };
|
||||
const auto convertedChars = ConvertToA(codepage, wstr);
|
||||
if (convertedChars.size() == 1)
|
||||
{
|
||||
// It is OK if the char is "signed -1", we want to interpret that as "unsigned 255" for the
|
||||
// "integer to character" conversion below with ::to_string, thus the static_cast.
|
||||
// Prime example is nonbreaking space U+00A0 will convert to OEM by codepage 437 to 0xFF which is -1 signed.
|
||||
// But it is absolutely valid as 0xFF or 255 unsigned as the correct CP437 character.
|
||||
// We need to treat it as unsigned because we're going to pretend it was a keypad entry
|
||||
// and you don't enter negative numbers on the keypad.
|
||||
unsigned char const uch = static_cast<unsigned char>(convertedChars.at(0));
|
||||
|
||||
// unsigned char values are in the range [0, 255] so we need to be
|
||||
// able to store up to 4 chars from the conversion (including the end of string char)
|
||||
auto charString = std::to_string(uch);
|
||||
|
||||
for (auto& ch : std::string_view(charString))
|
||||
{
|
||||
if (ch == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const WORD virtualKey = ch - '0' + VK_NUMPAD0;
|
||||
const WORD virtualScanCode = gsl::narrow<WORD>(MapVirtualKeyW(virtualKey, MAPVK_VK_TO_VSC));
|
||||
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
virtualKey,
|
||||
virtualScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
virtualKey,
|
||||
virtualScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
}
|
||||
}
|
||||
|
||||
// alt keyup
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
wch,
|
||||
0));
|
||||
return keyEvents;
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\ApiDetector.cpp" />
|
||||
<ClCompile Include="..\EventSynthesis.cpp" />
|
||||
<ClCompile Include="..\InteractivityFactory.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
|
@ -39,6 +40,7 @@
|
|||
<ClInclude Include="..\..\inc\IWindowMetrics.hpp" />
|
||||
<ClInclude Include="..\..\inc\Module.hpp" />
|
||||
<ClInclude Include="..\..\inc\VtApiRedirection.hpp" />
|
||||
<ClInclude Include="..\..\inc\EventSynthesis.hpp" />
|
||||
<ClInclude Include="..\ApiDetector.hpp" />
|
||||
<ClInclude Include="..\InteractivityFactory.hpp" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
<ClCompile Include="..\ApiDetector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\EventSynthesis.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\InteractivityFactory.hpp">
|
||||
|
@ -74,8 +77,11 @@
|
|||
<ClInclude Include="..\..\inc\VtApiRedirection.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\EventSynthesis.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -43,9 +43,10 @@ SOURCES = \
|
|||
..\InteractivityFactory.cpp \
|
||||
..\ServiceLocator.cpp \
|
||||
..\VtApiRedirection.cpp \
|
||||
..\EventSynthesis.cpp \
|
||||
|
||||
INCLUDES = \
|
||||
$(INCLUDES); \
|
||||
..; \
|
||||
..\..\..\..\..\ConIoSrv; \
|
||||
|
||||
|
||||
|
|
29
src/interactivity/inc/EventSynthesis.hpp
Normal file
29
src/interactivity/inc/EventSynthesis.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
- EventSynthesis.hpp
|
||||
|
||||
Abstract:
|
||||
- Defined functions for converting strings/characters into events (for interactivity)
|
||||
Separated from types/convert.
|
||||
|
||||
Author:
|
||||
- Dustin Howett (duhowett) 10-Feb-2021
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include "../../types/inc/IInputEvent.hpp"
|
||||
|
||||
namespace Microsoft::Console::Interactivity
|
||||
{
|
||||
std::deque<std::unique_ptr<KeyEvent>> CharToKeyEvents(const wchar_t wch, const unsigned int codepage);
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeKeyboardEvents(const wchar_t wch,
|
||||
const short keyState);
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage);
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
#include "../../types/inc/viewport.hpp"
|
||||
|
||||
#include "../inc/conint.h"
|
||||
#include "../inc/EventSynthesis.hpp"
|
||||
#include "../inc/ServiceLocator.hpp"
|
||||
|
||||
#pragma hdrstop
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "InteractDispatch.hpp"
|
||||
#include "DispatchCommon.hpp"
|
||||
#include "conGetSet.hpp"
|
||||
#include "../../interactivity/inc/EventSynthesis.hpp"
|
||||
#include "../../types/inc/Viewport.hpp"
|
||||
#include "../../types/inc/convert.hpp"
|
||||
#include "../../inc/unicode.hpp"
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
@ -72,7 +72,7 @@ bool InteractDispatch::WriteString(const std::wstring_view string)
|
|||
|
||||
for (const auto& wch : string)
|
||||
{
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents = CharToKeyEvents(wch, codepage);
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents = Microsoft::Console::Interactivity::CharToKeyEvents(wch, codepage);
|
||||
|
||||
std::move(convertedEvents.begin(),
|
||||
convertedEvents.end(),
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "ascii.hpp"
|
||||
#include "../input/terminalInput.hpp"
|
||||
#include "../../inc/unicode.hpp"
|
||||
#include "../../types/inc/convert.hpp"
|
||||
#include "../../interactivity/inc/EventSynthesis.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
@ -379,7 +379,7 @@ bool TestInteractDispatch::WriteString(const std::wstring_view string)
|
|||
{
|
||||
// We're forcing the translation to CP_USA, so that it'll be constant
|
||||
// regardless of the CP the test is running in
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents = CharToKeyEvents(wch, CP_USA);
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents = Microsoft::Console::Interactivity::CharToKeyEvents(wch, CP_USA);
|
||||
std::move(convertedEvents.begin(),
|
||||
convertedEvents.end(),
|
||||
std::back_inserter(keyEvents));
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
<ProjectReference Include="..\lib\parser.vcxproj">
|
||||
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\interactivity\base\lib\InteractivityBase.vcxproj">
|
||||
<Project>{06ec74cb-9a12-429c-b551-8562ec964846}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -52,4 +55,4 @@
|
|||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Taef.Redist.Wlk.10.57.200731005-develop\build\Taef.Redist.Wlk.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Taef.Redist.Wlk.10.57.200731005-develop\build\Taef.Redist.Wlk.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -6,17 +6,8 @@
|
|||
|
||||
#include "../inc/unicode.hpp"
|
||||
|
||||
#ifdef BUILD_ONECORE_INTERACTIVITY
|
||||
#include "../../interactivity/inc/VtApiRedirection.hpp"
|
||||
#endif
|
||||
|
||||
#pragma hdrstop
|
||||
|
||||
// TODO: MSFT 14150722 - can these const values be generated at
|
||||
// runtime without breaking compatibility?
|
||||
static const WORD altScanCode = 0x38;
|
||||
static const WORD leftShiftScanCode = 0x2A;
|
||||
|
||||
// Routine Description:
|
||||
// - Takes a multibyte string, allocates the appropriate amount of memory for the conversion, performs the conversion,
|
||||
// and returns the Unicode UTF-16 result in the smart pointer (and the length).
|
||||
|
@ -139,199 +130,6 @@ static const WORD leftShiftScanCode = 0x2A;
|
|||
return cchTarget;
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> CharToKeyEvents(const wchar_t wch,
|
||||
const unsigned int codepage)
|
||||
{
|
||||
const short invalidKey = -1;
|
||||
short keyState = VkKeyScanW(wch);
|
||||
|
||||
if (keyState == invalidKey)
|
||||
{
|
||||
// Determine DBCS character because these character does not know by VkKeyScan.
|
||||
// GetStringTypeW(CT_CTYPE3) & C3_ALPHA can determine all linguistic characters. However, this is
|
||||
// not include symbolic character for DBCS.
|
||||
WORD CharType = 0;
|
||||
GetStringTypeW(CT_CTYPE3, &wch, 1, &CharType);
|
||||
|
||||
if (WI_IsFlagSet(CharType, C3_ALPHA) || GetQuickCharWidth(wch) == CodepointWidth::Wide)
|
||||
{
|
||||
keyState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> convertedEvents;
|
||||
if (keyState == invalidKey)
|
||||
{
|
||||
// if VkKeyScanW fails (char is not in kbd layout), we must
|
||||
// emulate the key being input through the numpad
|
||||
convertedEvents = SynthesizeNumpadEvents(wch, codepage);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedEvents = SynthesizeKeyboardEvents(wch, keyState);
|
||||
}
|
||||
|
||||
return convertedEvents;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - converts a wchar_t into a series of KeyEvents as if it was typed
|
||||
// using the keyboard
|
||||
// Arguments:
|
||||
// - wch - the wchar_t to convert
|
||||
// Return Value:
|
||||
// - deque of KeyEvents that represent the wchar_t being typed
|
||||
// Note:
|
||||
// - will throw exception on error
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeKeyboardEvents(const wchar_t wch, const short keyState)
|
||||
{
|
||||
const byte modifierState = HIBYTE(keyState);
|
||||
|
||||
bool altGrSet = false;
|
||||
bool shiftSet = false;
|
||||
std::deque<std::unique_ptr<KeyEvent>> keyEvents;
|
||||
|
||||
// add modifier key event if necessary
|
||||
if (WI_AreAllFlagsSet(modifierState, VkKeyScanModState::CtrlAndAltPressed))
|
||||
{
|
||||
altGrSet = true;
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
(ENHANCED_KEY | LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED)));
|
||||
}
|
||||
else if (WI_IsFlagSet(modifierState, VkKeyScanModState::ShiftPressed))
|
||||
{
|
||||
shiftSet = true;
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_SHIFT),
|
||||
leftShiftScanCode,
|
||||
UNICODE_NULL,
|
||||
SHIFT_PRESSED));
|
||||
}
|
||||
|
||||
const auto vk = LOBYTE(keyState);
|
||||
const WORD virtualScanCode = gsl::narrow<WORD>(MapVirtualKeyW(vk, MAPVK_VK_TO_VSC));
|
||||
KeyEvent keyEvent{ true, 1, LOBYTE(keyState), virtualScanCode, wch, 0 };
|
||||
|
||||
// add modifier flags if necessary
|
||||
if (WI_IsFlagSet(modifierState, VkKeyScanModState::ShiftPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::Shift);
|
||||
}
|
||||
if (WI_IsFlagSet(modifierState, VkKeyScanModState::CtrlPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::LeftCtrl);
|
||||
}
|
||||
if (WI_AreAllFlagsSet(modifierState, VkKeyScanModState::CtrlAndAltPressed))
|
||||
{
|
||||
keyEvent.ActivateModifierKey(ModifierKeyState::RightAlt);
|
||||
}
|
||||
|
||||
// add key event down and up
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(keyEvent));
|
||||
keyEvent.SetKeyDown(false);
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(keyEvent));
|
||||
|
||||
// add modifier key up event
|
||||
if (altGrSet)
|
||||
{
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
ENHANCED_KEY));
|
||||
}
|
||||
else if (shiftSet)
|
||||
{
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_SHIFT),
|
||||
leftShiftScanCode,
|
||||
UNICODE_NULL,
|
||||
0));
|
||||
}
|
||||
|
||||
return keyEvents;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - converts a wchar_t into a series of KeyEvents as if it was typed
|
||||
// using Alt + numpad
|
||||
// Arguments:
|
||||
// - wch - the wchar_t to convert
|
||||
// Return Value:
|
||||
// - deque of KeyEvents that represent the wchar_t being typed using
|
||||
// alt + numpad
|
||||
// Note:
|
||||
// - will throw exception on error
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage)
|
||||
{
|
||||
std::deque<std::unique_ptr<KeyEvent>> keyEvents;
|
||||
|
||||
//alt keydown
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
|
||||
const int radix = 10;
|
||||
std::wstring wstr{ wch };
|
||||
const auto convertedChars = ConvertToA(codepage, wstr);
|
||||
if (convertedChars.size() == 1)
|
||||
{
|
||||
// It is OK if the char is "signed -1", we want to interpret that as "unsigned 255" for the
|
||||
// "integer to character" conversion below with ::to_string, thus the static_cast.
|
||||
// Prime example is nonbreaking space U+00A0 will convert to OEM by codepage 437 to 0xFF which is -1 signed.
|
||||
// But it is absolutely valid as 0xFF or 255 unsigned as the correct CP437 character.
|
||||
// We need to treat it as unsigned because we're going to pretend it was a keypad entry
|
||||
// and you don't enter negative numbers on the keypad.
|
||||
unsigned char const uch = static_cast<unsigned char>(convertedChars.at(0));
|
||||
|
||||
// unsigned char values are in the range [0, 255] so we need to be
|
||||
// able to store up to 4 chars from the conversion (including the end of string char)
|
||||
auto charString = std::to_string(uch);
|
||||
|
||||
for (auto& ch : std::string_view(charString))
|
||||
{
|
||||
if (ch == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const WORD virtualKey = ch - '0' + VK_NUMPAD0;
|
||||
const WORD virtualScanCode = gsl::narrow<WORD>(MapVirtualKeyW(virtualKey, MAPVK_VK_TO_VSC));
|
||||
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(true,
|
||||
1ui16,
|
||||
virtualKey,
|
||||
virtualScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
virtualKey,
|
||||
virtualScanCode,
|
||||
UNICODE_NULL,
|
||||
LEFT_ALT_PRESSED));
|
||||
}
|
||||
}
|
||||
|
||||
// alt keyup
|
||||
keyEvents.push_back(std::make_unique<KeyEvent>(false,
|
||||
1ui16,
|
||||
static_cast<WORD>(VK_MENU),
|
||||
altScanCode,
|
||||
wch,
|
||||
0));
|
||||
return keyEvents;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - naively determines the width of a UCS2 encoded wchar
|
||||
// Arguments:
|
||||
|
|
|
@ -14,11 +14,8 @@ Author:
|
|||
--*/
|
||||
|
||||
#pragma once
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include "IInputEvent.hpp"
|
||||
|
||||
enum class CodepointWidth : BYTE
|
||||
{
|
||||
|
@ -37,13 +34,6 @@ enum class CodepointWidth : BYTE
|
|||
[[nodiscard]] size_t GetALengthFromW(const UINT codepage,
|
||||
const std::wstring_view source);
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> CharToKeyEvents(const wchar_t wch, const unsigned int codepage);
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeKeyboardEvents(const wchar_t wch,
|
||||
const short keyState);
|
||||
|
||||
std::deque<std::unique_ptr<KeyEvent>> SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage);
|
||||
|
||||
CodepointWidth GetQuickCharWidth(const wchar_t wch) noexcept;
|
||||
|
||||
wchar_t Utf16ToUcs2(const std::wstring_view charData);
|
||||
|
|
Loading…
Reference in a new issue