void ColorSpectrum::OnKeyDown()

in dev/ColorPicker/ColorSpectrum.cpp [98:214]


void ColorSpectrum::OnKeyDown(winrt::KeyRoutedEventArgs const& args)
{
    if (args.Key() != winrt::VirtualKey::Left &&
        args.Key() != winrt::VirtualKey::Right &&
        args.Key() != winrt::VirtualKey::Up &&
        args.Key() != winrt::VirtualKey::Down)
    {
        __super::OnKeyDown(args);
        return;
    }

    bool isControlDown = (winrt::Window::Current().CoreWindow().GetKeyState(winrt::VirtualKey::Control) & winrt::CoreVirtualKeyStates::Down) == winrt::CoreVirtualKeyStates::Down;

    winrt::ColorPickerHsvChannel incrementChannel = winrt::ColorPickerHsvChannel::Hue;

    bool isSaturationValue = false;

    if (args.Key() == winrt::VirtualKey::Left ||
        args.Key() == winrt::VirtualKey::Right)
    {
        switch (Components())
        {
        case winrt::ColorSpectrumComponents::HueSaturation:
        case winrt::ColorSpectrumComponents::HueValue:
            incrementChannel = winrt::ColorPickerHsvChannel::Hue;
            break;

        case winrt::ColorSpectrumComponents::SaturationValue:
            isSaturationValue = true;
            [[fallthrough]]; // fallthrough is explicitly wanted
        case winrt::ColorSpectrumComponents::SaturationHue:
            incrementChannel = winrt::ColorPickerHsvChannel::Saturation;
            break;

        case winrt::ColorSpectrumComponents::ValueHue:
        case winrt::ColorSpectrumComponents::ValueSaturation:
            incrementChannel = winrt::ColorPickerHsvChannel::Value;
            break;
        }
    }
    else if (args.Key() == winrt::VirtualKey::Up ||
        args.Key() == winrt::VirtualKey::Down)
    {
        switch (Components())
        {
        case winrt::ColorSpectrumComponents::SaturationHue:
        case winrt::ColorSpectrumComponents::ValueHue:
            incrementChannel = winrt::ColorPickerHsvChannel::Hue;
            break;

        case winrt::ColorSpectrumComponents::HueSaturation:
        case winrt::ColorSpectrumComponents::ValueSaturation:
            incrementChannel = winrt::ColorPickerHsvChannel::Saturation;
            break;

        case winrt::ColorSpectrumComponents::SaturationValue:
            isSaturationValue = true;
            [[fallthrough]]; // fallthrough is explicitly wanted
        case winrt::ColorSpectrumComponents::HueValue:
            incrementChannel = winrt::ColorPickerHsvChannel::Value;
            break;
        }
    }

    double minBound = 0;
    double maxBound = 0;

    switch (incrementChannel)
    {
    case winrt::ColorPickerHsvChannel::Hue:
        minBound = MinHue();
        maxBound = MaxHue();
        break;

    case winrt::ColorPickerHsvChannel::Saturation:
        minBound = MinSaturation();
        maxBound = MaxSaturation();
        break;

    case winrt::ColorPickerHsvChannel::Value:
        minBound = MinValue();
        maxBound = MaxValue();
        break;
    }

    // The order of saturation and value in the spectrum is reversed - the max value is at the bottom while the min value is at the top -
    // so we want left and up to be lower for hue, but higher for saturation and value.
    // This will ensure that the icon always moves in the direction of the key press.
    IncrementDirection direction =
        (incrementChannel == winrt::ColorPickerHsvChannel::Hue && (args.Key() == winrt::VirtualKey::Left || args.Key() == winrt::VirtualKey::Up)) ||
        (incrementChannel != winrt::ColorPickerHsvChannel::Hue && (args.Key() == winrt::VirtualKey::Right || args.Key() == winrt::VirtualKey::Down)) ?
        IncrementDirection::Lower :
        IncrementDirection::Higher;

    // Image is flipped in RightToLeft, so we need to invert direction in that case.
    // The combination saturation and value is also flipped, so we need to invert in that case too.
    // If both are false, we don't need to invert.
    // If both are true, we would invert twice, so not invert at all.
    if ((FlowDirection() == winrt::FlowDirection::RightToLeft) != isSaturationValue &&
        (args.Key() == winrt::VirtualKey::Left || args.Key() == winrt::VirtualKey::Right))
    {
        if (direction == IncrementDirection::Higher)
        {
            direction = IncrementDirection::Lower;
        }
        else
        {
            direction = IncrementDirection::Higher;
        }
    }

    const IncrementAmount amount = isControlDown ? IncrementAmount::Large : IncrementAmount::Small;

    const winrt::float4 hsvColor = HsvColor();
    UpdateColor(IncrementColorChannel(Hsv(hsv::GetHue(hsvColor), hsv::GetSaturation(hsvColor), hsv::GetValue(hsvColor)), incrementChannel, direction, amount, true /* shouldWrap */, minBound, maxBound));
    args.Handled(true);
}