diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi index 78121137..a567b0f3 100644 --- a/build/staging/version/BundleInfo.wxi +++ b/build/staging/version/BundleInfo.wxi @@ -1,4 +1,4 @@ - + diff --git a/build/staging/version/WindowsMidiServicesVersion.cs b/build/staging/version/WindowsMidiServicesVersion.cs index e7115934..6554d0bf 100644 --- a/build/staging/version/WindowsMidiServicesVersion.cs +++ b/build/staging/version/WindowsMidiServicesVersion.cs @@ -6,12 +6,12 @@ public static class MidiBuildInformation { public const string Source = "GitHub Preview"; public const string Name = "Customer Preview 2"; - public const string BuildFullVersion = "1.0.3-preview-11.250209-429"; + public const string BuildFullVersion = "1.0.3-preview-11.250211-2313"; public const string VersionMajor = "1"; public const string VersionMinor = "0"; public const string VersionRevision = "3"; - public const string VersionDateNumber = "250209"; - public const string VersionTimeNumber = "429"; + public const string VersionDateNumber = "250211"; + public const string VersionTimeNumber = "2313"; } } diff --git a/build/staging/version/WindowsMidiServicesVersion.h b/build/staging/version/WindowsMidiServicesVersion.h index cf1a4154..5774f5ca 100644 --- a/build/staging/version/WindowsMidiServicesVersion.h +++ b/build/staging/version/WindowsMidiServicesVersion.h @@ -5,12 +5,12 @@ #define WINDOWS_MIDI_SERVICES_BUILD_SOURCE L"GitHub Preview" #define WINDOWS_MIDI_SERVICES_BUILD_VERSION_NAME L"Customer Preview 2" -#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_FULL L"1.0.3-preview-11.250209-429" +#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_FULL L"1.0.3-preview-11.250211-2313" #define WINDOWS_MIDI_SERVICES_BUILD_VERSION_MAJOR L"1" #define WINDOWS_MIDI_SERVICES_BUILD_VERSION_MINOR L"0" #define WINDOWS_MIDI_SERVICES_BUILD_VERSION_REVISION L"3" -#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_DATE_NUMBER L"250209" -#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_TIME_NUMBER L"429" +#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_DATE_NUMBER L"250211" +#define WINDOWS_MIDI_SERVICES_BUILD_VERSION_TIME_NUMBER L"2313" #endif diff --git a/docs/sdk-winrt-core/common/MidiGroup.md b/docs/sdk-winrt-core/common/MidiGroup.md index 399b3e1c..b12ceee9 100644 --- a/docs/sdk-winrt-core/common/MidiGroup.md +++ b/docs/sdk-winrt-core/common/MidiGroup.md @@ -22,7 +22,8 @@ The `MidiGroup` class is used to provide formatting and data validation for MIDI ## Constructors -| `MidiGroup(UInt8)` | Create a MidiGroup with the specified group Index (0-15) | +| `MidiGroup()` | Create a MidiGroup initialized with group Index 0 | +| `MidiGroup(UInt8)` | Create a MidiGroup with the specified group Index (0-15). C++ note: C++/WinRT creates a constructor which takes nullptr, as a result `MidiGroup(0)` will fail to compile if you have the compiler option set to equate 0 and nullptr. To avoid this, use `MidiGroup(static_cast(0))` or simply `MidiGroup()` | ## Properties diff --git a/samples/cpp-winrt/basics/client-basics-cpp.vcxproj b/samples/cpp-winrt/basics/client-basics-cpp.vcxproj index 5521a969..9e17f3b6 100644 --- a/samples/cpp-winrt/basics/client-basics-cpp.vcxproj +++ b/samples/cpp-winrt/basics/client-basics-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true false diff --git a/samples/cpp-winrt/basics/packages.config b/samples/cpp-winrt/basics/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/basics/packages.config +++ b/samples/cpp-winrt/basics/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/loopback-endpoints/loopback-endpoints-cpp.vcxproj b/samples/cpp-winrt/loopback-endpoints/loopback-endpoints-cpp.vcxproj index f453ff5f..cd091688 100644 --- a/samples/cpp-winrt/loopback-endpoints/loopback-endpoints-cpp.vcxproj +++ b/samples/cpp-winrt/loopback-endpoints/loopback-endpoints-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/samples/cpp-winrt/loopback-endpoints/packages.config b/samples/cpp-winrt/loopback-endpoints/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/loopback-endpoints/packages.config +++ b/samples/cpp-winrt/loopback-endpoints/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/send-speed/packages.config b/samples/cpp-winrt/send-speed/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/send-speed/packages.config +++ b/samples/cpp-winrt/send-speed/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/send-speed/send-speed-cpp.vcxproj b/samples/cpp-winrt/send-speed/send-speed-cpp.vcxproj index 8fa76522..e3945717 100644 --- a/samples/cpp-winrt/send-speed/send-speed-cpp.vcxproj +++ b/samples/cpp-winrt/send-speed/send-speed-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/samples/cpp-winrt/simple-app-to-app-midi/packages.config b/samples/cpp-winrt/simple-app-to-app-midi/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/simple-app-to-app-midi/packages.config +++ b/samples/cpp-winrt/simple-app-to-app-midi/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/simple-app-to-app-midi/simple-app-to-app-cpp.vcxproj b/samples/cpp-winrt/simple-app-to-app-midi/simple-app-to-app-cpp.vcxproj index 8176f9b6..cc4b41c7 100644 --- a/samples/cpp-winrt/simple-app-to-app-midi/simple-app-to-app-cpp.vcxproj +++ b/samples/cpp-winrt/simple-app-to-app-midi/simple-app-to-app-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/samples/cpp-winrt/static-enum-endpoints/packages.config b/samples/cpp-winrt/static-enum-endpoints/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/static-enum-endpoints/packages.config +++ b/samples/cpp-winrt/static-enum-endpoints/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/static-enum-endpoints/static-enum-endpoints-cpp.vcxproj b/samples/cpp-winrt/static-enum-endpoints/static-enum-endpoints-cpp.vcxproj index 7e36d41c..4e9d5e15 100644 --- a/samples/cpp-winrt/static-enum-endpoints/static-enum-endpoints-cpp.vcxproj +++ b/samples/cpp-winrt/static-enum-endpoints/static-enum-endpoints-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/samples/cpp-winrt/watch-endpoints/packages.config b/samples/cpp-winrt/watch-endpoints/packages.config index 8cd2fd68..acb430cb 100644 --- a/samples/cpp-winrt/watch-endpoints/packages.config +++ b/samples/cpp-winrt/watch-endpoints/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/cpp-winrt/watch-endpoints/watch-endpoints-cpp.vcxproj b/samples/cpp-winrt/watch-endpoints/watch-endpoints-cpp.vcxproj index b35d1956..332164df 100644 --- a/samples/cpp-winrt/watch-endpoints/watch-endpoints-cpp.vcxproj +++ b/samples/cpp-winrt/watch-endpoints/watch-endpoints-cpp.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/src/api/Inc/MidiDefs.h b/src/api/Inc/MidiDefs.h index 33089295..c359b57b 100644 --- a/src/api/Inc/MidiDefs.h +++ b/src/api/Inc/MidiDefs.h @@ -86,6 +86,11 @@ static_assert( MAXIMUM_LOOPED_BUFFER_SIZE < ULONG_MAX/2, "The maximum looped #define MIDI_USE_MMCSS_REG_VALUE L"UseMMCSS" #define MIDI_USE_MMCSS_REG_DEFAULT_VALUE 0x00000000 +// this is used as the default approach for how we name MIDI 1 ports +// individual ports can override this via a property in the list below. +#define MIDI_USE_OLD_MIDI1PORT_NAMING_DEFAULT_REG_VALUE L"DefaultToOldMidi1PortNaming" +#define MIDI_USE_OLD_MIDI1PORT_NAMING_DEFAULT_VALUE 0x00000001 + #define MIDI_CONFIG_FILE_REG_VALUE L"CurrentConfig" // if value > 0, then endpoint discovery and protocol negotiation are enabled @@ -93,9 +98,10 @@ static_assert( MAXIMUM_LOOPED_BUFFER_SIZE < ULONG_MAX/2, "The maximum looped #define MIDI_DISCOVERY_ENABLED_REG_VALUE L"Midi2DiscoveryEnabled" #define MIDI_DISCOVERY_ENABLED_REG_DEFAULT_VALUE 0x00000001 +// this is the amount of time we allocate to discovery across all native UMP format MIDI 2 devices #define MIDI_DISCOVERY_TIMEOUT_REG_VALUE L"Midi2DiscoveryTimeoutMS" #define MIDI_DISCOVERY_TIMEOUT_DEFAULT_VALUE 10000 -#define MIDI_DISCOVERY_TIMEOUT_MINIMUM_VALUE 1000 +#define MIDI_DISCOVERY_TIMEOUT_MINIMUM_VALUE 500 #define MIDI_DISCOVERY_TIMEOUT_MAXIMUM_VALUE 50000 @@ -639,7 +645,18 @@ DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_VirtualMidiEndpointAssociator, 900); // DEVP -// Structures for properties ================================================================ +// MIDI 1.0 Port Naming Properties ========================================================== +// Starts at 1000 + +// this property is used on the parent UMP interface to control all generated MIDI 1 ports +#define STRING_PKEY_MIDI_UseOldMidi1PortNamingScheme MIDI_STRING_PKEY_GUID MIDI_STRING_PKEY_PID_SEPARATOR L"1000" +DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_UseOldMidi1PortNamingScheme, 1000); // DEVPROP_TYPE_BOOL + + + + + +// Structures for properties ================================================================= diff --git a/src/api/Inc/midi_naming.h b/src/api/Inc/midi_naming.h new file mode 100644 index 00000000..c422afd0 --- /dev/null +++ b/src/api/Inc/midi_naming.h @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App API and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + +#pragma once + +#ifndef MIDI_NAMING_H +#define MIDI_NAMING_H + +#include +#include + +namespace WindowsMidiServicesInternal::Midi1PortNaming +{ + inline std::wstring CleanupKSPinName( + _In_ std::wstring const& pinName, + _In_ std::wstring parentDeviceName, + _In_ std::wstring filterName + ) + { + std::wstring cleanedPinName{}; + + // Used by ESI, MOTU, and others. We don't want to mess up other names, so check only + // for whole word. We do other removal in the next step + if (pinName == L"MIDI" || + pinName == L"Out" || pinName == L"OUT" || pinName == L"out" || + pinName == L"In" || pinName == L"IN" || pinName == L"in" + ) + { + cleanedPinName = L""; + } + else + { + cleanedPinName = pinName; + } + + // the double and triple space entries need to be last + // there are other ways to do this with pattern matching, + // but just banging this through for this version + const std::wstring wordsToRemove[] = + { + // many of these are added by our USB and KS stack, not by the device, which is why they are here + parentDeviceName, filterName, + L"[0]", L"[1]", L"[2]", L"[3]", L"[4]", L"[5]", L"[6]", L"[7]", L"[8]", L"[9]", L"[10]", L"[11]", L"[12]", L"[13]", L"[14]", L"[15]", L"[16]", + L" ", L" ", L" " + }; + + for (auto const& word : wordsToRemove) + { + if (cleanedPinName.length() >= word.length()) + { + auto idx = cleanedPinName.find(word); + + if (idx != std::wstring::npos) + { + cleanedPinName = cleanedPinName.erase(idx, word.length()); + } + } + } + + internal::InPlaceTrim(cleanedPinName); + + return cleanedPinName; + } + + + // This is used for generating the GTB names on KSA endpoints, for MIDI 1.0 devices. Those + // GTB names are used directly when creating WinMM endpoints + inline std::wstring GenerateMidi1PortName( + _In_ bool const useOldStyleNaming, // this comes from the property on the device, and if not specified, from the registry. Controls using old WinMM-style naming + _In_ std::wstring const& userSuppliedPortName, // if the user has supplied a name for the generated port, and we're not using old-style naming, this wins + _In_ std::wstring const& deviceContainerName, // oddly some old WinMM code picks up the deviceContainerName somehow + _In_ std::wstring const& parentDeviceName, // the name of the actual connected device from which the UMP interface is generated + _In_ std::wstring const& parentDeviceManufacturerName, // the name of the parent device + _In_ std::wstring const& filterName, // the name of the filter. This is sometimes the same as the parent device + _In_ std::wstring const& pinName, // the name of the KS Filter pin. This can be the same as the USB iJack + _In_ uint8_t const groupIndex, + _In_ MidiFlow const flowFromUserPerspective, + _In_ bool const isUmpDevice, + _In_ bool const isUsingVendorDriver, + _In_ bool const truncateToWinMMLimit, + _In_ std::vector const& otherExistingMidi1PortNamesForThisDeviceAndFlow + ) + { + UNREFERENCED_PARAMETER(deviceContainerName); + UNREFERENCED_PARAMETER(parentDeviceName); + UNREFERENCED_PARAMETER(parentDeviceManufacturerName); + UNREFERENCED_PARAMETER(groupIndex); + UNREFERENCED_PARAMETER(flowFromUserPerspective); + UNREFERENCED_PARAMETER(isUmpDevice); + UNREFERENCED_PARAMETER(isUsingVendorDriver); + UNREFERENCED_PARAMETER(otherExistingMidi1PortNamesForThisDeviceAndFlow); + + // user supplied a port name, so it is what we use + // if we're using old-style naming, we do not use + // any user-supplied information for the name + if (!userSuppliedPortName.empty() && !useOldStyleNaming) + { + return userSuppliedPortName; + } + + + if (useOldStyleNaming) + { + std::wstring name{}; + + // TODO: Find the old naming code in the source tree, and reimplement + + + + return name; + } + else + { + std::wstring name{}; + + auto cleanedPinName = CleanupKSPinName(pinName, parentDeviceName, filterName); + + name = internal::TrimmedWStringCopy(filterName + L" " + internal::TrimmedWStringCopy(cleanedPinName)); + + if (truncateToWinMMLimit) + { + if (name.length() + 1 > MAXPNAMELEN) + { + if (!cleanedPinName.empty()) + { + // we're over length, so just use the pin name + name = cleanedPinName.substr(0, MAXPNAMELEN - 1); + } + else + { + // we're over length, and there's no pin name + // so we use the filter name + name = filterName.substr(0, MAXPNAMELEN - 1); + } + } + } + + // TODO: do we need to do any port differentiators here? Look at the collection and see + // if there are already ports starting with the same name, and if so, increment a counter and append + + return name; + } + + } + +} + +#endif \ No newline at end of file diff --git a/src/api/Midi2.sln b/src/api/Midi2.sln index 72775e07..560bc0f6 100644 --- a/src/api/Midi2.sln +++ b/src/api/Midi2.sln @@ -42,6 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{A4512D Inc\loopback_ids.h = Inc\loopback_ids.h Inc\MidiDefs.h = Inc\MidiDefs.h Inc\midi_group_terminal_blocks.h = Inc\midi_group_terminal_blocks.h + Inc\midi_naming.h = Inc\midi_naming.h Inc\midi_timestamp.h = Inc\midi_timestamp.h Inc\midi_ump.h = Inc\midi_ump.h Inc\midi_ump_message_defs.h = Inc\midi_ump_message_defs.h diff --git a/src/api/Transport/KSAggregateTransport/Midi2.KSAggregateMidiEndpointManager.cpp b/src/api/Transport/KSAggregateTransport/Midi2.KSAggregateMidiEndpointManager.cpp index 1d116347..32fa6cb8 100644 --- a/src/api/Transport/KSAggregateTransport/Midi2.KSAggregateMidiEndpointManager.cpp +++ b/src/api/Transport/KSAggregateTransport/Midi2.KSAggregateMidiEndpointManager.cpp @@ -91,53 +91,53 @@ CMidi2KSAggregateMidiEndpointManager::Initialize( -// this will be used for the group terminal block name but also for the WinMM port name -HRESULT -CreateGroupTerminalBlockName( - _In_ std::wstring parentDeviceName, - _In_ std::wstring filterName, - _In_ std::wstring currentPinName, - _Inout_ std::wstring& newGroupTerminalBlockName) -{ - std::wstring cleanedPinName{}; - - // MOTU-specific. We don't want to mess up other names, so check only for whole word - if (currentPinName == L"MIDI") - { - cleanedPinName = L""; - } - else - { - cleanedPinName = currentPinName; - } - - // the double and triple space entries need to be last - // there are other ways to do this with pattern matching, - // but just banging this through for this version - std::wstring wordsToRemove[] = - { - parentDeviceName, filterName, - L"[0]", L"[1]", L"[2]", L"[3]", L"[4]", L"[5]", L"[6]", L"[7]", L"[8]", L"[9]", L"[10]", L"[11]", L"[12]", L"[13]", L"[14]", L"[15]", L"[16]", - L" ", L" ", L" " - }; - - for (auto const& word : wordsToRemove) - { - if (cleanedPinName.length() >= word.length()) - { - auto idx = cleanedPinName.find(word); - - if (idx != std::wstring::npos) - { - cleanedPinName = cleanedPinName.erase(idx, word.length()); - } - } - } - - newGroupTerminalBlockName = internal::TrimmedWStringCopy(filterName + L" " + internal::TrimmedWStringCopy(cleanedPinName)); - - return S_OK; -} +//// this will be used for the group terminal block name but also for the WinMM port name +//HRESULT +//CreateGroupTerminalBlockName( +// _In_ std::wstring parentDeviceName, +// _In_ std::wstring filterName, +// _In_ std::wstring currentPinName, +// _Inout_ std::wstring& newGroupTerminalBlockName) +//{ +// std::wstring cleanedPinName{}; +// +// // Used by ESI, MOTU, and others. We don't want to mess up other names, so check only for whole word +// if (currentPinName == L"MIDI") +// { +// cleanedPinName = L""; +// } +// else +// { +// cleanedPinName = currentPinName; +// } +// +// // the double and triple space entries need to be last +// // there are other ways to do this with pattern matching, +// // but just banging this through for this version +// std::wstring wordsToRemove[] = +// { +// parentDeviceName, filterName, +// L"[0]", L"[1]", L"[2]", L"[3]", L"[4]", L"[5]", L"[6]", L"[7]", L"[8]", L"[9]", L"[10]", L"[11]", L"[12]", L"[13]", L"[14]", L"[15]", L"[16]", +// L" ", L" ", L" " +// }; +// +// for (auto const& word : wordsToRemove) +// { +// if (cleanedPinName.length() >= word.length()) +// { +// auto idx = cleanedPinName.find(word); +// +// if (idx != std::wstring::npos) +// { +// cleanedPinName = cleanedPinName.erase(idx, word.length()); +// } +// } +// } +// +// newGroupTerminalBlockName = internal::TrimmedWStringCopy(filterName + L" " + internal::TrimmedWStringCopy(cleanedPinName)); +// +// return S_OK; +//} typedef struct { @@ -218,6 +218,9 @@ CMidi2KSAggregateMidiEndpointManager::CreateMidiUmpEndpoint( std::vector blocks{ }; std::vector pinMapEntries{ }; + std::vector portNamesUserFlowOut{ }; + std::vector portNamesUserFlowIn{ }; + for (auto const& pin : masterEndpointDefinition.MidiPins) { RETURN_HR_IF(E_INVALIDARG, pin.FilterDeviceId.empty()); @@ -233,26 +236,78 @@ CMidi2KSAggregateMidiEndpointManager::CreateMidiUmpEndpoint( pinMapEntry.FilterId = pin.FilterDeviceId; pinMapEntry.PinDataFlow = pin.PinDataFlow; + MidiFlow flowFromUserPerspective; + + + std::wstring userSuppliedPortName{}; // TODO: This should come from config file + bool useOldStyleNaming{ false }; // TODO: This should come from registry and property + std::wstring deviceContainerName{}; // TODO: Need to get this from the device info + std::wstring parentDeviceManufacturerName{}; // TODO: Need to get this from the parent device + bool isUsingVendorDriver{ false }; // TODO: Need to get this from the device information + + if (pin.PinDataFlow == MidiFlow::MidiFlowIn) { + flowFromUserPerspective = MidiFlow::MidiFlowOut; + pinMapEntry.GroupIndex = currentGtbInputGroupIndex; gtb.Direction = MIDI_GROUP_TERMINAL_BLOCK_INPUT; // from the pin/gtb's perspective gtb.FirstGroupIndex = currentGtbInputGroupIndex; currentGtbInputGroupIndex++; + + gtb.Name = internal::Midi1PortNaming::GenerateMidi1PortName( + useOldStyleNaming, // this comes from the property on the device, and if not specified, from the registry. Controls using old WinMM-style naming + userSuppliedPortName, // if the user has supplied a name for the generated port, and we're not using old-style naming, this wins + deviceContainerName, // oddly some old WinMM code picks up the deviceContainerName somehow + masterEndpointDefinition.ParentDeviceName, // the name of the actual connected device from which the UMP interface is generated + parentDeviceManufacturerName, // the name of the parent device + pin.FilterName, // the name of the filter. This is sometimes the same as the parent device + pin.PinName, // the name of the KS Filter pin. This can be the same as the USB iJack + gtb.FirstGroupIndex, + flowFromUserPerspective, + false, // this is not a native UMP device, it is a native byte stream device + isUsingVendorDriver, + true, // we truncate to the WinMM max name limit (32 chars including nul) + portNamesUserFlowOut + ); + + // this is kept just so we can add ordinal differentiators if we need to + portNamesUserFlowOut.push_back(gtb.Name); } else if (pin.PinDataFlow == MidiFlow::MidiFlowOut) { + flowFromUserPerspective = MidiFlow::MidiFlowIn; + pinMapEntry.GroupIndex = currentGtbOutputGroupIndex; gtb.Direction = MIDI_GROUP_TERMINAL_BLOCK_OUTPUT; // from the pin/gtb's perspective gtb.FirstGroupIndex = currentGtbOutputGroupIndex; currentGtbOutputGroupIndex++; + + gtb.Name = internal::Midi1PortNaming::GenerateMidi1PortName( + useOldStyleNaming, // this comes from the property on the device, and if not specified, from the registry. Controls using old WinMM-style naming + userSuppliedPortName, // if the user has supplied a name for the generated port, and we're not using old-style naming, this wins + deviceContainerName, // oddly some old WinMM code picks up the deviceContainerName somehow + masterEndpointDefinition.ParentDeviceName, // the name of the actual connected device from which the UMP interface is generated + parentDeviceManufacturerName, // the name of the parent device + pin.FilterName, // the name of the filter. This is sometimes the same as the parent device + pin.PinName, // the name of the KS Filter pin. This can be the same as the USB iJack + gtb.FirstGroupIndex, + flowFromUserPerspective, + false, // this is not a native UMP device, it is a native byte stream device + isUsingVendorDriver, + true, // we truncate to the WinMM max name limit (32 chars including nul) + portNamesUserFlowIn + ); + + // this is kept just so we can add ordinal differentiators if we need to + portNamesUserFlowIn.push_back(gtb.Name); } else { RETURN_IF_FAILED(E_INVALIDARG); } - LOG_IF_FAILED(CreateGroupTerminalBlockName(masterEndpointDefinition.ParentDeviceName, pin.FilterName, pin.PinName, gtb.Name)); + //LOG_IF_FAILED(CreateGroupTerminalBlockName(masterEndpointDefinition.ParentDeviceName, pin.FilterName, pin.PinName, gtb.Name)); // default values as defined in the MIDI 2.0 USB spec gtb.Protocol = 0x01; // midi 1.0 @@ -810,9 +865,19 @@ HRESULT CMidi2KSAggregateMidiEndpointManager::OnDeviceRemoved(DeviceWatcher, Dev } _Use_decl_annotations_ -HRESULT CMidi2KSAggregateMidiEndpointManager::OnDeviceUpdated(DeviceWatcher, DeviceInformationUpdate) +HRESULT CMidi2KSAggregateMidiEndpointManager::OnDeviceUpdated(DeviceWatcher, DeviceInformationUpdate update) { //see this function for info on the IDeviceInformationUpdate object: https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/enumerate-devices#enumerate-and-watch-devices + + // NOTE: When you change the assigned driver for the device, instead of sending + // separate remove/add events, this gets a couple of OnDeviceUpdate notifications. + + for (auto const& prop : update.Properties()) + { + OutputDebugString((std::wstring(L"KSA: ") + std::wstring(prop.Key().c_str())).c_str()); + } + + return S_OK; } diff --git a/src/api/Transport/KSAggregateTransport/pch.h b/src/api/Transport/KSAggregateTransport/pch.h index 7057ebf5..cf747d0b 100644 --- a/src/api/Transport/KSAggregateTransport/pch.h +++ b/src/api/Transport/KSAggregateTransport/pch.h @@ -77,9 +77,8 @@ namespace json = ::winrt::Windows::Data::Json; #include "swd_helpers.h" #include "resource_util.h" #include "ump_helpers.h" - #include "MidiXProc.h" - +#include "midi_naming.h" #include "strsafe.h" @@ -108,7 +107,6 @@ namespace json = ::winrt::Windows::Data::Json; #include "Midi2UMP2BSTransform_i.c" - class CMidi2KSAggregateMidiEndpointManager; class CMidi2KSAggregateMidiInProxy; class CMidi2KSAggregateMidiOutProxy; diff --git a/src/api/Transport/KSTransport/Midi2.KSMidiEndpointManager.cpp b/src/api/Transport/KSTransport/Midi2.KSMidiEndpointManager.cpp index c553385c..81b8e04c 100644 --- a/src/api/Transport/KSTransport/Midi2.KSMidiEndpointManager.cpp +++ b/src/api/Transport/KSTransport/Midi2.KSMidiEndpointManager.cpp @@ -847,9 +847,15 @@ HRESULT CMidi2KSMidiEndpointManager::OnDeviceRemoved(DeviceWatcher, DeviceInform } _Use_decl_annotations_ -HRESULT CMidi2KSMidiEndpointManager::OnDeviceUpdated(DeviceWatcher, DeviceInformationUpdate) +HRESULT CMidi2KSMidiEndpointManager::OnDeviceUpdated(DeviceWatcher, DeviceInformationUpdate update) { //see this function for info on the IDeviceInformationUpdate object: https://learn.microsoft.com/en-us/windows/uwp/devices-sensors/enumerate-devices#enumerate-and-watch-devices + + for (auto const& prop : update.Properties()) + { + OutputDebugString((std::wstring(L"KS: ") + std::wstring(prop.Key().c_str())).c_str() ); + } + return S_OK; } diff --git a/src/app-sdk/app-sdk-tools-and-tests.sln b/src/app-sdk/app-sdk-tools-and-tests.sln index 167a6809..5d0e37be 100644 --- a/src/app-sdk/app-sdk-tools-and-tests.sln +++ b/src/app-sdk/app-sdk-tools-and-tests.sln @@ -23,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midimdnsinfo", "midimdnsinf EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midi1monitor", "midi1monitor\midi1monitor.vcxproj", "{357A35F3-D207-43C5-8F56-B3A374F9EBF9}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midiupdatedriver", "midiupdatedriver\midiupdatedriver.vcxproj", "{631E4512-699C-4BC8-AE31-942498CB55FA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -163,6 +165,22 @@ Global {357A35F3-D207-43C5-8F56-B3A374F9EBF9}.Release|ARM64EC.Build.0 = Release|ARM64 {357A35F3-D207-43C5-8F56-B3A374F9EBF9}.Release|x64.ActiveCfg = Release|x64 {357A35F3-D207-43C5-8F56-B3A374F9EBF9}.Release|x64.Build.0 = Release|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|Any CPU.Build.0 = Debug|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|ARM64.Build.0 = Debug|ARM64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|ARM64EC.Build.0 = Debug|ARM64EC + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|x64.ActiveCfg = Debug|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Debug|x64.Build.0 = Debug|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|Any CPU.ActiveCfg = Release|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|Any CPU.Build.0 = Release|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|ARM64.ActiveCfg = Release|ARM64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|ARM64.Build.0 = Release|ARM64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|ARM64EC.ActiveCfg = Release|ARM64EC + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|ARM64EC.Build.0 = Release|ARM64EC + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|x64.ActiveCfg = Release|x64 + {631E4512-699C-4BC8-AE31-942498CB55FA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -176,6 +194,7 @@ Global {9803D8E6-5CA5-420C-A02B-5E3327355041} = {900D72D2-91F0-4E6C-B694-192FD48393D2} {C787073C-50F0-5CA0-D53C-12107196F2F0} = {C8B31D71-0226-4D2D-AC78-53D5C84F472F} {357A35F3-D207-43C5-8F56-B3A374F9EBF9} = {C8B31D71-0226-4D2D-AC78-53D5C84F472F} + {631E4512-699C-4BC8-AE31-942498CB55FA} = {C8B31D71-0226-4D2D-AC78-53D5C84F472F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AE1DF8B9-9FAB-4E20-8AC6-FF316882222F} diff --git a/src/app-sdk/mididiag/mididiag.vcxproj b/src/app-sdk/mididiag/mididiag.vcxproj index 0d43feeb..5e1c8514 100644 --- a/src/app-sdk/mididiag/mididiag.vcxproj +++ b/src/app-sdk/mididiag/mididiag.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/src/app-sdk/mididiag/packages.config b/src/app-sdk/mididiag/packages.config index 9596ff16..b98787f6 100644 --- a/src/app-sdk/mididiag/packages.config +++ b/src/app-sdk/mididiag/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/app-sdk/midimdnsinfo/midimdnsinfo.vcxproj b/src/app-sdk/midimdnsinfo/midimdnsinfo.vcxproj index ea4fd8f4..ed6225d9 100644 --- a/src/app-sdk/midimdnsinfo/midimdnsinfo.vcxproj +++ b/src/app-sdk/midimdnsinfo/midimdnsinfo.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/src/app-sdk/midimdnsinfo/packages.config b/src/app-sdk/midimdnsinfo/packages.config index 9596ff16..b98787f6 100644 --- a/src/app-sdk/midimdnsinfo/packages.config +++ b/src/app-sdk/midimdnsinfo/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/app-sdk/midiupdatedriver/color.hpp b/src/app-sdk/midiupdatedriver/color.hpp new file mode 100644 index 00000000..cb080b6e --- /dev/null +++ b/src/app-sdk/midiupdatedriver/color.hpp @@ -0,0 +1,881 @@ +// source: https://github.com/aafulei/color-console/blob/master/include/color.hpp + + +#ifndef COLOR_HPP +#define COLOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace hue +{ + constexpr int DEFAULT_COLOR = 7; + constexpr int BAD_COLOR = -256; + + const std::map CODES = { + {"black", 0}, {"k", 0}, + {"blue", 1}, {"b", 1}, + {"green", 2}, {"g", 2}, + {"aqua", 3}, {"a", 3}, + {"red", 4}, {"r", 4}, + {"purple", 5}, {"p", 5}, + {"yellow", 6}, {"y", 6}, + {"white", 7}, {"w", 7}, + {"grey", 8}, {"e", 8}, + {"light blue", 9}, {"lb", 9}, + {"light green", 10}, {"lg", 10}, + {"light aqua", 11}, {"la", 11}, + {"light red", 12}, {"lr", 12}, + {"light purple", 13}, {"lp", 13}, + {"light yellow", 14}, {"ly", 14}, + {"bright white", 15}, {"bw", 15} + }; + + const std::map NAMES = { + { 0, "black"}, + { 1, "blue"}, + { 2, "green"}, + { 3, "aqua"}, + { 4, "red"}, + { 5, "purple"}, + { 6, "yellow"}, + { 7, "white"}, + { 8, "grey"}, + { 9, "light blue"}, + {10, "light green"}, + {11, "light aqua"}, + {12, "light red"}, + {13, "light purple"}, + {14, "light yellow"}, + {15, "bright white"} + }; + + inline bool is_good(int c) + { + return 0 <= c && c < 256; + } + + inline int itoc(int c) + { + return is_good(c) ? c : BAD_COLOR; + } + + inline int itoc(int a, int b) + { + return itoc(a + b * 16); + } + + // std::string to color + int stoc(std::string a) + { + // convert s to lowercase, and format variants like "light_blue" + std::transform(a.begin(), a.end(), a.begin(), [](char c) + { + if ('A' <= c && c <= 'Z') + c = c - 'A' + 'a'; + else if (c == '_' || c == '-') + c = ' '; + return c; + }); + + // operator[] on std::map is non-const, use std::map::at instead + return (CODES.find(a) != CODES.end()) ? CODES.at(a) : BAD_COLOR; + } + + int stoc(std::string a, std::string b) + { + return itoc(stoc(a), stoc(b)); + } + + std::string ctos(int c) + { + return (0 <= c && c < 256) ? + "(text) " + NAMES.at(c % 16) + " + " + + "(background) " + NAMES.at(c / 16) : + "BAD COLOR"; + } + + int get() + { + CONSOLE_SCREEN_BUFFER_INFO i; + return GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &i) ? + i.wAttributes : BAD_COLOR; + } + + int get_text() + { + return (get() != BAD_COLOR) ? get() % 16 : BAD_COLOR; + } + + int get_background() + { + return (get() != BAD_COLOR) ? get() / 16 : BAD_COLOR; + } + + void set(int c) + { + if (is_good(c)) + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); + } + + void set(int a, int b) + { + set(a + b * 16); + } + + void set(std::string a, std::string b) + { + set(stoc(a) + stoc(b) * 16); + } + + void set_text(std::string a) + { + set(stoc(a), get_background()); + } + + void set_background(std::string b) + { + set(get_text(), stoc(b)); + } + + void reset() + { + set(DEFAULT_COLOR); + } + + int invert(int c) + { + if (is_good(c)) { + int a = c % 16; + int b = c / 16; + return b + a * 16; + } + else + return BAD_COLOR; + } + + std::ostream& reset(std::ostream& os) { reset(); return os; } + std::ostream& black(std::ostream& os) { set_text("k"); return os; } + std::ostream& blue(std::ostream& os) { set_text("b"); return os; } + std::ostream& green(std::ostream& os) { set_text("g"); return os; } + std::ostream& aqua(std::ostream& os) { set_text("a"); return os; } + std::ostream& red(std::ostream& os) { set_text("r"); return os; } + std::ostream& purple(std::ostream& os) { set_text("p"); return os; } + std::ostream& yellow(std::ostream& os) { set_text("y"); return os; } + std::ostream& white(std::ostream& os) { set_text("w"); return os; } + std::ostream& grey(std::ostream& os) { set_text("e"); return os; } + std::ostream& light_blue(std::ostream& os) { set_text("lb"); return os; } + std::ostream& light_green(std::ostream& os) { set_text("lg"); return os; } + std::ostream& light_aqua(std::ostream& os) { set_text("la"); return os; } + std::ostream& light_red(std::ostream& os) { set_text("lr"); return os; } + std::ostream& light_purple(std::ostream& os) { set_text("lp"); return os; } + std::ostream& light_yellow(std::ostream& os) { set_text("ly"); return os; } + std::ostream& bright_white(std::ostream& os) { set_text("bw"); return os; } + std::ostream& on_black(std::ostream& os) { set_background("k"); return os; } + std::ostream& on_blue(std::ostream& os) { set_background("b"); return os; } + std::ostream& on_green(std::ostream& os) { set_background("g"); return os; } + std::ostream& on_aqua(std::ostream& os) { set_background("a"); return os; } + std::ostream& on_red(std::ostream& os) { set_background("r"); return os; } + std::ostream& on_purple(std::ostream& os) { set_background("p"); return os; } + std::ostream& on_yellow(std::ostream& os) { set_background("y"); return os; } + std::ostream& on_white(std::ostream& os) { set_background("w"); return os; } + std::ostream& on_grey(std::ostream& os) { set_background("e"); return os; } + std::ostream& on_light_blue(std::ostream& os) { set_background("lb"); return os; } + std::ostream& on_light_green(std::ostream& os) { set_background("lg"); return os; } + std::ostream& on_light_aqua(std::ostream& os) { set_background("la"); return os; } + std::ostream& on_light_red(std::ostream& os) { set_background("lr"); return os; } + std::ostream& on_light_purple(std::ostream& os) { set_background("lp"); return os; } + std::ostream& on_light_yellow(std::ostream& os) { set_background("ly"); return os; } + std::ostream& on_bright_white(std::ostream& os) { set_background("bw"); return os; } + std::ostream& black_on_black(std::ostream& os) { set("k", "k"); return os; } + std::ostream& black_on_blue(std::ostream& os) { set("k", "b"); return os; } + std::ostream& black_on_green(std::ostream& os) { set("k", "g"); return os; } + std::ostream& black_on_aqua(std::ostream& os) { set("k", "a"); return os; } + std::ostream& black_on_red(std::ostream& os) { set("k", "r"); return os; } + std::ostream& black_on_purple(std::ostream& os) { set("k", "p"); return os; } + std::ostream& black_on_yellow(std::ostream& os) { set("k", "y"); return os; } + std::ostream& black_on_white(std::ostream& os) { set("k", "w"); return os; } + std::ostream& black_on_grey(std::ostream& os) { set("k", "e"); return os; } + std::ostream& black_on_light_blue(std::ostream& os) { set("k", "lb"); return os; } + std::ostream& black_on_light_green(std::ostream& os) { set("k", "lg"); return os; } + std::ostream& black_on_light_aqua(std::ostream& os) { set("k", "la"); return os; } + std::ostream& black_on_light_red(std::ostream& os) { set("k", "lr"); return os; } + std::ostream& black_on_light_purple(std::ostream& os) { set("k", "lp"); return os; } + std::ostream& black_on_light_yellow(std::ostream& os) { set("k", "ly"); return os; } + std::ostream& black_on_bright_white(std::ostream& os) { set("k", "bw"); return os; } + std::ostream& blue_on_black(std::ostream& os) { set("b", "k"); return os; } + std::ostream& blue_on_blue(std::ostream& os) { set("b", "b"); return os; } + std::ostream& blue_on_green(std::ostream& os) { set("b", "g"); return os; } + std::ostream& blue_on_aqua(std::ostream& os) { set("b", "a"); return os; } + std::ostream& blue_on_red(std::ostream& os) { set("b", "r"); return os; } + std::ostream& blue_on_purple(std::ostream& os) { set("b", "p"); return os; } + std::ostream& blue_on_yellow(std::ostream& os) { set("b", "y"); return os; } + std::ostream& blue_on_white(std::ostream& os) { set("b", "w"); return os; } + std::ostream& blue_on_grey(std::ostream& os) { set("b", "e"); return os; } + std::ostream& blue_on_light_blue(std::ostream& os) { set("b", "lb"); return os; } + std::ostream& blue_on_light_green(std::ostream& os) { set("b", "lg"); return os; } + std::ostream& blue_on_light_aqua(std::ostream& os) { set("b", "la"); return os; } + std::ostream& blue_on_light_red(std::ostream& os) { set("b", "lr"); return os; } + std::ostream& blue_on_light_purple(std::ostream& os) { set("b", "lp"); return os; } + std::ostream& blue_on_light_yellow(std::ostream& os) { set("b", "ly"); return os; } + std::ostream& blue_on_bright_white(std::ostream& os) { set("b", "bw"); return os; } + std::ostream& green_on_black(std::ostream& os) { set("g", "k"); return os; } + std::ostream& green_on_blue(std::ostream& os) { set("g", "b"); return os; } + std::ostream& green_on_green(std::ostream& os) { set("g", "g"); return os; } + std::ostream& green_on_aqua(std::ostream& os) { set("g", "a"); return os; } + std::ostream& green_on_red(std::ostream& os) { set("g", "r"); return os; } + std::ostream& green_on_purple(std::ostream& os) { set("g", "p"); return os; } + std::ostream& green_on_yellow(std::ostream& os) { set("g", "y"); return os; } + std::ostream& green_on_white(std::ostream& os) { set("g", "w"); return os; } + std::ostream& green_on_grey(std::ostream& os) { set("g", "e"); return os; } + std::ostream& green_on_light_blue(std::ostream& os) { set("g", "lb"); return os; } + std::ostream& green_on_light_green(std::ostream& os) { set("g", "lg"); return os; } + std::ostream& green_on_light_aqua(std::ostream& os) { set("g", "la"); return os; } + std::ostream& green_on_light_red(std::ostream& os) { set("g", "lr"); return os; } + std::ostream& green_on_light_purple(std::ostream& os) { set("g", "lp"); return os; } + std::ostream& green_on_light_yellow(std::ostream& os) { set("g", "ly"); return os; } + std::ostream& green_on_bright_white(std::ostream& os) { set("g", "bw"); return os; } + std::ostream& aqua_on_black(std::ostream& os) { set("a", "k"); return os; } + std::ostream& aqua_on_blue(std::ostream& os) { set("a", "b"); return os; } + std::ostream& aqua_on_green(std::ostream& os) { set("a", "g"); return os; } + std::ostream& aqua_on_aqua(std::ostream& os) { set("a", "a"); return os; } + std::ostream& aqua_on_red(std::ostream& os) { set("a", "r"); return os; } + std::ostream& aqua_on_purple(std::ostream& os) { set("a", "p"); return os; } + std::ostream& aqua_on_yellow(std::ostream& os) { set("a", "y"); return os; } + std::ostream& aqua_on_white(std::ostream& os) { set("a", "w"); return os; } + std::ostream& aqua_on_grey(std::ostream& os) { set("a", "e"); return os; } + std::ostream& aqua_on_light_blue(std::ostream& os) { set("a", "lb"); return os; } + std::ostream& aqua_on_light_green(std::ostream& os) { set("a", "lg"); return os; } + std::ostream& aqua_on_light_aqua(std::ostream& os) { set("a", "la"); return os; } + std::ostream& aqua_on_light_red(std::ostream& os) { set("a", "lr"); return os; } + std::ostream& aqua_on_light_purple(std::ostream& os) { set("a", "lp"); return os; } + std::ostream& aqua_on_light_yellow(std::ostream& os) { set("a", "ly"); return os; } + std::ostream& aqua_on_bright_white(std::ostream& os) { set("a", "bw"); return os; } + std::ostream& red_on_black(std::ostream& os) { set("r", "k"); return os; } + std::ostream& red_on_blue(std::ostream& os) { set("r", "b"); return os; } + std::ostream& red_on_green(std::ostream& os) { set("r", "g"); return os; } + std::ostream& red_on_aqua(std::ostream& os) { set("r", "a"); return os; } + std::ostream& red_on_red(std::ostream& os) { set("r", "r"); return os; } + std::ostream& red_on_purple(std::ostream& os) { set("r", "p"); return os; } + std::ostream& red_on_yellow(std::ostream& os) { set("r", "y"); return os; } + std::ostream& red_on_white(std::ostream& os) { set("r", "w"); return os; } + std::ostream& red_on_grey(std::ostream& os) { set("r", "e"); return os; } + std::ostream& red_on_light_blue(std::ostream& os) { set("r", "lb"); return os; } + std::ostream& red_on_light_green(std::ostream& os) { set("r", "lg"); return os; } + std::ostream& red_on_light_aqua(std::ostream& os) { set("r", "la"); return os; } + std::ostream& red_on_light_red(std::ostream& os) { set("r", "lr"); return os; } + std::ostream& red_on_light_purple(std::ostream& os) { set("r", "lp"); return os; } + std::ostream& red_on_light_yellow(std::ostream& os) { set("r", "ly"); return os; } + std::ostream& red_on_bright_white(std::ostream& os) { set("r", "bw"); return os; } + std::ostream& purple_on_black(std::ostream& os) { set("p", "k"); return os; } + std::ostream& purple_on_blue(std::ostream& os) { set("p", "b"); return os; } + std::ostream& purple_on_green(std::ostream& os) { set("p", "g"); return os; } + std::ostream& purple_on_aqua(std::ostream& os) { set("p", "a"); return os; } + std::ostream& purple_on_red(std::ostream& os) { set("p", "r"); return os; } + std::ostream& purple_on_purple(std::ostream& os) { set("p", "p"); return os; } + std::ostream& purple_on_yellow(std::ostream& os) { set("p", "y"); return os; } + std::ostream& purple_on_white(std::ostream& os) { set("p", "w"); return os; } + std::ostream& purple_on_grey(std::ostream& os) { set("p", "e"); return os; } + std::ostream& purple_on_light_blue(std::ostream& os) { set("p", "lb"); return os; } + std::ostream& purple_on_light_green(std::ostream& os) { set("p", "lg"); return os; } + std::ostream& purple_on_light_aqua(std::ostream& os) { set("p", "la"); return os; } + std::ostream& purple_on_light_red(std::ostream& os) { set("p", "lr"); return os; } + std::ostream& purple_on_light_purple(std::ostream& os) { set("p", "lp"); return os; } + std::ostream& purple_on_light_yellow(std::ostream& os) { set("p", "ly"); return os; } + std::ostream& purple_on_bright_white(std::ostream& os) { set("p", "bw"); return os; } + std::ostream& yellow_on_black(std::ostream& os) { set("y", "k"); return os; } + std::ostream& yellow_on_blue(std::ostream& os) { set("y", "b"); return os; } + std::ostream& yellow_on_green(std::ostream& os) { set("y", "g"); return os; } + std::ostream& yellow_on_aqua(std::ostream& os) { set("y", "a"); return os; } + std::ostream& yellow_on_red(std::ostream& os) { set("y", "r"); return os; } + std::ostream& yellow_on_purple(std::ostream& os) { set("y", "p"); return os; } + std::ostream& yellow_on_yellow(std::ostream& os) { set("y", "y"); return os; } + std::ostream& yellow_on_white(std::ostream& os) { set("y", "w"); return os; } + std::ostream& yellow_on_grey(std::ostream& os) { set("y", "e"); return os; } + std::ostream& yellow_on_light_blue(std::ostream& os) { set("y", "lb"); return os; } + std::ostream& yellow_on_light_green(std::ostream& os) { set("y", "lg"); return os; } + std::ostream& yellow_on_light_aqua(std::ostream& os) { set("y", "la"); return os; } + std::ostream& yellow_on_light_red(std::ostream& os) { set("y", "lr"); return os; } + std::ostream& yellow_on_light_purple(std::ostream& os) { set("y", "lp"); return os; } + std::ostream& yellow_on_light_yellow(std::ostream& os) { set("y", "ly"); return os; } + std::ostream& yellow_on_bright_white(std::ostream& os) { set("y", "bw"); return os; } + std::ostream& white_on_black(std::ostream& os) { set("w", "k"); return os; } + std::ostream& white_on_blue(std::ostream& os) { set("w", "b"); return os; } + std::ostream& white_on_green(std::ostream& os) { set("w", "g"); return os; } + std::ostream& white_on_aqua(std::ostream& os) { set("w", "a"); return os; } + std::ostream& white_on_red(std::ostream& os) { set("w", "r"); return os; } + std::ostream& white_on_purple(std::ostream& os) { set("w", "p"); return os; } + std::ostream& white_on_yellow(std::ostream& os) { set("w", "y"); return os; } + std::ostream& white_on_white(std::ostream& os) { set("w", "w"); return os; } + std::ostream& white_on_grey(std::ostream& os) { set("w", "e"); return os; } + std::ostream& white_on_light_blue(std::ostream& os) { set("w", "lb"); return os; } + std::ostream& white_on_light_green(std::ostream& os) { set("w", "lg"); return os; } + std::ostream& white_on_light_aqua(std::ostream& os) { set("w", "la"); return os; } + std::ostream& white_on_light_red(std::ostream& os) { set("w", "lr"); return os; } + std::ostream& white_on_light_purple(std::ostream& os) { set("w", "lp"); return os; } + std::ostream& white_on_light_yellow(std::ostream& os) { set("w", "ly"); return os; } + std::ostream& white_on_bright_white(std::ostream& os) { set("w", "bw"); return os; } + std::ostream& grey_on_black(std::ostream& os) { set("e", "k"); return os; } + std::ostream& grey_on_blue(std::ostream& os) { set("e", "b"); return os; } + std::ostream& grey_on_green(std::ostream& os) { set("e", "g"); return os; } + std::ostream& grey_on_aqua(std::ostream& os) { set("e", "a"); return os; } + std::ostream& grey_on_red(std::ostream& os) { set("e", "r"); return os; } + std::ostream& grey_on_purple(std::ostream& os) { set("e", "p"); return os; } + std::ostream& grey_on_yellow(std::ostream& os) { set("e", "y"); return os; } + std::ostream& grey_on_white(std::ostream& os) { set("e", "w"); return os; } + std::ostream& grey_on_grey(std::ostream& os) { set("e", "e"); return os; } + std::ostream& grey_on_light_blue(std::ostream& os) { set("e", "lb"); return os; } + std::ostream& grey_on_light_green(std::ostream& os) { set("e", "lg"); return os; } + std::ostream& grey_on_light_aqua(std::ostream& os) { set("e", "la"); return os; } + std::ostream& grey_on_light_red(std::ostream& os) { set("e", "lr"); return os; } + std::ostream& grey_on_light_purple(std::ostream& os) { set("e", "lp"); return os; } + std::ostream& grey_on_light_yellow(std::ostream& os) { set("e", "ly"); return os; } + std::ostream& grey_on_bright_white(std::ostream& os) { set("e", "bw"); return os; } + std::ostream& light_blue_on_black(std::ostream& os) { set("lb", "k"); return os; } + std::ostream& light_blue_on_blue(std::ostream& os) { set("lb", "b"); return os; } + std::ostream& light_blue_on_green(std::ostream& os) { set("lb", "g"); return os; } + std::ostream& light_blue_on_aqua(std::ostream& os) { set("lb", "a"); return os; } + std::ostream& light_blue_on_red(std::ostream& os) { set("lb", "r"); return os; } + std::ostream& light_blue_on_purple(std::ostream& os) { set("lb", "p"); return os; } + std::ostream& light_blue_on_yellow(std::ostream& os) { set("lb", "y"); return os; } + std::ostream& light_blue_on_white(std::ostream& os) { set("lb", "w"); return os; } + std::ostream& light_blue_on_grey(std::ostream& os) { set("lb", "e"); return os; } + std::ostream& light_blue_on_light_blue(std::ostream& os) { set("lb", "lb"); return os; } + std::ostream& light_blue_on_light_green(std::ostream& os) { set("lb", "lg"); return os; } + std::ostream& light_blue_on_light_aqua(std::ostream& os) { set("lb", "la"); return os; } + std::ostream& light_blue_on_light_red(std::ostream& os) { set("lb", "lr"); return os; } + std::ostream& light_blue_on_light_purple(std::ostream& os) { set("lb", "lp"); return os; } + std::ostream& light_blue_on_light_yellow(std::ostream& os) { set("lb", "ly"); return os; } + std::ostream& light_blue_on_bright_white(std::ostream& os) { set("lb", "bw"); return os; } + std::ostream& light_green_on_black(std::ostream& os) { set("lg", "k"); return os; } + std::ostream& light_green_on_blue(std::ostream& os) { set("lg", "b"); return os; } + std::ostream& light_green_on_green(std::ostream& os) { set("lg", "g"); return os; } + std::ostream& light_green_on_aqua(std::ostream& os) { set("lg", "a"); return os; } + std::ostream& light_green_on_red(std::ostream& os) { set("lg", "r"); return os; } + std::ostream& light_green_on_purple(std::ostream& os) { set("lg", "p"); return os; } + std::ostream& light_green_on_yellow(std::ostream& os) { set("lg", "y"); return os; } + std::ostream& light_green_on_white(std::ostream& os) { set("lg", "w"); return os; } + std::ostream& light_green_on_grey(std::ostream& os) { set("lg", "e"); return os; } + std::ostream& light_green_on_light_blue(std::ostream& os) { set("lg", "lb"); return os; } + std::ostream& light_green_on_light_green(std::ostream& os) { set("lg", "lg"); return os; } + std::ostream& light_green_on_light_aqua(std::ostream& os) { set("lg", "la"); return os; } + std::ostream& light_green_on_light_red(std::ostream& os) { set("lg", "lr"); return os; } + std::ostream& light_green_on_light_purple(std::ostream& os) { set("lg", "lp"); return os; } + std::ostream& light_green_on_light_yellow(std::ostream& os) { set("lg", "ly"); return os; } + std::ostream& light_green_on_bright_white(std::ostream& os) { set("lg", "bw"); return os; } + std::ostream& light_aqua_on_black(std::ostream& os) { set("la", "k"); return os; } + std::ostream& light_aqua_on_blue(std::ostream& os) { set("la", "b"); return os; } + std::ostream& light_aqua_on_green(std::ostream& os) { set("la", "g"); return os; } + std::ostream& light_aqua_on_aqua(std::ostream& os) { set("la", "a"); return os; } + std::ostream& light_aqua_on_red(std::ostream& os) { set("la", "r"); return os; } + std::ostream& light_aqua_on_purple(std::ostream& os) { set("la", "p"); return os; } + std::ostream& light_aqua_on_yellow(std::ostream& os) { set("la", "y"); return os; } + std::ostream& light_aqua_on_white(std::ostream& os) { set("la", "w"); return os; } + std::ostream& light_aqua_on_grey(std::ostream& os) { set("la", "e"); return os; } + std::ostream& light_aqua_on_light_blue(std::ostream& os) { set("la", "lb"); return os; } + std::ostream& light_aqua_on_light_green(std::ostream& os) { set("la", "lg"); return os; } + std::ostream& light_aqua_on_light_aqua(std::ostream& os) { set("la", "la"); return os; } + std::ostream& light_aqua_on_light_red(std::ostream& os) { set("la", "lr"); return os; } + std::ostream& light_aqua_on_light_purple(std::ostream& os) { set("la", "lp"); return os; } + std::ostream& light_aqua_on_light_yellow(std::ostream& os) { set("la", "ly"); return os; } + std::ostream& light_aqua_on_bright_white(std::ostream& os) { set("la", "bw"); return os; } + std::ostream& light_red_on_black(std::ostream& os) { set("lr", "k"); return os; } + std::ostream& light_red_on_blue(std::ostream& os) { set("lr", "b"); return os; } + std::ostream& light_red_on_green(std::ostream& os) { set("lr", "g"); return os; } + std::ostream& light_red_on_aqua(std::ostream& os) { set("lr", "a"); return os; } + std::ostream& light_red_on_red(std::ostream& os) { set("lr", "r"); return os; } + std::ostream& light_red_on_purple(std::ostream& os) { set("lr", "p"); return os; } + std::ostream& light_red_on_yellow(std::ostream& os) { set("lr", "y"); return os; } + std::ostream& light_red_on_white(std::ostream& os) { set("lr", "w"); return os; } + std::ostream& light_red_on_grey(std::ostream& os) { set("lr", "e"); return os; } + std::ostream& light_red_on_light_blue(std::ostream& os) { set("lr", "lb"); return os; } + std::ostream& light_red_on_light_green(std::ostream& os) { set("lr", "lg"); return os; } + std::ostream& light_red_on_light_aqua(std::ostream& os) { set("lr", "la"); return os; } + std::ostream& light_red_on_light_red(std::ostream& os) { set("lr", "lr"); return os; } + std::ostream& light_red_on_light_purple(std::ostream& os) { set("lr", "lp"); return os; } + std::ostream& light_red_on_light_yellow(std::ostream& os) { set("lr", "ly"); return os; } + std::ostream& light_red_on_bright_white(std::ostream& os) { set("lr", "bw"); return os; } + std::ostream& light_purple_on_black(std::ostream& os) { set("lp", "k"); return os; } + std::ostream& light_purple_on_blue(std::ostream& os) { set("lp", "b"); return os; } + std::ostream& light_purple_on_green(std::ostream& os) { set("lp", "g"); return os; } + std::ostream& light_purple_on_aqua(std::ostream& os) { set("lp", "a"); return os; } + std::ostream& light_purple_on_red(std::ostream& os) { set("lp", "r"); return os; } + std::ostream& light_purple_on_purple(std::ostream& os) { set("lp", "p"); return os; } + std::ostream& light_purple_on_yellow(std::ostream& os) { set("lp", "y"); return os; } + std::ostream& light_purple_on_white(std::ostream& os) { set("lp", "w"); return os; } + std::ostream& light_purple_on_grey(std::ostream& os) { set("lp", "e"); return os; } + std::ostream& light_purple_on_light_blue(std::ostream& os) { set("lp", "lb"); return os; } + std::ostream& light_purple_on_light_green(std::ostream& os) { set("lp", "lg"); return os; } + std::ostream& light_purple_on_light_aqua(std::ostream& os) { set("lp", "la"); return os; } + std::ostream& light_purple_on_light_red(std::ostream& os) { set("lp", "lr"); return os; } + std::ostream& light_purple_on_light_purple(std::ostream& os) { set("lp", "lp"); return os; } + std::ostream& light_purple_on_light_yellow(std::ostream& os) { set("lp", "ly"); return os; } + std::ostream& light_purple_on_bright_white(std::ostream& os) { set("lp", "bw"); return os; } + std::ostream& light_yellow_on_black(std::ostream& os) { set("ly", "k"); return os; } + std::ostream& light_yellow_on_blue(std::ostream& os) { set("ly", "b"); return os; } + std::ostream& light_yellow_on_green(std::ostream& os) { set("ly", "g"); return os; } + std::ostream& light_yellow_on_aqua(std::ostream& os) { set("ly", "a"); return os; } + std::ostream& light_yellow_on_red(std::ostream& os) { set("ly", "r"); return os; } + std::ostream& light_yellow_on_purple(std::ostream& os) { set("ly", "p"); return os; } + std::ostream& light_yellow_on_yellow(std::ostream& os) { set("ly", "y"); return os; } + std::ostream& light_yellow_on_white(std::ostream& os) { set("ly", "w"); return os; } + std::ostream& light_yellow_on_grey(std::ostream& os) { set("ly", "e"); return os; } + std::ostream& light_yellow_on_light_blue(std::ostream& os) { set("ly", "lb"); return os; } + std::ostream& light_yellow_on_light_green(std::ostream& os) { set("ly", "lg"); return os; } + std::ostream& light_yellow_on_light_aqua(std::ostream& os) { set("ly", "la"); return os; } + std::ostream& light_yellow_on_light_red(std::ostream& os) { set("ly", "lr"); return os; } + std::ostream& light_yellow_on_light_purple(std::ostream& os) { set("ly", "lp"); return os; } + std::ostream& light_yellow_on_light_yellow(std::ostream& os) { set("ly", "ly"); return os; } + std::ostream& light_yellow_on_bright_white(std::ostream& os) { set("ly", "bw"); return os; } + std::ostream& bright_white_on_black(std::ostream& os) { set("bw", "k"); return os; } + std::ostream& bright_white_on_blue(std::ostream& os) { set("bw", "b"); return os; } + std::ostream& bright_white_on_green(std::ostream& os) { set("bw", "g"); return os; } + std::ostream& bright_white_on_aqua(std::ostream& os) { set("bw", "a"); return os; } + std::ostream& bright_white_on_red(std::ostream& os) { set("bw", "r"); return os; } + std::ostream& bright_white_on_purple(std::ostream& os) { set("bw", "p"); return os; } + std::ostream& bright_white_on_yellow(std::ostream& os) { set("bw", "y"); return os; } + std::ostream& bright_white_on_white(std::ostream& os) { set("bw", "w"); return os; } + std::ostream& bright_white_on_grey(std::ostream& os) { set("bw", "e"); return os; } + std::ostream& bright_white_on_light_blue(std::ostream& os) { set("bw", "lb"); return os; } + std::ostream& bright_white_on_light_green(std::ostream& os) { set("bw", "lg"); return os; } + std::ostream& bright_white_on_light_aqua(std::ostream& os) { set("bw", "la"); return os; } + std::ostream& bright_white_on_light_red(std::ostream& os) { set("bw", "lr"); return os; } + std::ostream& bright_white_on_light_purple(std::ostream& os) { set("bw", "lp"); return os; } + std::ostream& bright_white_on_light_yellow(std::ostream& os) { set("bw", "ly"); return os; } + std::ostream& bright_white_on_bright_white(std::ostream& os) { set("bw", "bw"); return os; } +} + + +namespace dye +{ + template + using bar = typename std::conditional::value, std::string, T>::type; + + template class colorful; + template class item; + + template + class colorful : private std::list> + { + public: + using std::list>::list; + + colorful& operator+=(const colorful& rhs) + { + this->insert(this->end(), rhs.begin(), rhs.end()); + return *this; + } + + colorful& operator+=(colorful&& rhs) + { + this->splice(this->end(), std::move(rhs)); + return *this; + } + + colorful& operator+=(T t) + { + this->push_back(std::move(t)); + return *this; + } + + void push_front(T t) + { + this->std::list>::push_front(item(std::move(t))); + } + + void push_back(T t) + { + this->std::list>::push_back(item(std::move(t))); + } + + colorful& invert() + { + for (auto& elem : *this) + elem.invert(); + return *this; + } + + template + friend std::ostream& operator<<(std::ostream&, const colorful&); + + template + friend colorful invert(colorful col); + }; + + template + colorful operator+(colorful lhs, colorful rhs) + { + colorful res(std::move(lhs)); + return res += rhs; + } + + template + colorful operator+(colorful lhs, std::string rhs) + { + colorful res(std::move(lhs)); + res.push_back(std::move(rhs)); + return res; + } + + template + colorful operator+(const std::string& lhs, colorful rhs) + { + colorful res(std::move(rhs)); + res.push_front(std::move(lhs)); + return res; + } + + template + std::ostream& operator<<(std::ostream& os, const colorful& colorful) + { + for (const auto& elem : colorful) + os << elem; + return os; + } + + template + colorful invert(colorful col) + { + colorful res(std::move(col)); + for (auto& elem : res) + elem.invert(); + return res; + } + + template + class item + { + T thing; + int color; + + public: + item(T t) : thing(std::move(t)), color(hue::get()) {} + item(T t, int a) : thing(std::move(t)), color(hue::itoc(a)) {} + item(T t, int a, int b) : thing(std::move(t)), color(hue::itoc(a, b)) {} + item(T t, std::string a) : thing(std::move(t)), color(hue::stoc(a)) {} + item(T t, std::string a, std::string b) : thing(std::move(t)), color(hue::stoc(a, b)) {} + + item& invert() + { + color = hue::invert(color); + return *this; + } + + template + friend class colorful; + + template + friend std::ostream& operator<<(std::ostream&, const item&); + }; + + template + std::ostream& operator<<(std::ostream& os, const item& it) + { + hue::set(it.color); + os << it.thing; + hue::reset(); + return os; + } + + template using R = colorful>; + template using S = item>; + + template R colorize(T t, std::string a) { return R { S(t, a) }; } + template R vanilla(T t) { return R { S(t) }; } + template R black(T t) { return R { S(t, "k") }; } + template R blue(T t) { return R { S(t, "b") }; } + template R green(T t) { return R { S(t, "g") }; } + template R aqua(T t) { return R { S(t, "a") }; } + template R red(T t) { return R { S(t, "r") }; } + template R purple(T t) { return R { S(t, "p") }; } + template R yellow(T t) { return R { S(t, "y") }; } + template R white(T t) { return R { S(t, "w") }; } + template R grey(T t) { return R { S(t, "e") }; } + template R light_blue(T t) { return R { S(t, "lb") }; } + template R light_green(T t) { return R { S(t, "lg") }; } + template R light_aqua(T t) { return R { S(t, "la") }; } + template R light_red(T t) { return R { S(t, "lr") }; } + template R light_purple(T t) { return R { S(t, "lp") }; } + template R light_yellow(T t) { return R { S(t, "ly") }; } + template R bright_white(T t) { return R { S(t, "bw") }; } + template R on_black(T t) { return R { S(t, "k", "k") }; } + template R on_blue(T t) { return R { S(t, "k", "b") }; } + template R on_green(T t) { return R { S(t, "k", "g") }; } + template R on_aqua(T t) { return R { S(t, "k", "a") }; } + template R on_red(T t) { return R { S(t, "k", "r") }; } + template R on_purple(T t) { return R { S(t, "k", "p") }; } + template R on_yellow(T t) { return R { S(t, "k", "y") }; } + template R on_white(T t) { return R { S(t, "k", "w") }; } + template R on_grey(T t) { return R { S(t, "k", "e") }; } + template R on_light_blue(T t) { return R { S(t, "k", "lb") }; } + template R on_light_green(T t) { return R { S(t, "k", "lg") }; } + template R on_light_aqua(T t) { return R { S(t, "k", "la") }; } + template R on_light_red(T t) { return R { S(t, "k", "lr") }; } + template R on_light_purple(T t) { return R { S(t, "k", "lp") }; } + template R on_light_yellow(T t) { return R { S(t, "k", "ly") }; } + template R on_bright_white(T t) { return R { S(t, "k", "bw") }; } + template R black_on_black(T t) { return R { S(t, "k", "k") }; } + template R black_on_blue(T t) { return R { S(t, "k", "b") }; } + template R black_on_green(T t) { return R { S(t, "k", "g") }; } + template R black_on_aqua(T t) { return R { S(t, "k", "a") }; } + template R black_on_red(T t) { return R { S(t, "k", "r") }; } + template R black_on_purple(T t) { return R { S(t, "k", "p") }; } + template R black_on_yellow(T t) { return R { S(t, "k", "y") }; } + template R black_on_white(T t) { return R { S(t, "k", "w") }; } + template R black_on_grey(T t) { return R { S(t, "k", "e") }; } + template R black_on_light_blue(T t) { return R { S(t, "k", "lb") }; } + template R black_on_light_green(T t) { return R { S(t, "k", "lg") }; } + template R black_on_light_aqua(T t) { return R { S(t, "k", "la") }; } + template R black_on_light_red(T t) { return R { S(t, "k", "lr") }; } + template R black_on_light_purple(T t) { return R { S(t, "k", "lp") }; } + template R black_on_light_yellow(T t) { return R { S(t, "k", "ly") }; } + template R black_on_bright_white(T t) { return R { S(t, "k", "bw") }; } + template R blue_on_black(T t) { return R { S(t, "b", "k") }; } + template R blue_on_blue(T t) { return R { S(t, "b", "b") }; } + template R blue_on_green(T t) { return R { S(t, "b", "g") }; } + template R blue_on_aqua(T t) { return R { S(t, "b", "a") }; } + template R blue_on_red(T t) { return R { S(t, "b", "r") }; } + template R blue_on_purple(T t) { return R { S(t, "b", "p") }; } + template R blue_on_yellow(T t) { return R { S(t, "b", "y") }; } + template R blue_on_white(T t) { return R { S(t, "b", "w") }; } + template R blue_on_grey(T t) { return R { S(t, "b", "e") }; } + template R blue_on_light_blue(T t) { return R { S(t, "b", "lb") }; } + template R blue_on_light_green(T t) { return R { S(t, "b", "lg") }; } + template R blue_on_light_aqua(T t) { return R { S(t, "b", "la") }; } + template R blue_on_light_red(T t) { return R { S(t, "b", "lr") }; } + template R blue_on_light_purple(T t) { return R { S(t, "b", "lp") }; } + template R blue_on_light_yellow(T t) { return R { S(t, "b", "ly") }; } + template R blue_on_bright_white(T t) { return R { S(t, "b", "bw") }; } + template R green_on_black(T t) { return R { S(t, "g", "k") }; } + template R green_on_blue(T t) { return R { S(t, "g", "b") }; } + template R green_on_green(T t) { return R { S(t, "g", "g") }; } + template R green_on_aqua(T t) { return R { S(t, "g", "a") }; } + template R green_on_red(T t) { return R { S(t, "g", "r") }; } + template R green_on_purple(T t) { return R { S(t, "g", "p") }; } + template R green_on_yellow(T t) { return R { S(t, "g", "y") }; } + template R green_on_white(T t) { return R { S(t, "g", "w") }; } + template R green_on_grey(T t) { return R { S(t, "g", "e") }; } + template R green_on_light_blue(T t) { return R { S(t, "g", "lb") }; } + template R green_on_light_green(T t) { return R { S(t, "g", "lg") }; } + template R green_on_light_aqua(T t) { return R { S(t, "g", "la") }; } + template R green_on_light_red(T t) { return R { S(t, "g", "lr") }; } + template R green_on_light_purple(T t) { return R { S(t, "g", "lp") }; } + template R green_on_light_yellow(T t) { return R { S(t, "g", "ly") }; } + template R green_on_bright_white(T t) { return R { S(t, "g", "bw") }; } + template R aqua_on_black(T t) { return R { S(t, "a", "k") }; } + template R aqua_on_blue(T t) { return R { S(t, "a", "b") }; } + template R aqua_on_green(T t) { return R { S(t, "a", "g") }; } + template R aqua_on_aqua(T t) { return R { S(t, "a", "a") }; } + template R aqua_on_red(T t) { return R { S(t, "a", "r") }; } + template R aqua_on_purple(T t) { return R { S(t, "a", "p") }; } + template R aqua_on_yellow(T t) { return R { S(t, "a", "y") }; } + template R aqua_on_white(T t) { return R { S(t, "a", "w") }; } + template R aqua_on_grey(T t) { return R { S(t, "a", "e") }; } + template R aqua_on_light_blue(T t) { return R { S(t, "a", "lb") }; } + template R aqua_on_light_green(T t) { return R { S(t, "a", "lg") }; } + template R aqua_on_light_aqua(T t) { return R { S(t, "a", "la") }; } + template R aqua_on_light_red(T t) { return R { S(t, "a", "lr") }; } + template R aqua_on_light_purple(T t) { return R { S(t, "a", "lp") }; } + template R aqua_on_light_yellow(T t) { return R { S(t, "a", "ly") }; } + template R aqua_on_bright_white(T t) { return R { S(t, "a", "bw") }; } + template R red_on_black(T t) { return R { S(t, "r", "k") }; } + template R red_on_blue(T t) { return R { S(t, "r", "b") }; } + template R red_on_green(T t) { return R { S(t, "r", "g") }; } + template R red_on_aqua(T t) { return R { S(t, "r", "a") }; } + template R red_on_red(T t) { return R { S(t, "r", "r") }; } + template R red_on_purple(T t) { return R { S(t, "r", "p") }; } + template R red_on_yellow(T t) { return R { S(t, "r", "y") }; } + template R red_on_white(T t) { return R { S(t, "r", "w") }; } + template R red_on_grey(T t) { return R { S(t, "r", "e") }; } + template R red_on_light_blue(T t) { return R { S(t, "r", "lb") }; } + template R red_on_light_green(T t) { return R { S(t, "r", "lg") }; } + template R red_on_light_aqua(T t) { return R { S(t, "r", "la") }; } + template R red_on_light_red(T t) { return R { S(t, "r", "lr") }; } + template R red_on_light_purple(T t) { return R { S(t, "r", "lp") }; } + template R red_on_light_yellow(T t) { return R { S(t, "r", "ly") }; } + template R red_on_bright_white(T t) { return R { S(t, "r", "bw") }; } + template R purple_on_black(T t) { return R { S(t, "p", "k") }; } + template R purple_on_blue(T t) { return R { S(t, "p", "b") }; } + template R purple_on_green(T t) { return R { S(t, "p", "g") }; } + template R purple_on_aqua(T t) { return R { S(t, "p", "a") }; } + template R purple_on_red(T t) { return R { S(t, "p", "r") }; } + template R purple_on_purple(T t) { return R { S(t, "p", "p") }; } + template R purple_on_yellow(T t) { return R { S(t, "p", "y") }; } + template R purple_on_white(T t) { return R { S(t, "p", "w") }; } + template R purple_on_grey(T t) { return R { S(t, "p", "e") }; } + template R purple_on_light_blue(T t) { return R { S(t, "p", "lb") }; } + template R purple_on_light_green(T t) { return R { S(t, "p", "lg") }; } + template R purple_on_light_aqua(T t) { return R { S(t, "p", "la") }; } + template R purple_on_light_red(T t) { return R { S(t, "p", "lr") }; } + template R purple_on_light_purple(T t) { return R { S(t, "p", "lp") }; } + template R purple_on_light_yellow(T t) { return R { S(t, "p", "ly") }; } + template R purple_on_bright_white(T t) { return R { S(t, "p", "bw") }; } + template R yellow_on_black(T t) { return R { S(t, "y", "k") }; } + template R yellow_on_blue(T t) { return R { S(t, "y", "b") }; } + template R yellow_on_green(T t) { return R { S(t, "y", "g") }; } + template R yellow_on_aqua(T t) { return R { S(t, "y", "a") }; } + template R yellow_on_red(T t) { return R { S(t, "y", "r") }; } + template R yellow_on_purple(T t) { return R { S(t, "y", "p") }; } + template R yellow_on_yellow(T t) { return R { S(t, "y", "y") }; } + template R yellow_on_white(T t) { return R { S(t, "y", "w") }; } + template R yellow_on_grey(T t) { return R { S(t, "y", "e") }; } + template R yellow_on_light_blue(T t) { return R { S(t, "y", "lb") }; } + template R yellow_on_light_green(T t) { return R { S(t, "y", "lg") }; } + template R yellow_on_light_aqua(T t) { return R { S(t, "y", "la") }; } + template R yellow_on_light_red(T t) { return R { S(t, "y", "lr") }; } + template R yellow_on_light_purple(T t) { return R { S(t, "y", "lp") }; } + template R yellow_on_light_yellow(T t) { return R { S(t, "y", "ly") }; } + template R yellow_on_bright_white(T t) { return R { S(t, "y", "bw") }; } + template R white_on_black(T t) { return R { S(t, "w", "k") }; } + template R white_on_blue(T t) { return R { S(t, "w", "b") }; } + template R white_on_green(T t) { return R { S(t, "w", "g") }; } + template R white_on_aqua(T t) { return R { S(t, "w", "a") }; } + template R white_on_red(T t) { return R { S(t, "w", "r") }; } + template R white_on_purple(T t) { return R { S(t, "w", "p") }; } + template R white_on_yellow(T t) { return R { S(t, "w", "y") }; } + template R white_on_white(T t) { return R { S(t, "w", "w") }; } + template R white_on_grey(T t) { return R { S(t, "w", "e") }; } + template R white_on_light_blue(T t) { return R { S(t, "w", "lb") }; } + template R white_on_light_green(T t) { return R { S(t, "w", "lg") }; } + template R white_on_light_aqua(T t) { return R { S(t, "w", "la") }; } + template R white_on_light_red(T t) { return R { S(t, "w", "lr") }; } + template R white_on_light_purple(T t) { return R { S(t, "w", "lp") }; } + template R white_on_light_yellow(T t) { return R { S(t, "w", "ly") }; } + template R white_on_bright_white(T t) { return R { S(t, "w", "bw") }; } + template R grey_on_black(T t) { return R { S(t, "e", "k") }; } + template R grey_on_blue(T t) { return R { S(t, "e", "b") }; } + template R grey_on_green(T t) { return R { S(t, "e", "g") }; } + template R grey_on_aqua(T t) { return R { S(t, "e", "a") }; } + template R grey_on_red(T t) { return R { S(t, "e", "r") }; } + template R grey_on_purple(T t) { return R { S(t, "e", "p") }; } + template R grey_on_yellow(T t) { return R { S(t, "e", "y") }; } + template R grey_on_white(T t) { return R { S(t, "e", "w") }; } + template R grey_on_grey(T t) { return R { S(t, "e", "e") }; } + template R grey_on_light_blue(T t) { return R { S(t, "e", "lb") }; } + template R grey_on_light_green(T t) { return R { S(t, "e", "lg") }; } + template R grey_on_light_aqua(T t) { return R { S(t, "e", "la") }; } + template R grey_on_light_red(T t) { return R { S(t, "e", "lr") }; } + template R grey_on_light_purple(T t) { return R { S(t, "e", "lp") }; } + template R grey_on_light_yellow(T t) { return R { S(t, "e", "ly") }; } + template R grey_on_bright_white(T t) { return R { S(t, "e", "bw") }; } + template R light_blue_on_black(T t) { return R { S(t, "lb", "k") }; } + template R light_blue_on_blue(T t) { return R { S(t, "lb", "b") }; } + template R light_blue_on_green(T t) { return R { S(t, "lb", "g") }; } + template R light_blue_on_aqua(T t) { return R { S(t, "lb", "a") }; } + template R light_blue_on_red(T t) { return R { S(t, "lb", "r") }; } + template R light_blue_on_purple(T t) { return R { S(t, "lb", "p") }; } + template R light_blue_on_yellow(T t) { return R { S(t, "lb", "y") }; } + template R light_blue_on_white(T t) { return R { S(t, "lb", "w") }; } + template R light_blue_on_grey(T t) { return R { S(t, "lb", "e") }; } + template R light_blue_on_light_blue(T t) { return R { S(t, "lb", "lb") }; } + template R light_blue_on_light_green(T t) { return R { S(t, "lb", "lg") }; } + template R light_blue_on_light_aqua(T t) { return R { S(t, "lb", "la") }; } + template R light_blue_on_light_red(T t) { return R { S(t, "lb", "lr") }; } + template R light_blue_on_light_purple(T t) { return R { S(t, "lb", "lp") }; } + template R light_blue_on_light_yellow(T t) { return R { S(t, "lb", "ly") }; } + template R light_blue_on_bright_white(T t) { return R { S(t, "lb", "bw") }; } + template R light_green_on_black(T t) { return R { S(t, "lg", "k") }; } + template R light_green_on_blue(T t) { return R { S(t, "lg", "b") }; } + template R light_green_on_green(T t) { return R { S(t, "lg", "g") }; } + template R light_green_on_aqua(T t) { return R { S(t, "lg", "a") }; } + template R light_green_on_red(T t) { return R { S(t, "lg", "r") }; } + template R light_green_on_purple(T t) { return R { S(t, "lg", "p") }; } + template R light_green_on_yellow(T t) { return R { S(t, "lg", "y") }; } + template R light_green_on_white(T t) { return R { S(t, "lg", "w") }; } + template R light_green_on_grey(T t) { return R { S(t, "lg", "e") }; } + template R light_green_on_light_blue(T t) { return R { S(t, "lg", "lb") }; } + template R light_green_on_light_green(T t) { return R { S(t, "lg", "lg") }; } + template R light_green_on_light_aqua(T t) { return R { S(t, "lg", "la") }; } + template R light_green_on_light_red(T t) { return R { S(t, "lg", "lr") }; } + template R light_green_on_light_purple(T t) { return R { S(t, "lg", "lp") }; } + template R light_green_on_light_yellow(T t) { return R { S(t, "lg", "ly") }; } + template R light_green_on_bright_white(T t) { return R { S(t, "lg", "bw") }; } + template R light_aqua_on_black(T t) { return R { S(t, "la", "k") }; } + template R light_aqua_on_blue(T t) { return R { S(t, "la", "b") }; } + template R light_aqua_on_green(T t) { return R { S(t, "la", "g") }; } + template R light_aqua_on_aqua(T t) { return R { S(t, "la", "a") }; } + template R light_aqua_on_red(T t) { return R { S(t, "la", "r") }; } + template R light_aqua_on_purple(T t) { return R { S(t, "la", "p") }; } + template R light_aqua_on_yellow(T t) { return R { S(t, "la", "y") }; } + template R light_aqua_on_white(T t) { return R { S(t, "la", "w") }; } + template R light_aqua_on_grey(T t) { return R { S(t, "la", "e") }; } + template R light_aqua_on_light_blue(T t) { return R { S(t, "la", "lb") }; } + template R light_aqua_on_light_green(T t) { return R { S(t, "la", "lg") }; } + template R light_aqua_on_light_aqua(T t) { return R { S(t, "la", "la") }; } + template R light_aqua_on_light_red(T t) { return R { S(t, "la", "lr") }; } + template R light_aqua_on_light_purple(T t) { return R { S(t, "la", "lp") }; } + template R light_aqua_on_light_yellow(T t) { return R { S(t, "la", "ly") }; } + template R light_aqua_on_bright_white(T t) { return R { S(t, "la", "bw") }; } + template R light_red_on_black(T t) { return R { S(t, "lr", "k") }; } + template R light_red_on_blue(T t) { return R { S(t, "lr", "b") }; } + template R light_red_on_green(T t) { return R { S(t, "lr", "g") }; } + template R light_red_on_aqua(T t) { return R { S(t, "lr", "a") }; } + template R light_red_on_red(T t) { return R { S(t, "lr", "r") }; } + template R light_red_on_purple(T t) { return R { S(t, "lr", "p") }; } + template R light_red_on_yellow(T t) { return R { S(t, "lr", "y") }; } + template R light_red_on_white(T t) { return R { S(t, "lr", "w") }; } + template R light_red_on_grey(T t) { return R { S(t, "lr", "e") }; } + template R light_red_on_light_blue(T t) { return R { S(t, "lr", "lb") }; } + template R light_red_on_light_green(T t) { return R { S(t, "lr", "lg") }; } + template R light_red_on_light_aqua(T t) { return R { S(t, "lr", "la") }; } + template R light_red_on_light_red(T t) { return R { S(t, "lr", "lr") }; } + template R light_red_on_light_purple(T t) { return R { S(t, "lr", "lp") }; } + template R light_red_on_light_yellow(T t) { return R { S(t, "lr", "ly") }; } + template R light_red_on_bright_white(T t) { return R { S(t, "lr", "bw") }; } + template R light_purple_on_black(T t) { return R { S(t, "lp", "k") }; } + template R light_purple_on_blue(T t) { return R { S(t, "lp", "b") }; } + template R light_purple_on_green(T t) { return R { S(t, "lp", "g") }; } + template R light_purple_on_aqua(T t) { return R { S(t, "lp", "a") }; } + template R light_purple_on_red(T t) { return R { S(t, "lp", "r") }; } + template R light_purple_on_purple(T t) { return R { S(t, "lp", "p") }; } + template R light_purple_on_yellow(T t) { return R { S(t, "lp", "y") }; } + template R light_purple_on_white(T t) { return R { S(t, "lp", "w") }; } + template R light_purple_on_grey(T t) { return R { S(t, "lp", "e") }; } + template R light_purple_on_light_blue(T t) { return R { S(t, "lp", "lb") }; } + template R light_purple_on_light_green(T t) { return R { S(t, "lp", "lg") }; } + template R light_purple_on_light_aqua(T t) { return R { S(t, "lp", "la") }; } + template R light_purple_on_light_red(T t) { return R { S(t, "lp", "lr") }; } + template R light_purple_on_light_purple(T t) { return R { S(t, "lp", "lp") }; } + template R light_purple_on_light_yellow(T t) { return R { S(t, "lp", "ly") }; } + template R light_purple_on_bright_white(T t) { return R { S(t, "lp", "bw") }; } + template R light_yellow_on_black(T t) { return R { S(t, "ly", "k") }; } + template R light_yellow_on_blue(T t) { return R { S(t, "ly", "b") }; } + template R light_yellow_on_green(T t) { return R { S(t, "ly", "g") }; } + template R light_yellow_on_aqua(T t) { return R { S(t, "ly", "a") }; } + template R light_yellow_on_red(T t) { return R { S(t, "ly", "r") }; } + template R light_yellow_on_purple(T t) { return R { S(t, "ly", "p") }; } + template R light_yellow_on_yellow(T t) { return R { S(t, "ly", "y") }; } + template R light_yellow_on_white(T t) { return R { S(t, "ly", "w") }; } + template R light_yellow_on_grey(T t) { return R { S(t, "ly", "e") }; } + template R light_yellow_on_light_blue(T t) { return R { S(t, "ly", "lb") }; } + template R light_yellow_on_light_green(T t) { return R { S(t, "ly", "lg") }; } + template R light_yellow_on_light_aqua(T t) { return R { S(t, "ly", "la") }; } + template R light_yellow_on_light_red(T t) { return R { S(t, "ly", "lr") }; } + template R light_yellow_on_light_purple(T t) { return R { S(t, "ly", "lp") }; } + template R light_yellow_on_light_yellow(T t) { return R { S(t, "ly", "ly") }; } + template R light_yellow_on_bright_white(T t) { return R { S(t, "ly", "bw") }; } + template R bright_white_on_black(T t) { return R { S(t, "bw", "k") }; } + template R bright_white_on_blue(T t) { return R { S(t, "bw", "b") }; } + template R bright_white_on_green(T t) { return R { S(t, "bw", "g") }; } + template R bright_white_on_aqua(T t) { return R { S(t, "bw", "a") }; } + template R bright_white_on_red(T t) { return R { S(t, "bw", "r") }; } + template R bright_white_on_purple(T t) { return R { S(t, "bw", "p") }; } + template R bright_white_on_yellow(T t) { return R { S(t, "bw", "y") }; } + template R bright_white_on_white(T t) { return R { S(t, "bw", "w") }; } + template R bright_white_on_grey(T t) { return R { S(t, "bw", "e") }; } + template R bright_white_on_light_blue(T t) { return R { S(t, "bw", "lb") }; } + template R bright_white_on_light_green(T t) { return R { S(t, "bw", "lg") }; } + template R bright_white_on_light_aqua(T t) { return R { S(t, "bw", "la") }; } + template R bright_white_on_light_red(T t) { return R { S(t, "bw", "lr") }; } + template R bright_white_on_light_purple(T t) { return R { S(t, "bw", "lp") }; } + template R bright_white_on_light_yellow(T t) { return R { S(t, "bw", "ly") }; } + template R bright_white_on_bright_white(T t) { return R { S(t, "bw", "bw") }; } +} + +#endif \ No newline at end of file diff --git a/src/app-sdk/midiupdatedriver/main.cpp b/src/app-sdk/midiupdatedriver/main.cpp new file mode 100644 index 00000000..3286d083 --- /dev/null +++ b/src/app-sdk/midiupdatedriver/main.cpp @@ -0,0 +1,343 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +#pragma once + +#include "pch.h" + +#include "color.hpp" + +#define LINE_LENGTH 79 + +#define CMD_RETURN_SUCCESS 0 +#define CMD_RETURN_SUCCESS_NEEDS_REBOOT 1 + +#define CMD_RETURN_INSUFFICIENT_PERMISSIONS 2 +#define CMD_RETURN_INVALID_OR_MISSING_ARGS 3 +#define CMD_RETURN_INVALID_DEVICE 4 +#define CMD_RETURN_DRIVER_ALREADY_ASSIGNED 5 + +#define CMD_RETURN_ERROR_OTHER_FAILURE 9 + + +void WriteInfo(_In_ std::string info) +{ + std::cout << dye::aqua(info) << std::endl; +} + +void WriteSuccess(_In_ std::string info) +{ + std::cout << dye::green(info) << std::endl; +} + +void WriteError(_In_ std::string error) +{ + std::cout << dye::light_red(error) << std::endl; +} + +void WriteSystemError(_In_ DWORD errorNumber) +{ + WCHAR message[MAX_ERROR_MESSAGE_CHARS]{ 0 }; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorNumber, 0, message, MAX_ERROR_MESSAGE_CHARS, NULL); + std::wcout << errorNumber << " : " << message << std::endl; +} + + + +HDEVINFO m_deviceInfoSet; +SP_DEVINFO_DATA m_device{ }; + +HDEVINFO m_driverInfoSet; +SP_DRVINFO_DATA m_newDriverInfo{ }; + + +bool LoadDeviceInfo(_In_ std::wstring deviceInstanceId) +{ + auto handle = SetupDiGetClassDevsW(&GUID_CLASS_USB_DEVICE, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); + + if (handle == INVALID_HANDLE_VALUE) + { + WriteError("Unable to load device information."); + WriteSystemError(GetLastError()); + std::wcout << deviceInstanceId << std::endl; + + return false; + } + + //std::cout << "debug: got device info set" << std::endl; + + m_deviceInfoSet = handle; + m_device.cbSize = sizeof(SP_DEVINFO_DATA); + + BOOL enumResult{ TRUE }; + DWORD memberIndex{ 0 }; + while (enumResult) + { + enumResult = SetupDiEnumDeviceInfo(m_deviceInfoSet, memberIndex, &m_device); + + if (!enumResult) + { + WriteError("Unable to enum device information."); + WriteSystemError(GetLastError()); + std::wcout << deviceInstanceId << std::endl; + + return false; + } + else + { + wchar_t thisDeviceInstanceId[512]{ 0 }; + auto res = SetupDiGetDeviceInstanceIdW(m_deviceInfoSet, &m_device, thisDeviceInstanceId, 512, NULL); + + //std::wcout << thisDeviceInstanceId << std::endl; + + if (res) + { + if (internal::ToUpperTrimmedWStringCopy(thisDeviceInstanceId) == deviceInstanceId) + { + std::wcout << L"Found a match" << std::endl; + return true; + } + } + } + + memberIndex++; + } + +} + +bool LoadMidi2DriverInfo() +{ + //auto handle = SetupDiGetClassDevsW(&GUID_CLASS_USB_DEVICE, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); + + //GUID classList[1024]; + //DWORD requiredSize{ 0 }; + + //auto result = SetupDiBuildClassInfoList( + // DIBCI_NOINSTALLCLASS, + // classList, + // 1024, + // &requiredSize + //); + + auto result = SetupDiBuildDriverInfoList( + m_deviceInfoSet, + NULL, + SPDIT_CLASSDRIVER + ); + + + if (!result) + { + WriteError("Unable to build class driver list."); + WriteSystemError(GetLastError()); + + return false; + } + + BOOL enumResult{ TRUE }; + DWORD memberIndex{ 0 }; + + SP_DRVINFO_DATA driverData{ }; + + + SP_DEVINSTALL_PARAMS_W installParams{}; + installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W); + installParams.Flags = DI_COMPAT_FROM_CLASS; + + SetupDiSetDeviceInstallParamsW(m_deviceInfoSet, &m_device, &installParams); + + while (enumResult) + { + driverData.cbSize = sizeof(SP_DRVINFO_DATA); + enumResult = SetupDiEnumDriverInfoW(m_deviceInfoSet, &m_device, SPDIT_CLASSDRIVER, memberIndex, &driverData); + + + if (!enumResult) + { + WriteError("Unable to enum driver information."); + WriteSystemError(GetLastError()); + + return false; + } + else + { + //if (driverData.MfgName == L"Microsoft") + { + std::wcout << L"---" << std::endl; + std::wcout << driverData.MfgName << std::endl; + std::wcout << driverData.ProviderName << std::endl; + std::wcout << driverData.Description << std::endl; + } + } + + memberIndex++; + } + + + // media class: {4d36e96c-e325-11ce-bfc1-08002be10318} + + return true; +} + +int ChangeDeviceFromMidi1ToMidi2(_In_ std::wstring deviceInstanceId) +{ + BOOL needsReboot{ false }; + + if (!LoadDeviceInfo(deviceInstanceId)) + { + return CMD_RETURN_INVALID_DEVICE; + } + + + if (!LoadMidi2DriverInfo()) + { + return CMD_RETURN_ERROR_OTHER_FAILURE; + } + + + + + + auto ret = TRUE; + //auto ret = DiInstallDevice( + // NULL, + // m_deviceInfoSet, + // &m_device, + // &m_newDriverInfo, + // 0, + // &needsReboot + //); + + + //auto ret = UpdateDriverForPlugAndPlayDevicesW( + // NULL, + // deviceInstanceId.c_str(), + // L"C:\\Windows\\System32\\DriverStore\\FileRepository\\usbmidi2.inf_amd64_5518a95d6f5d2db5\\usbmidi2.inf", + // INSTALLFLAG_FORCE | INSTALLFLAG_READONLY, + // &needsReboot + //); + + + if (ret == TRUE) + { + if (needsReboot) + { + WriteSuccess("Driver assignment succeeded. Please reboot to finalize."); + return CMD_RETURN_SUCCESS_NEEDS_REBOOT; + } + else + { + WriteSuccess("Driver assignment succeeded."); + return CMD_RETURN_SUCCESS; + } + + } + else if (ret == ERROR_ACCESS_DENIED) + { + WriteError("Insufficient permissions. This must be run from an elevated Administrator process."); + return CMD_RETURN_INSUFFICIENT_PERMISSIONS; + } + else + { + // some other error + WriteSystemError(GetLastError()); + WriteError("Unknown error. Unable to assign driver."); + return CMD_RETURN_ERROR_OTHER_FAILURE; + } + + return CMD_RETURN_SUCCESS; +} + +int ChangeDeviceFromMidi2ToMidi1(_In_ std::wstring deviceInstanceId) +{ + + return CMD_RETURN_SUCCESS; +} + +int ChangeDeviceToDefault(_In_ std::wstring deviceInstanceId) +{ + + return CMD_RETURN_SUCCESS; +} + + +int __cdecl wmain(_In_ int argc, _In_ wchar_t* argv[]) +{ + std::cout << dye::grey(std::string(LINE_LENGTH, '=')) << std::endl; + std::cout << dye::aqua(" Switch a class-compliant USB MIDI device to a new class driver") << std::endl; + std::cout << dye::aqua(" This must be run in an elevated (Administrator) command prompt") << std::endl; + std::cout << dye::grey(std::string(LINE_LENGTH, '=')) << std::endl; + + // enter number to monitor + + uint16_t portNumber{ 0 }; + bool portNumberProvided{ false }; + + if (argc == 3) + { + std::wstring targetVersion = internal::ToLowerTrimmedWStringCopy(argv[1]); + std::wstring deviceInstanceId = internal::ToUpperTrimmedWStringCopy(argv[2]); + + if (targetVersion != L"1" && targetVersion != L"2" && targetVersion != L"default") + { + WriteError("Invalid driver version specified."); + + return CMD_RETURN_INVALID_OR_MISSING_ARGS; + } + + //if (!IsValidDevice(deviceInstanceId)) + //{ + // WriteError("Invalid device instance id specified."); + + // return CMD_RETURN_INVALID_DEVICE; + //} + + // data checks out. proceed. + + if (targetVersion == L"1") + { + return ChangeDeviceFromMidi2ToMidi1(deviceInstanceId); + } + else if(targetVersion == L"2") + { + return ChangeDeviceFromMidi1ToMidi2(deviceInstanceId); + } + else // default + { + return ChangeDeviceToDefault(deviceInstanceId); + } + + } + else + { + std::string tab{ " " }; + + std::cout << std::endl; + std::cout << dye::light_yellow("USAGE:") << std::endl; + std::cout << tab << "midiupdatedriver" << dye::grey(" ") << std::endl; + std::cout << std::endl; + std::cout << dye::light_yellow("EXAMPLES:") << std::endl; + std::cout << tab << "midiupdatedriver " << dye::grey("1 \"USB\\VID_0944&PID_0133\\7&2eb6a416&0&4\"") << std::endl; + std::cout << tab << "midiupdatedriver " << dye::grey("2 \"USB\\VID_2E14&PID_0006&MI_02\\8&28675245&0&0002\"") << std::endl; + std::cout << tab << "midiupdatedriver " << dye::grey("default \"USB\\VID_2E14&PID_0006&MI_02\\8&28675245&0&0002\"") << std::endl; + std::cout << std::endl; + std::cout << dye::light_yellow("ARGUMENTS:") << std::endl; + std::cout << tab << " " << dye::grey("1 for usbaudio.sys (MIDI 1 class driver)") << std::endl; + std::cout << tab << " " << dye::grey("2 for USBMidi2.sys (MIDI 1 / 2 class driver)") << std::endl; + std::cout << tab << " " << dye::grey("default to let Windows pick the best driver for the device") << std::endl; + std::cout << tab << " " << dye::grey("The unique Instance Id found using pnputil or the device properties") << std::endl; + std::cout << std::endl; + + return CMD_RETURN_INVALID_OR_MISSING_ARGS; + } + + + return CMD_RETURN_SUCCESS; +} + diff --git a/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj b/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj new file mode 100644 index 00000000..e9e32f46 --- /dev/null +++ b/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj @@ -0,0 +1,199 @@ + + + + + true + true + true + true + 15.0 + {631E4512-699C-4BC8-AE31-942498CB55FA} + Win32Proj + midiupdatedriver + 10.0 + 10.0.20348.0 + midiupdatedriver + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Release + ARM64 + + + Debug + x64 + + + Release + ARM64EC + + + Release + x64 + + + + Application + v143 + v142 + v141 + v140 + Unicode + + + true + true + + + false + true + false + + + + + + + + + + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + $(SolutionDir)vsfiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + $(SolutionDir)vsfiles\out\$(ProjectName)\$(Platform)\$(Configuration)\ + $(IncludePath) + ..\..\api\VSFiles\intermediate\midiks\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midiksenum\$(Platform)\$(Configuration);..\..\api\VSFiles\intermediate\midikscommon\$(Platform)\$(Configuration);$(LibraryPath) + $(ExternalIncludePath);$(SolutionDir)..\api\inc;$(SolutionDir)..\api\vsfiles\intermediate\IDL\$(Platform)\$(Configuration) + + + + Use + pch.h + $(IntDir)pch.pch + _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + Level4 + %(AdditionalOptions) /permissive- /bigobj + + + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + stdcpp20 + stdcpp20 + stdcpp20 + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + + + Console + false + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib;midiks.lib;midikscommon.lib;midiksenum.lib + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib;midiks.lib;midikscommon.lib;midiksenum.lib + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib; + + + + + WIN32;%(PreprocessorDefinitions) + stdcpp20 + + + ntdll.lib;%(AdditionalDependencies) + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions) + stdcpp20 + stdcpp20 + stdcpp20 + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + %(AdditionalIncludeDirectories);..\..\api\VSFiles\intermediate\idl\$(Platform)\$(Configuration);..\..\api\inc;$(SolutionDir)..\..\build\staging\version\;$(GeneratedFilesDir) + + + Console + true + true + false + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib;midiks.lib;midikscommon.lib;midiksenum.lib + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib;midiks.lib;midikscommon.lib;midiksenum.lib + %(AdditionalDependencies);onecoreuap.lib;ksuser.lib;avrt.lib;newdev.lib; + + + + + + + + + + Create + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj.filters b/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj.filters new file mode 100644 index 00000000..d58691ae --- /dev/null +++ b/src/app-sdk/midiupdatedriver/midiupdatedriver.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + + + + + \ No newline at end of file diff --git a/src/app-sdk/midiupdatedriver/packages.config b/src/app-sdk/midiupdatedriver/packages.config new file mode 100644 index 00000000..2ddc908f --- /dev/null +++ b/src/app-sdk/midiupdatedriver/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/app-sdk/midiupdatedriver/pch.cpp b/src/app-sdk/midiupdatedriver/pch.cpp new file mode 100644 index 00000000..b437ca7e --- /dev/null +++ b/src/app-sdk/midiupdatedriver/pch.cpp @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +#include "pch.h" diff --git a/src/app-sdk/midiupdatedriver/pch.h b/src/app-sdk/midiupdatedriver/pch.h new file mode 100644 index 00000000..3e70d018 --- /dev/null +++ b/src/app-sdk/midiupdatedriver/pch.h @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License +// ============================================================================ +// This is part of the Windows MIDI Services App SDK and should be used +// in your Windows application via an official binary distribution. +// Further information: https://aka.ms/midi +// ============================================================================ + + +#pragma once + +#include +//#include + +//#pragma warning (disable: 4005) +//#include +//#pragma warning (pop) + + +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +//#include "SWDevice.h" +#include +//#include "Devpkey.h" +#include + +#include "wstring_util.h" +//#include "swd_helpers.h" + + +namespace internal = ::WindowsMidiServicesInternal; + +#include "initguid.h" +#include "usbiodef.h" + +#include "ks.h" +#include "ksmedia.h" + +// for device installation routines +#include "SetupAPI.h" +#include "newdev.h" \ No newline at end of file diff --git a/src/app-sdk/midiusbinfo/midiusbinfo.vcxproj b/src/app-sdk/midiusbinfo/midiusbinfo.vcxproj index 95e31f4c..b4ae7e37 100644 --- a/src/app-sdk/midiusbinfo/midiusbinfo.vcxproj +++ b/src/app-sdk/midiusbinfo/midiusbinfo.vcxproj @@ -2,7 +2,7 @@ - Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250209-429 + Microsoft.Windows.Devices.Midi2.1.0.3-preview-11.250211-2313 true true true diff --git a/src/app-sdk/midiusbinfo/packages.config b/src/app-sdk/midiusbinfo/packages.config index 9596ff16..b98787f6 100644 --- a/src/app-sdk/midiusbinfo/packages.config +++ b/src/app-sdk/midiusbinfo/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/app-sdk/tests/Offline.unittests/MidiGroupTests.cpp b/src/app-sdk/tests/Offline.unittests/MidiGroupTests.cpp index 0a9b5e14..73ada01b 100644 --- a/src/app-sdk/tests/Offline.unittests/MidiGroupTests.cpp +++ b/src/app-sdk/tests/Offline.unittests/MidiGroupTests.cpp @@ -34,4 +34,18 @@ void MidiGroupTests::TestInvalidData() MidiGroup g(0xAC); VERIFY_ARE_EQUAL(g.Index(), 0x0C); -} \ No newline at end of file +} + +void MidiGroupTests::TestConstructor() +{ + // The class is designed to ignore the most significant nibble because + // that allows for passing in a full status + channel byte without pre-cleaning + + MidiGroup g0(static_cast(0)); + MidiGroup g1(static_cast(1)); + MidiGroup g15(static_cast(15)); + + VERIFY_ARE_EQUAL(g0.Index(), 0x0); + VERIFY_ARE_EQUAL(g1.Index(), 0x1); + VERIFY_ARE_EQUAL(g15.Index(), 0x15); +} diff --git a/src/app-sdk/tests/Offline.unittests/MidiGroupTests.h b/src/app-sdk/tests/Offline.unittests/MidiGroupTests.h index 7c110e35..5c31bd9e 100644 --- a/src/app-sdk/tests/Offline.unittests/MidiGroupTests.h +++ b/src/app-sdk/tests/Offline.unittests/MidiGroupTests.h @@ -28,6 +28,7 @@ class MidiGroupTests TEST_METHOD(TestBasics); TEST_METHOD(TestInvalidData); TEST_METHOD(TestLabels); + TEST_METHOD(TestConstructor); private: diff --git a/src/app-sdk/winrt/MidiEndpointDevicePropertyHelper.cpp b/src/app-sdk/winrt/MidiEndpointDevicePropertyHelper.cpp index 581a18e4..e8743961 100644 --- a/src/app-sdk/winrt/MidiEndpointDevicePropertyHelper.cpp +++ b/src/app-sdk/winrt/MidiEndpointDevicePropertyHelper.cpp @@ -223,6 +223,8 @@ namespace winrt::Microsoft::Windows::Devices::Midi2::implementation AddSingleMapEntry(PROPERTY_PAIR(STRING_PKEY_MIDI_VirtualMidiEndpointAssociator)); + AddSingleMapEntry(PROPERTY_PAIR(STRING_PKEY_MIDI_UseOldMidi1PortNamingScheme)); + m_initialized = true; } } diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/App.xaml.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/App.xaml.cs index a161d543..5abdbc99 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/App.xaml.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/App.xaml.cs @@ -109,6 +109,9 @@ public App() services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Controls/MidiEndpointDeviceListItemControl.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Controls/MidiEndpointDeviceListItemControl.xaml index 32f576f9..86418471 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Controls/MidiEndpointDeviceListItemControl.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Controls/MidiEndpointDeviceListItemControl.xaml @@ -18,7 +18,7 @@ - + @@ -69,31 +69,36 @@ diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToEmojiCheckConverter.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToEmojiCheckConverter.cs index 5a103d2a..d7c2aab9 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToEmojiCheckConverter.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToEmojiCheckConverter.cs @@ -21,7 +21,7 @@ public object Convert(object value, Type targetType, object parameter, string la return "❌"; } - throw new ArgumentException("BooleanToVisibilityConverter object must be a bool"); + throw new ArgumentException("BooleanToEmojiCheckConverter object must be a bool"); } public object? ConvertBack(object value, Type targetType, object parameter, string language) diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToFluentCheckConverter.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToFluentCheckConverter.cs new file mode 100644 index 00000000..9d71e9fa --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Helpers/BooleanToFluentCheckConverter.cs @@ -0,0 +1,31 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Data; + +namespace Microsoft.Midi.Settings.Helpers; + +public partial class BooleanToFluentCheckConverter : IValueConverter +{ + public BooleanToFluentCheckConverter() + { + } + + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is bool val) + { + if (val) + { + return "\uf16c"; + } + + return "\uf16b"; + } + + throw new ArgumentException("BooleanToFluentCheckConverter object must be a bool"); + } + + public object? ConvertBack(object value, Type targetType, object parameter, string language) + { + return null; + } +} \ No newline at end of file diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml new file mode 100644 index 00000000..78e9ffa6 --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml.cs new file mode 100644 index 00000000..d7b4e101 --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagPage.xaml.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using Microsoft.Midi.Settings.Contracts.Services; +using Microsoft.Midi.Settings.Controls; +using Microsoft.Midi.Settings.ViewModels; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Microsoft.Midi.Settings.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class EndpointsDiagPage : Page + { + private ILoggingService _loggingService; + + + public EndpointsDiagViewModel ViewModel + { + get; + } + + + public EndpointsDiagPage() + { + ViewModel = App.GetService(); + _loggingService = App.GetService(); + + Loaded += DevicesPage_Loaded; + + InitializeComponent(); + } + + private void DevicesPage_Loaded(object sender, RoutedEventArgs e) + { + ViewModel.DispatcherQueue = this.DispatcherQueue; + + ViewModel.RefreshDeviceCollection(); + } + + + // work around WinUI binding bug + private void MidiEndpointDeviceListItemControl_Loaded(object sender, RoutedEventArgs e) + { + ((MidiEndpointDeviceListItemControl)sender).ViewDeviceDetailsCommand = ViewModel.ViewDeviceDetailsCommand; + } + } +} + diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagViewModel.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagViewModel.cs new file mode 100644 index 00000000..8133561e --- /dev/null +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Sections/Endpoints/DIAG/EndpointsDiagViewModel.cs @@ -0,0 +1,25 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Microsoft.Midi.Settings.Contracts.Services; +using Microsoft.Midi.Settings.Contracts.ViewModels; +using Microsoft.Midi.Settings.Models; +using Microsoft.Midi.Settings.Services; +using Microsoft.UI.Dispatching; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Microsoft.Midi.Settings.ViewModels +{ + public partial class EndpointsDiagViewModel : SingleTransportEndpointViewModelBase, INavigationAware + { + public EndpointsDiagViewModel(INavigationService navigationService) : base("DIAG", navigationService) + { + } + + } +} diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs index 6b151a62..f86c08fe 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Services/PageService.cs @@ -21,6 +21,8 @@ public PageService() Configure(); Configure(); + Configure(); + Configure(); Configure(); diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw index af5ece9e..45ef20e6 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Strings/en-us/Resources.resw @@ -378,4 +378,37 @@ Devices may have more than one MIDI Endpoint. This is the parent device for this endpoint. + + Diagnostic + + + Set MIDI Service to auto-start at boot (requires Administrator account) + + + Set a USB MIDI 1.0 device to use the new fast UMP MIDI 2.0 driver (requires Administrator account) + + + Create a loopback endpoint so two or more applications can communicate using MIDI messages + + + Send a file of System Exclusive data (patches, firmware, etc.) to an endpoint + + + Capture MIDI Diagnostics information to a text file for use with technical support + + + Open Windows MIDI Services Console + + + Set up Network MIDI 2.0 to enable MIDI messages to be sent to other devices on your local network. + + + Endpoints + + + Service and Drivers + + + Other + \ No newline at end of file diff --git a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Styles/TextBlock.xaml b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Styles/TextBlock.xaml index b04af77a..ab881196 100644 --- a/src/user-tools/midi-settings/Microsoft.Midi.Settings/Styles/TextBlock.xaml +++ b/src/user-tools/midi-settings/Microsoft.Midi.Settings/Styles/TextBlock.xaml @@ -52,6 +52,15 @@ +