Repository: microsoft/terminal
File: src/host/inputBuffer.cpp (C++)

Code before:
{
    return WI_IsFlagSet(InputMode, ENABLE_VIRTUAL_TERMINAL_INPUT);
}

// Routine Description:
// - Handler for inserting key sequences into the buffer when the terminal emulation layer
//   has determined a key can be converted appropriately into a sequence of inputs
// Arguments:
// - inEvents - Series of input records to insert into the buffer
// Return Value:
// - <none>
void InputBuffer::_HandleTerminalInputCallback(const TerminalInput::StringType& text)
{
    try
    {
        if (text.empty())
        {
            return;
        }

        for (const auto& wch : text)
        {
            if (wch == UNICODE_NULL)
            {
                // Simulates a null byte input event.
                _storage.push_back(SynthesizeKeyEvent(true, 1, LOBYTE(OneCoreSafeVkKeyScanW(0)), 0, wch, CTRL_PRESSED | SHIFT_PRESSED));
                continue;
            }
            _storage.push_back(SynthesizeKeyEvent(true, 1, 0, 0, wch, 0));
        }

        if (!_vtInputShouldSuppress)
        {
            ServiceLocator::LocateGlobals().hInputEvent.SetEvent();
            WakeUpReadersWaitingForData();
        }
    }
    catch (...)
    {
        LOG_HR(wil::ResultFromCaughtException());
    }
}

TerminalInput& InputBuffer::GetTerminalInput()
{
    return _termInput;
}


Review comment (suggestion):
I don't think you can just hardcode the `CTRL_PRESSED` and `SHIFT_PRESSED` flags like this. You need to check what flags are set in the `HIBYTE` returned from the `VkKeyScanW(0)` call, and then convert those to equivalent `ControlKeyState` flags. Otherwise this will assumedly only work on keyboards where the null key is generated with a Ctrl Shift combination.

Code after:
{
    return WI_IsFlagSet(InputMode, ENABLE_VIRTUAL_TERMINAL_INPUT);
}

// Routine Description:
// - Handler for inserting key sequences into the buffer when the terminal emulation layer
//   has determined a key can be converted appropriately into a sequence of inputs
// Arguments:
// - inEvents - Series of input records to insert into the buffer
// Return Value:
// - <none>
void InputBuffer::_HandleTerminalInputCallback(const TerminalInput::StringType& text)
{
    try
    {
        if (text.empty())
        {
            return;
        }

        for (const auto& wch : text)
        {
            if (wch == UNICODE_NULL)
            {
                // Convert null byte back to input event with proper control state
                const auto zeroKey = OneCoreSafeVkKeyScanW(0);
                uint32_t ctrlState = 0;
                WI_SetFlagIf(ctrlState, SHIFT_PRESSED, WI_IsFlagSet(zeroKey, 0x100));
                WI_SetFlagIf(ctrlState, LEFT_CTRL_PRESSED, WI_IsFlagSet(zeroKey, 0x200));
                WI_SetFlagIf(ctrlState, LEFT_ALT_PRESSED, WI_IsFlagSet(zeroKey, 0x400));
                _storage.push_back(SynthesizeKeyEvent(true, 1, LOBYTE(zeroKey), 0, wch, ctrlState));
                continue;
            }
            _storage.push_back(SynthesizeKeyEvent(true, 1, 0, 0, wch, 0));
        }

        if (!_vtInputShouldSuppress)
        {
            ServiceLocator::LocateGlobals().hInputEvent.SetEvent();
            WakeUpReadersWaitingForData();
        }
    }
    catch (...)
    {
        LOG_HR(wil::ResultFromCaughtException());
    }
}

TerminalInput& InputBuffer::GetTerminalInput()
{
    return _termInput;