diff --git a/ToothTray/BluetoothAudioDevices.cpp b/ToothTray/BluetoothAudioDevices.cpp index 80bada3..48ecee2 100644 --- a/ToothTray/BluetoothAudioDevices.cpp +++ b/ToothTray/BluetoothAudioDevices.cpp @@ -114,7 +114,7 @@ std::vector BluetoothAudioDeviceEnumerator::EnumerateAudioDe std::unordered_map::const_iterator containerIte = containers.find(containerId); if (containerIte != containers.cend()) { const std::wstring& containerName = containerIte->second; - ite = bluetoothConnectors.emplace(std::piecewise_construct, std::forward_as_tuple(containerId), std::forward_as_tuple(containerName)).first; + ite = bluetoothConnectors.emplace(std::piecewise_construct, std::forward_as_tuple(containerId), std::forward_as_tuple(containerName, containerId)).first; } } diff --git a/ToothTray/BluetoothAudioDevices.h b/ToothTray/BluetoothAudioDevices.h index 3f1ecc0..5bb6127 100644 --- a/ToothTray/BluetoothAudioDevices.h +++ b/ToothTray/BluetoothAudioDevices.h @@ -15,13 +15,19 @@ class BluetoothConnector { BluetoothConnector(BluetoothConnector&& other) = default; BluetoothConnector& operator=(BluetoothConnector&&) = default; - BluetoothConnector(const std::wstring& containerName) - : m_deviceName(containerName), m_isConnected(false) {} + BluetoothConnector(const std::wstring& containerName, const GUID& containerId) + : m_deviceName(containerName), m_containerId(containerId), m_isConnected(false) {} std::wstring_view DeviceName() const { return std::wstring_view(m_deviceName); } + std::wstring_view ContainerId() const { + wchar_t* containerIdBuffer = new wchar_t[200]; + StringFromGUID2(m_containerId, containerIdBuffer, 200); + return std::wstring_view(containerIdBuffer); + } + void addConnectorControl(const wil::com_ptr& connectorControl, DWORD state); bool IsConnected() { @@ -37,6 +43,7 @@ class BluetoothConnector { } private: std::wstring m_deviceName; + GUID m_containerId; bool m_isConnected; std::vector> m_ksControls; diff --git a/ToothTray/BluetoothDeviceWatcher.cpp b/ToothTray/BluetoothDeviceWatcher.cpp index 0ede257..2bda423 100644 --- a/ToothTray/BluetoothDeviceWatcher.cpp +++ b/ToothTray/BluetoothDeviceWatcher.cpp @@ -14,7 +14,7 @@ void OutputDeviceProperties(std::wostringstream& sout, const winrt::Windows::Fou for (const auto& kvp : properties) { const winrt::hstring&& propName = kvp.Key(); if (propName == L"System.Devices.Aep.ContainerId") { - winrt::guid containerId = kvp.Value().as(); + winrt::guid containerId = winrt::unbox_value(kvp.Value()); sout << propName.c_str(); } else { diff --git a/ToothTray/BluetoothRadio.h b/ToothTray/BluetoothRadio.h index 5976e80..5f565da 100644 --- a/ToothTray/BluetoothRadio.h +++ b/ToothTray/BluetoothRadio.h @@ -5,7 +5,7 @@ class BluetoothDevice { public: - constexpr BluetoothDevice() : m_hRadio(NULL), m_info({ 0 }) {} + BluetoothDevice() : m_hRadio(NULL), m_info({ 0 }) {} BluetoothDevice(HANDLE hRadio, const BLUETOOTH_DEVICE_INFO& info); void Enable(); @@ -21,15 +21,15 @@ class BluetoothDevice { class BluetoothRadio { public: static BluetoothRadio FindFirst(); - constexpr BluetoothRadio(std::nullptr_t) : m_hRadio(NULL), m_hNotify(NULL) {} + BluetoothRadio(std::nullptr_t) : m_hRadio(NULL), m_hNotify(NULL) {} ~BluetoothRadio() noexcept; - constexpr BluetoothRadio(BluetoothRadio&& other) noexcept : m_hRadio(other.m_hRadio), m_hNotify(other.m_hNotify) + BluetoothRadio(BluetoothRadio&& other) noexcept : m_hRadio(other.m_hRadio), m_hNotify(other.m_hNotify) { other.m_hRadio = other.m_hNotify = NULL; } - constexpr BluetoothRadio& operator=(BluetoothRadio&& other) noexcept + BluetoothRadio& operator=(BluetoothRadio&& other) noexcept { std::swap(m_hRadio, other.m_hRadio); std::swap(m_hNotify, other.m_hNotify); @@ -44,7 +44,7 @@ class BluetoothRadio { void EnableAudioSink(); void DisableAudioSink(); private: - constexpr BluetoothRadio(HANDLE hRadio) : m_hRadio(hRadio), m_hNotify(NULL) {} + BluetoothRadio(HANDLE hRadio) : m_hRadio(hRadio), m_hNotify(NULL) {} HANDLE m_hRadio; HDEVNOTIFY m_hNotify; diff --git a/ToothTray/ToothTray.cpp b/ToothTray/ToothTray.cpp index 53dfd60..9ba4691 100644 --- a/ToothTray/ToothTray.cpp +++ b/ToothTray/ToothTray.cpp @@ -4,6 +4,8 @@ #include "framework.h" #include "ToothTray.h" #include +#include +#include #include #include "debuglog.h" @@ -29,6 +31,205 @@ BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); +int wmain(int argc, wchar_t* argv[]) { + winrt::init_apartment(); + std::vector connectors = bluetoothAudioDeviceEmumerator.EnumerateAudioDevices(); + + std::setlocale(LC_ALL, ""); + + const wchar_t* command = L"list"; + if (argc >= 2) { + command = argv[1]; + } + + if (lstrcmpW(command, L"list") == 0) { + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + std::wstring deviceName = std::wstring(ite->DeviceName()); + bool checked = ite->IsConnected(); + + wprintf(L"%ls %ls %ls\n", checked ? L"1" : L"0", std::wstring(ite->ContainerId()).c_str(), deviceName.c_str()); + } + return 0; + } else if(lstrcmpW(command, L"is-connected") == 0 && argc >= 3) { + const wchar_t* isConnectedArg = argv[2]; + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + std::wstring deviceName = std::wstring(ite->DeviceName()); + bool checked = ite->IsConnected(); + + if (lstrcmpW(isConnectedArg, deviceName.c_str()) == 0) { + wprintf(checked ? L"1\n" : L"0\n"); + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"is-connected-by-container-id") == 0 && argc >= 3) { + const wchar_t* isConnectedArg = argv[2]; + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + bool checked = ite->IsConnected(); + + if (lstrcmpW(isConnectedArg, std::wstring(ite->ContainerId()).c_str()) == 0) { + wprintf(checked ? L"1\n" : L"0\n"); + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"connect") == 0 && argc >= 3) { + const wchar_t* connectArg = argv[2]; + + bool force = false; + if (argc >= 4 && lstrcmpW(argv[2], L"-f") == 0) { + connectArg = argv[3]; + force = true; + } + + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + if (lstrcmpW(connectArg, std::wstring(ite->DeviceName()).c_str()) == 0) { + ite->Connect(); + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"connect-by-container-id") == 0 && argc >= 3) { + const wchar_t* connectArg = argv[2]; + + bool force = false; + if (argc >= 4 && lstrcmpW(argv[2], L"-f") == 0) { + connectArg = argv[3]; + force = true; + } + + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + if (lstrcmpW(connectArg, std::wstring(ite->ContainerId()).c_str()) == 0) { + if (force || !ite->IsConnected()) { + ite->Connect(); + } + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"connect-by-container-id") == 0 && argc >= 3) { + const wchar_t* connectArg = argv[2]; + + bool force = false; + if (argc >= 4 && lstrcmpW(argv[2], L"-f") == 0) { + connectArg = argv[3]; + force = true; + } + + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + if (lstrcmpW(connectArg, std::wstring(ite->ContainerId()).c_str()) == 0) { + if (force || !ite->IsConnected()) { + ite->Connect(); + } + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"disconnect") == 0 && argc >= 3) { + const wchar_t* connectArg = argv[2]; + + bool force = false; + if (argc >= 4 && lstrcmpW(argv[2], L"-f") == 0) { + connectArg = argv[3]; + force = true; + } + + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + if (lstrcmpW(connectArg, std::wstring(ite->DeviceName()).c_str()) == 0) { + if (force || ite->IsConnected()) { + ite->Disconnect(); + } + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + else if (lstrcmpW(command, L"disconnect-by-container-id") == 0 && argc >= 3) { + const wchar_t* connectArg = argv[2]; + + bool force = false; + if (argc >= 4 && lstrcmpW(argv[2], L"-f") == 0) { + connectArg = argv[3]; + force = true; + } + + bool found = false; + + for (std::vector::iterator ite = connectors.begin(); ite != connectors.end(); ++ite) { + if (lstrcmpW(connectArg, std::wstring(ite->ContainerId()).c_str()) == 0) { + if (force || ite->IsConnected()) { + ite->Disconnect(); + } + found = true; + break; + } + } + if (!found) { + fwprintf(stderr, L"device not found (2)\n"); + return 2; + } + return 0; + } + + const wchar_t* helpText = L"toothtray-cli list\ntoothtray-cli is-connected \"My Device\"\ntoothtray-cli is-connected-by-container-id {xxx}\ntoothtray-cli connect[-by-container-id] [-f] ...\ntoothtray-cli disconnect[-by-container-id] [-f] ...\n"; + + if (lstrcmpW(command, L"-h") == 0 || lstrcmpW(command, L"--help") == 0) { + fwprintf(stdout, helpText); + } + else { + fwprintf(stderr, helpText); + } + + return 0; +} + int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, diff --git a/ToothTray/ToothTray.vcxproj b/ToothTray/ToothTray.vcxproj index da0e98c..7fe1677 100644 --- a/ToothTray/ToothTray.vcxproj +++ b/ToothTray/ToothTray.vcxproj @@ -21,13 +21,13 @@ Application true - v143 + v142 Unicode Application false - v143 + v142 true Unicode @@ -56,11 +56,12 @@ _DEBUG;_WINDOWS;%(PreprocessorDefinitions) true stdcpplatest + /await %(AdditionalOptions) Windows true - Ws2_32.lib;Bthprops.lib;%(AdditionalDependencies) + Ws2_32.lib;Bthprops.lib;windowsapp.lib;%(AdditionalDependencies) @@ -71,13 +72,15 @@ true NDEBUG;_WINDOWS;%(PreprocessorDefinitions) true + /await %(AdditionalOptions) + stdcpplatest - Windows + Console true true true - Ws2_32.lib;Bthprops.lib;%(AdditionalDependencies) + Ws2_32.lib;Bthprops.lib;windowsapp.lib;%(AdditionalDependencies)