13 Commits

Author SHA1 Message Date
22f9a8a1a6 checklist stuff 2022-12-22 10:55:56 +01:00
7e76c4813d failed loudness eq experiment 2022-12-14 18:42:16 +01:00
8967846657 Separate windows shell interaction into it's own file 2022-08-10 14:17:50 +02:00
c58b6c5624 mute button 2022-07-26 20:34:40 +02:00
5f5e24fa9c 1.0.4 2022-07-26 18:08:13 +02:00
cdffa1b50b per channel peak meters 2022-07-26 18:07:57 +02:00
eec9e25e12 1.0.3 2022-07-26 15:22:51 +02:00
3b4853acda Fix device add/remove handlers 2022-07-26 15:22:23 +02:00
cea13986f0 1.0.2 2022-07-24 02:09:58 +02:00
3641ffdad9 Set working dir on startup 2022-07-24 02:07:35 +02:00
7fa68792fb Use exe path to search for fonts 2022-07-22 21:48:04 +02:00
ebdd35b1e1 1.1 2022-07-22 01:49:30 +02:00
b986bfde39 fix missing tray icon bug 2022-07-22 01:48:26 +02:00
23 changed files with 2887 additions and 215 deletions

View File

@@ -1,13 +1,44 @@
#include "ApplicationData.h" #include "ApplicationData.h"
#include "Util.h"
#include "AudioApi.h"
#include <functiondiscoverykeys.h>
AudioDevice::AudioDevice() AudioDevice::AudioDevice(IMMDevice* device, LPCWSTR deviceId) : device(device)
{ {
id = std::wstring(deviceId);
IPropertyStore* propertyStore;
HRESULT err = device->OpenPropertyStore(STGM_READ, &propertyStore);
isError(err, "Failed to open prop store: ");
PROPVARIANT deviceNameProp;
const wchar_t* deviceName;
err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
isError(err, "Failed to read name of device :");
name = utf8Encode(deviceName);
err = device->GetState(&state);
isError(err, "Failed to reat state of device: ");
err = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&volumeInterface);
isError(err, "Failed to get audio endpoint volume interface: ");
err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface);
isError(err, "Failed to get audio meter interface: ");
getVolumeLimit(volumeInterface, &minVolumeDb, &maxVolumeDb);
if (propertyStore)
{
propertyStore->Release();
}
} }
AudioDevice::AudioDevice(AudioDevice&& other) noexcept AudioDevice::AudioDevice(AudioDevice&& other) noexcept
: device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface), : device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface),
id(other.id), name(other.name), state(other.state), id(other.id), name(other.name), state(other.state),
isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication) isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication),
minVolumeDb(other.minVolumeDb), maxVolumeDb(other.maxVolumeDb)
{ {
other.device = nullptr; other.device = nullptr;
other.volumeInterface = nullptr; other.volumeInterface = nullptr;
@@ -25,6 +56,8 @@ AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept
this->isDefaultConsole = other.isDefaultConsole; this->isDefaultConsole = other.isDefaultConsole;
this->isDefaultMedia = other.isDefaultMedia; this->isDefaultMedia = other.isDefaultMedia;
this->isDefaultCommunication = other.isDefaultCommunication; this->isDefaultCommunication = other.isDefaultCommunication;
this->minVolumeDb = other.minVolumeDb;
this->maxVolumeDb = other.maxVolumeDb;
other.device = nullptr; other.device = nullptr;
other.volumeInterface = nullptr; other.volumeInterface = nullptr;

View File

@@ -1,10 +1,12 @@
#pragma once #pragma once
#include <mmdeviceapi.h> #include "AudioNotificationListener.h"
#include <endpointvolume.h> #include <endpointvolume.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "AudioNotificationListener.h" #include <unordered_map>
class AudioDevice { class AudioDevice {
public: public:
@@ -14,11 +16,13 @@ public:
std::wstring id = {}; std::wstring id = {};
std::string name = {}; std::string name = {};
unsigned long state = {}; unsigned long state = {};
bool isDefaultConsole = {}; bool isDefaultConsole = false;
bool isDefaultMedia = {}; bool isDefaultMedia = false;
bool isDefaultCommunication = {}; bool isDefaultCommunication = false;
float minVolumeDb = 0.f;
float maxVolumeDb = 0.f;
AudioDevice(); AudioDevice(IMMDevice* device, LPCWSTR deviceId);
AudioDevice(AudioDevice&& other) noexcept; AudioDevice(AudioDevice&& other) noexcept;
AudioDevice& operator=(AudioDevice&& other) noexcept; AudioDevice& operator=(AudioDevice&& other) noexcept;
~AudioDevice(); ~AudioDevice();
@@ -42,13 +46,16 @@ public:
bool autostart = false; bool autostart = false;
bool docked = false; bool docked = false;
bool showDisabledDevices = false; bool showDisabledDevices = false;
std::vector<std::string> taskNames = {};
std::unordered_map<std::string, std::vector<time_t>> tasks = {};
}; };
class ApplicationData { class ApplicationData {
public: public:
ApplicationSettings settings = {}; ApplicationSettings settings = {};
size_t checklistLength = 0;
std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>(); std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>();
ApplicationData(const ApplicationData&) = delete; //ApplicationData(const ApplicationData&) = delete;
ApplicationData& operator=(const ApplicationData&) = delete; //ApplicationData& operator=(const ApplicationData&) = delete;
}; };

View File

@@ -7,26 +7,22 @@
// see https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appshellintegration/NotificationIcon/NotificationIcon.cpp // see https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appshellintegration/NotificationIcon/NotificationIcon.cpp
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "comctl32.lib") #pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "rpcrt4.lib")
#include <windows.h>
#include <functional>
#include <iostream>
#include <sstream>
#include <shellapi.h>
#include <commctrl.h>
#include <strsafe.h>
#include "Util.h" #include "Util.h"
#include "AudioApi.h" #include "AudioApi.h"
#include "Settings.h" #include "Settings.h"
#include "resource.h"
#include "AsuroTool.h" #include "AsuroTool.h"
#include "WindowsShell.h"
class __declspec(uuid("3bc52579-15fd-43bb-9686-6273c238535e")) TrayGUID; #include <array>
#include <functional>
#include <iostream>
#include <sstream>
#include <format>
#include <ctime>
UINT const WMAPP_NOTIFYCALLBACK = WM_APP + 1; #define MAX_FONT_PATH_LENGTH 2048
UINT const WMAPP_HIDEFLYOUT = WM_APP + 2;
// Globals for use in callbacks // Globals for use in callbacks
DrawData* gDrawData; DrawData* gDrawData;
@@ -36,6 +32,13 @@ bool isHidden = false;
int main() int main()
{ {
std::wstring appDir;
getAppDir(appDir);
if (_wchdir(appDir.c_str()) != 0)
{
std::cout << "Failed to set working dir." << std::endl;
}
ApplicationData applicationData{}; ApplicationData applicationData{};
ImGuiCallbacks callbacks{}; ImGuiCallbacks callbacks{};
@@ -43,79 +46,40 @@ int main()
callbacks.drawFunc = std::bind(draw, std::placeholders::_1, std::ref(applicationData)); callbacks.drawFunc = std::bind(draw, std::placeholders::_1, std::ref(applicationData));
callbacks.cleanupFunc = std::bind(cleanup, std::placeholders::_1, std::ref(applicationData)); callbacks.cleanupFunc = std::bind(cleanup, std::placeholders::_1, std::ref(applicationData));
startImgui(callbacks, "Audio Thingy", 600, 400); startImgui(callbacks, "Audio Thingy", 700, 400);
} }
void init(DrawData& drawData, ApplicationData& appData) void init(DrawData& drawData, ApplicationData& appData)
{ {
std::wstring appPath;
getAppDir(appPath);
char appPathStr[MAX_FONT_PATH_LENGTH];
HRESULT convResult = WideCharToMultiByte(CP_UTF8, NULL, &appPath[0], -1, appPathStr, MAX_FONT_PATH_LENGTH, NULL, nullptr);
isError(convResult, "Failed to convert path: ");
// sad :( // sad :(
gDrawData = &drawData; gDrawData = &drawData;
gAppData = &appData; gAppData = &appData;
// Load text font // Load text font
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("Montserrat-Regular.ttf", 18.0f); std::string fontPath = std::string(appPathStr);
fontPath.append("\\Montserrat-Regular.ttf");
io.Fonts->AddFontFromFileTTF(fontPath.c_str(), 18.0f);
// Load icon font // Load icon font
static const ImWchar icons_ranges[] = { 0xEA01, 0xF2DF, 0 }; static const ImWchar icons_ranges[] = { 0xEA01, 0xF2DF, 0 };
ImFontConfig icons_config; ImFontConfig icons_config;
icons_config.MergeMode = true; icons_config.MergeMode = true;
icons_config.PixelSnapH = true; icons_config.PixelSnapH = true;
io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges); icons_config.GlyphOffset = { 0., 2. };
std::string iconFontPath = std::string(appPathStr);
iconFontPath.append("\\remixicon.ttf");
io.Fonts->AddFontFromFileTTF(iconFontPath.c_str(), 14.0f, &icons_config, icons_ranges);
// Set window icon
HINSTANCE instance = GetModuleHandle(NULL);
LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
HANDLE iconLarge = LoadImageW(instance, iconId, IMAGE_ICON, 64, 64, 0);
HANDLE iconSmall = LoadImageW(instance, iconId, IMAGE_ICON, 32, 32, 0);
SendMessage(drawData.window_handle, WM_SETICON, ICON_BIG, (LPARAM)iconLarge);
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL2, (LPARAM)iconSmall);
// Set tray icon initShell(drawData);
NOTIFYICONDATA nid = { sizeof(nid) };
nid.hWnd = drawData.window_handle;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP | NIF_GUID;
nid.guidItem = __uuidof(TrayGUID);
nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK;
HRESULT iconResult;
iconResult = LoadIconMetric(instance, iconId, LIM_SMALL, &nid.hIcon);
isError(iconResult, "Failed to load tray icon image: ");
iconResult = LoadString(instance, IDS_STRING_TOOLTIP, nid.szTip, ARRAYSIZE(nid.szTip));
isError(iconResult, "Failed to load tray icon text: ");
Shell_NotifyIcon(NIM_ADD, &nid);
nid.uVersion = NOTIFYICON_VERSION_4;
Shell_NotifyIcon(NIM_SETVERSION, &nid);
if (!SetWindowsHookEx(WH_CALLWNDPROC, trayIconEventHandler, instance, GetCurrentThreadId()))
{
std::cout << "Failed to hook tray icon events: " << std::hex << GetLastError() << std::endl;
}
// Set window minimize behavior
glfwSetWindowIconifyCallback(drawData.window, [](GLFWwindow* window, int isIconified) {
if (isIconified && gAppData->settings.docked)
{
glfwHideWindow(window);
}
isHidden = isIconified;
});
glfwSetWindowFocusCallback(drawData.window, [](GLFWwindow* window, int isFocused) {
if (!isFocused && gAppData->settings.docked && !justDocked)
{
glfwIconifyWindow(window);
}
});
// Load settings
initSettings(drawData, appData); initSettings(drawData, appData);
// Set up audio device api
initAudio(appData); initAudio(appData);
} }
@@ -123,11 +87,6 @@ void draw(DrawData& drawData, ApplicationData& appData)
{ {
justDocked = false; justDocked = false;
// sad :(
gDrawData = &drawData;
gAppData = &appData;
// Actual Drawing
if (isHidden) if (isHidden)
{ {
glfwWaitEvents(); glfwWaitEvents();
@@ -140,17 +99,24 @@ void draw(DrawData& drawData, ApplicationData& appData)
// Menu Bar // Menu Bar
customYCursor += menuBar(drawData, appData).y; customYCursor += menuBar(drawData, appData).y;
// Checklist
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += checklistWindow(appData, std::format(" {} Checklist", ICON_CHECK_FILL).c_str()).y;
customYCursor += 5.;
// Playback Devices // Playback Devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData.audioData->playbackDevices, " \xEE\xB8\x84 Playback").y; customYCursor += audioDeviceWindow(appData, appData.audioData->playbackDevices, std::format(" {} Playback", ICON_HEADPHONE_FILL).c_str()).y;
customYCursor += 5.; customYCursor += 5.;
// Recording devices // Recording devices
ImGui::SetNextWindowPos(ImVec2(0, customYCursor)); ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0)); ImGui::SetNextWindowSize(ImVec2(viewportSize.x, 0));
customYCursor += audioDeviceWindow(appData, appData.audioData->recordingDevices, " \xEE\xBD\x8F Recording").y; customYCursor += audioDeviceWindow(appData, appData.audioData->recordingDevices, std::format(" {} Recording", ICON_MIC_FILL).c_str()).y;
// Resize viewport // Resize viewport
drawData.window_size.y = customYCursor; drawData.window_size.y = customYCursor;
@@ -165,11 +131,7 @@ void draw(DrawData& drawData, ApplicationData& appData)
void cleanup(DrawData& drawData, ApplicationData& appData) void cleanup(DrawData& drawData, ApplicationData& appData)
{ {
// Remove tray icon cleanupShell(drawData);
NOTIFYICONDATA nid = { sizeof(nid) };
nid.uFlags = NIF_GUID;
nid.guidItem = __uuidof(TrayGUID);
bool test = Shell_NotifyIcon(NIM_DELETE, &nid);
} }
ImVec2 menuBar(DrawData& drawData, ApplicationData& appData) ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
@@ -181,9 +143,7 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
{ {
if (ImGui::BeginMenu("Settings")) if (ImGui::BeginMenu("Settings"))
{ {
bool prevDocked = appData.settings.docked; if (ImGui::Checkbox("Docked", &appData.settings.docked))
ImGui::Checkbox("Docked", &appData.settings.docked);
if (appData.settings.docked != prevDocked)
{ {
closeMenu = true; closeMenu = true;
updateDocked(drawData, appData); updateDocked(drawData, appData);
@@ -212,13 +172,13 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
{ {
ImVec2 availableSpace = ImGui::GetContentRegionAvail(); ImVec2 availableSpace = ImGui::GetContentRegionAvail();
ImVec2 cursorPos = ImGui::GetCursorPos(); ImVec2 cursorPos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(cursorPos.x + availableSpace.x - 33.); ImGui::SetCursorPosX(cursorPos.x + availableSpace.x - 47.);
if (ImGui::SmallButton("-")) if (ImGui::SmallButton(ICON_SUBTRACT_FILL))
{ {
glfwIconifyWindow(drawData.window); glfwIconifyWindow(drawData.window);
} }
if (ImGui::SmallButton("x")) if (ImGui::SmallButton(ICON_CLOSE_FILL))
{ {
glfwSetWindowShouldClose(drawData.window, GLFW_TRUE); glfwSetWindowShouldClose(drawData.window, GLFW_TRUE);
} }
@@ -256,6 +216,91 @@ bool customButton(const char* id_start, const char* id_end, const char* title, b
return result; return result;
} }
void drawCheclistDayLines(ApplicationData& appData, ImDrawList* drawList, float lineHeight, time_t day)
{
auto& tasks = appData.settings.tasks;
size_t totalTasks = appData.settings.taskNames.size();
size_t count = std::count_if(tasks.begin(), tasks.end(), [&](std::pair<std::string, std::vector<time_t>> t) { return std::any_of(t.second.begin(), t.second.end(), [&](time_t tt) { return tt == day; }); });
for (int i = 0; i < count; i++)
{
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
drawList->AddLine({ cursorPos.x, cursorPos.y }, { cursorPos.x, cursorPos.y + lineHeight }, ImColor(.4f, .9f, .3f), 3.f);
ImGui::SetCursorScreenPos({ cursorPos.x + 5.f, cursorPos.y });
}
for (int i = 0; i < max(0, totalTasks - count); i++)
{
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
drawList->AddLine({ cursorPos.x, cursorPos.y }, { cursorPos.x, cursorPos.y + lineHeight }, ImColor(.1f, .3f, .05f), 3.f);
ImGui::SetCursorScreenPos({ cursorPos.x + 5.f, cursorPos.y });
}
}
time_t getDayStartOf(time_t time)
{
tm localTime;
localtime_s(&localTime, &time);
localTime.tm_hour = 0;
localTime.tm_min = 0;
localTime.tm_sec = 0;
return mktime(&localTime);
}
ImVec2 checklistWindow(ApplicationData& appData, const char* title)
{
if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize))
{
time_t today = getDayStartOf(std::time(nullptr));
ImDrawList* drawList = ImGui::GetWindowDrawList();
float lineHeight = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2;
for (int pastDay = 3; pastDay >= 1; pastDay--)
{
time_t date = today - (60 * 60 * 24 * pastDay);
drawCheclistDayLines(appData, drawList, lineHeight, date);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5.f);
}
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
drawList->AddLine({ cursorPos.x, cursorPos.y - 2.f }, { cursorPos.x, cursorPos.y + lineHeight + 2.f }, IM_COL32_WHITE, 1.f);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.f);
drawCheclistDayLines(appData, drawList, lineHeight, today);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.f);
auto todayMatcher = [&](time_t t) { return getDayStartOf(t) == today; };
for (std::string& taskName : appData.settings.taskNames)
{
if (!appData.settings.tasks.contains(taskName))
{
appData.settings.tasks.insert({ taskName, std::vector<time_t>{} });
}
std::vector<time_t>& taskDates = appData.settings.tasks[taskName];
bool taskDoneToday = std::any_of(taskDates.begin(), taskDates.end(), todayMatcher);
if (ImGui::Checkbox(taskName.c_str(), &taskDoneToday))
{
if (taskDoneToday)
{
taskDates.push_back(today);
}
else
{
std::erase_if(taskDates, todayMatcher);
}
}
ImGui::SameLine();
}
}
ImVec2 size = ImGui::GetWindowSize();
ImGui::End();
return size;
}
ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& deviceList, const char* title) ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& deviceList, const char* title)
{ {
if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize)) if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize))
@@ -294,8 +339,23 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (dev.state == DEVICE_STATE_ACTIVE) if (dev.state == DEVICE_STATE_ACTIVE)
{ {
// Log scale because it looks better (no actual reason for these exact numbers) // Mute button
float meterValue = log10f(getMeterValue(dev.meterInterface) * 9. + 1.); ImGui::PushID(std::string("bn_mute_").append(deviceIdUtf8).c_str());
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
bool isDeviceMuted = isMuted(dev.volumeInterface);
if (ImGui::Button(isDeviceMuted ? ICON_VOLUME_MUTE_FILL : ICON_VOLUME_UP_FILL))
{
setMuted(dev.volumeInterface, !isDeviceMuted);
}
ImGui::PopStyleColor();
ImGui::PopID();
ImGui::SameLine(0, 2);
// Meter
static std::array<float, 2> meterValues{};
UINT channelCount = getMeterValues(dev.meterInterface, meterValues);
auto drawList = ImGui::GetWindowDrawList(); auto drawList = ImGui::GetWindowDrawList();
ImVec2 windowPos = ImGui::GetWindowPos(); ImVec2 windowPos = ImGui::GetWindowPos();
@@ -306,21 +366,34 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
const float linePaddingX = 3.; const float linePaddingX = 3.;
cursorPos.x += linePaddingX; cursorPos.x += linePaddingX;
// BG line
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX), lineY), IM_COL32(120, 120, 120, 255), 2.); drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX), lineY), IM_COL32(120, 120, 120, 255), 2.);
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValue, lineY), IM_COL32(200, 200, 255, 255), 3.);
// Channel lines
if (channelCount == 1)
{
drawList->AddLine(ImVec2(cursorPos.x, lineY), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[0], lineY), IM_COL32(200, 200, 255, 255), 3.);
}
if (channelCount == 2)
{
drawList->AddLine(ImVec2(cursorPos.x, lineY - 2), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[0], lineY - 2), IM_COL32(200, 200, 255, 255), 3.);
drawList->AddLine(ImVec2(cursorPos.x, lineY + 2), ImVec2(cursorPos.x + (space.x - 2. * linePaddingX) * meterValues[1], lineY + 2), IM_COL32(200, 200, 255, 255), 3.);
}
ImGui::SetNextItemWidth(space.x);
ImGui::PushID(&dev.id);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
if (isDeviceMuted) ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(.4, .4, .4, 1.));
float volume = getVolume(dev.volumeInterface); float volume = getVolume(dev.volumeInterface);
float prevVolume = volume; if (ImGui::SliderFloat("", &volume, 0., 1., "", ImGuiSliderFlags_NoRoundToFormat | ImGuiSliderFlags_AlwaysClamp))
ImGui::SetNextItemWidth(space.x);
ImGui::PushID(dev.device);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
ImGui::SliderFloat("", &volume, 0., 1., "", ImGuiSliderFlags_NoRoundToFormat | ImGuiSliderFlags_AlwaysClamp);
ImGui::PopStyleColor();
ImGui::PopID();
if (prevVolume != volume)
{ {
setVolume(dev.volumeInterface, volume); setVolume(dev.volumeInterface, volume);
} }
if (isDeviceMuted) ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopID();
} }
// Defaults // Defaults
@@ -331,7 +404,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
{ {
drawCircle(5, IM_COL32(50, 50, 222, 255)); drawCircle(5, IM_COL32(50, 50, 222, 255));
} }
if (customButton("bn_d_", deviceIdUtf8.c_str(), "\xEE\xBE\x82", !dev.isDefaultConsole)) if (customButton("bn_d_", deviceIdUtf8.c_str(), ICON_MUSIC_2_FILL, !dev.isDefaultConsole))
{ {
setDefaultAudioDevice(*appData.audioData, dev.id.c_str(), ERole::eConsole); setDefaultAudioDevice(*appData.audioData, dev.id.c_str(), ERole::eConsole);
} }
@@ -341,7 +414,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
{ {
drawCircle(5, IM_COL32(222, 50, 50, 255)); drawCircle(5, IM_COL32(222, 50, 50, 255));
} }
if (customButton("bn_c_", deviceIdUtf8.c_str(), "\xEE\xBF\xA9", !dev.isDefaultCommunication)) if (customButton("bn_c_", deviceIdUtf8.c_str(), ICON_PHONE_FILL, !dev.isDefaultCommunication))
{ {
setDefaultAudioDevice(*appData.audioData, dev.id.c_str(), ERole::eCommunications); setDefaultAudioDevice(*appData.audioData, dev.id.c_str(), ERole::eCommunications);
} }
@@ -369,24 +442,3 @@ void drawCircle(float radius, ImU32 color)
ImVec2 windowPos = ImGui::GetWindowPos(); ImVec2 windowPos = ImGui::GetWindowPos();
drawList->AddCircleFilled(ImVec2(cursorPos.x + windowPos.x, cursorPos.y + windowPos.y + ImGui::GetTextLineHeight() / 2.), radius, color); drawList->AddCircleFilled(ImVec2(cursorPos.x + windowPos.x, cursorPos.y + windowPos.y + ImGui::GetTextLineHeight() / 2.), radius, color);
} }
LRESULT CALLBACK trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0)
{
CWPSTRUCT* data = (CWPSTRUCT*)lParam;
if (data->message == WMAPP_NOTIFYCALLBACK)
{
switch (data->lParam)
{
case NIN_SELECT:
glfwShowWindow(gDrawData->window);
glfwRestoreWindow(gDrawData->window);
break;
}
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}

View File

@@ -1,16 +1,15 @@
#pragma once #pragma once
#include <vector>
#include "ImguiBase.h" #include "ImguiBase.h"
#include "ApplicationData.h" #include "ApplicationData.h"
#include <vector>
void init(DrawData& drawData, ApplicationData& customData); void init(DrawData& drawData, ApplicationData& customData);
void draw(DrawData& drawData, ApplicationData& customData); void draw(DrawData& drawData, ApplicationData& customData);
void cleanup(DrawData& drawData, ApplicationData& appData); void cleanup(DrawData& drawData, ApplicationData& appData);
ImVec2 menuBar(DrawData& drawData, ApplicationData& appData); ImVec2 menuBar(DrawData& drawData, ApplicationData& appData);
ImVec2 checklistWindow(ApplicationData& appData, const char* title);
ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& deviceList, const char* title); ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& deviceList, const char* title);
void drawCircle(float radius, ImU32 color); void drawCircle(float radius, ImU32 color);
LRESULT trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam);

View File

@@ -71,8 +71,8 @@ IDI_ICON1 ICON "kaiju.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1 FILEVERSION 1,0,4,1
PRODUCTVERSION 1,0,0,1 PRODUCTVERSION 1,0,4,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@@ -89,12 +89,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Asuro" VALUE "CompanyName", "Asuro"
VALUE "FileDescription", "Audio Thingy" VALUE "FileDescription", "Audio Thingy"
VALUE "FileVersion", "1.0.0.1" VALUE "FileVersion", "1.0.4.1"
VALUE "InternalName", "AsuroTool.exe" VALUE "InternalName", "AsuroTool.exe"
VALUE "LegalCopyright", "Copyright (C) 2022" VALUE "LegalCopyright", "Copyright (C) 2022"
VALUE "OriginalFilename", "AsuroTool.exe" VALUE "OriginalFilename", "AsuroTool.exe"
VALUE "ProductName", "Audio Thingy" VALUE "ProductName", "Audio Thingy"
VALUE "ProductVersion", "1.0.0.1" VALUE "ProductVersion", "1.0.4.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@@ -111,7 +111,7 @@ END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_STRING_TOOLTIP "uwu" IDS_STRING_TOOLTIP "Audio Thingy"
END END
#endif // English (United Kingdom) resources #endif // English (United Kingdom) resources

View File

@@ -93,10 +93,14 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings> <DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -108,12 +112,16 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings> <DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -123,10 +131,14 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings> <DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -138,12 +150,16 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings> <DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@@ -152,6 +168,7 @@
<ClCompile Include="AudioNotificationListener.cpp" /> <ClCompile Include="AudioNotificationListener.cpp" />
<ClCompile Include="Settings.cpp" /> <ClCompile Include="Settings.cpp" />
<ClCompile Include="Util.cpp" /> <ClCompile Include="Util.cpp" />
<ClCompile Include="WindowsShell.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="ApplicationData.h" /> <ClInclude Include="ApplicationData.h" />
@@ -163,6 +180,7 @@
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="Settings.h" /> <ClInclude Include="Settings.h" />
<ClInclude Include="Util.h" /> <ClInclude Include="Util.h" />
<ClInclude Include="WindowsShell.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ImguiBase\ImguiBase.vcxproj"> <ProjectReference Include="..\ImguiBase\ImguiBase.vcxproj">

View File

@@ -39,6 +39,9 @@
<ClCompile Include="Settings.cpp"> <ClCompile Include="Settings.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="WindowsShell.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="AsuroTool.h"> <ClInclude Include="AsuroTool.h">
@@ -65,6 +68,9 @@
<ClInclude Include="PolicyConfig.h"> <ClInclude Include="PolicyConfig.h">
<Filter>Header Files\Audio</Filter> <Filter>Header Files\Audio</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="WindowsShell.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CopyFileToFolders Include="Montserrat-Regular.ttf"> <CopyFileToFolders Include="Montserrat-Regular.ttf">

View File

@@ -1,14 +1,18 @@
#include "AudioApi.h"
#include "Util.h"
#include "PolicyConfig.h"
#include <windows.h> #include <windows.h>
#include <functiondiscoverykeys.h> #include <functiondiscoverykeys.h>
#include <endpointvolume.h> #include <endpointvolume.h>
#include <initguid.h>
#include <mmdeviceapi.h>
#include <array>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <iostream>
#include "Util.h"
#include "AudioApi.h"
#include "PolicyConfig.h"
void initAudio(ApplicationData& appData) void initAudio(ApplicationData& appData)
{ {
@@ -31,7 +35,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
deviceList.clear(); deviceList.clear();
HRESULT err; HRESULT err;
IMMDeviceCollection* deviceCollection = NULL; IMMDeviceCollection* deviceCollection = nullptr;
err = audioData.deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection); err = audioData.deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection);
if (isError(err, "Failed to enumerate audio devices: ")) return; if (isError(err, "Failed to enumerate audio devices: ")) return;
@@ -40,7 +44,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
err = deviceCollection->GetCount(&deviceCount); err = deviceCollection->GetCount(&deviceCount);
if (isError(err, "Failed to count audio devices: ")) return; if (isError(err, "Failed to count audio devices: ")) return;
IMMDevice* defaultConsoleDevice = NULL; IMMDevice* defaultConsoleDevice = nullptr;
LPWSTR defaultConsoleId = nullptr; LPWSTR defaultConsoleId = nullptr;
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
if (!FAILED(err)) if (!FAILED(err))
@@ -48,7 +52,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
defaultConsoleDevice->GetId(&defaultConsoleId); defaultConsoleDevice->GetId(&defaultConsoleId);
} }
IMMDevice* defaultMediaOutput = NULL; IMMDevice* defaultMediaOutput = nullptr;
LPWSTR defaultMediaId = nullptr; LPWSTR defaultMediaId = nullptr;
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
if (!FAILED(err)) if (!FAILED(err))
@@ -56,7 +60,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
defaultMediaOutput->GetId(&defaultMediaId); defaultMediaOutput->GetId(&defaultMediaId);
} }
IMMDevice* defaultCommunicationOutput = NULL; IMMDevice* defaultCommunicationOutput = nullptr;
LPWSTR defaultCommunicationId = nullptr; LPWSTR defaultCommunicationId = nullptr;
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput); err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
if (!FAILED(err)) if (!FAILED(err))
@@ -66,57 +70,35 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
for (UINT i = 0; i < deviceCount; i += 1) for (UINT i = 0; i < deviceCount; i += 1)
{ {
AudioDevice deviceData{}; IMMDevice* device;
err = deviceCollection->Item(i, &device);
err = deviceCollection->Item(i, &deviceData.device);
if (isError(err, std::stringstream("Failed to get device ") << i << ": ")) if (isError(err, std::stringstream("Failed to get device ") << i << ": "))
{ {
continue; continue;
} }
LPWSTR deviceId; LPWSTR deviceId;
err = deviceData.device->GetId(&deviceId); err = device->GetId(&deviceId);
isError(err, std::stringstream("Failed to get device id ") << i << ": "); if (!isError(err, std::stringstream("Failed to get device id ") << i << ": "))
deviceData.id = std::wstring(deviceId);
IPropertyStore* propertyStore;
err = deviceData.device->OpenPropertyStore(STGM_READ, &propertyStore);
isError(err, std::stringstream("Failed to open device ") << i << "prop store: ");
PROPVARIANT deviceNameProp;
const wchar_t* deviceName;
err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
isError(err, std::stringstream("Failed to read name of device ") << i << ": ");
deviceData.name = utf8Encode(deviceName);
err = deviceData.device->GetState(&deviceData.state);
isError(err, std::stringstream("Failed to reat state of device ") << i << ": ");
err = deviceData.device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&deviceData.volumeInterface);
isError(err, "Failed to get audio endpoint volume interface: ");
err = deviceData.device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&deviceData.meterInterface);
isError(err, "Failed to get audio meter interface: ");
if (defaultConsoleId)
{ {
deviceData.isDefaultConsole = wcscmp(defaultConsoleId, deviceId) == 0; AudioDevice audioDevice(device, deviceId);
}
if (defaultMediaId) if (defaultConsoleId)
{ {
deviceData.isDefaultMedia = wcscmp(defaultMediaId, deviceId) == 0; audioDevice.isDefaultConsole = wcscmp(defaultConsoleId, deviceId) == 0;
} }
if (defaultCommunicationId) if (defaultMediaId)
{ {
deviceData.isDefaultCommunication = wcscmp(defaultCommunicationId, deviceId) == 0; audioDevice.isDefaultMedia = wcscmp(defaultMediaId, deviceId) == 0;
}
if (defaultCommunicationId)
{
audioDevice.isDefaultCommunication = wcscmp(defaultCommunicationId, deviceId) == 0;
}
deviceList.push_back(std::move(audioDevice));
} }
deviceList.push_back(std::move(deviceData));
if (propertyStore)
{
propertyStore->Release();
}
CoTaskMemFree(deviceId); CoTaskMemFree(deviceId);
} }
@@ -150,7 +132,7 @@ HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY
void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole role) void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole role)
{ {
IPolicyConfigVista* pPolicyConfig; IPolicyConfigVista* pPolicyConfig = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig); HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient), NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig);
if (!isError(hr, "Failed to set default audio device: ")) if (!isError(hr, "Failed to set default audio device: "))
@@ -178,13 +160,85 @@ void setVolume(IAudioEndpointVolume* volumeInterface, float newVolume)
isError(hr, "Failed to set volume level: "); isError(hr, "Failed to set volume level: ");
} }
float getMeterValue(IAudioMeterInformation* meterInterface) UINT getMeterValues(IAudioMeterInformation* meterInterface, std::array<float, 2>& outLevels)
{ {
float volume; UINT channelCount;
if (FAILED(meterInterface->GetPeakValue(&volume))) if (FAILED(meterInterface->GetMeteringChannelCount(&channelCount)) || channelCount > 2) return 0;
{
volume = 0.;
}
return volume; if (FAILED(meterInterface->GetChannelsPeakValues(channelCount, &outLevels[0]))) return 0;
return channelCount;
}
void getVolumeLimit(IAudioEndpointVolume* volumeInterface, float* outMin, float* outMax)
{
float dummy;
volumeInterface->GetVolumeRange(outMin, outMax, &dummy);
}
bool isMuted(IAudioEndpointVolume* volumeInterface)
{
BOOL result = false;
if (FAILED(volumeInterface->GetMute(&result))) return false;
return static_cast<bool>(result);
}
void setMuted(IAudioEndpointVolume* volumeInterface, bool newState)
{
volumeInterface->SetMute(static_cast<BOOL>(newState), NULL);
}
void CreateLoudnessEqualizationKey(PROPERTYKEY& key)
{
// Realtek: const wchar_t* guid = L"E0A941A0-88A2-4df5-8D6B-DD20BB06E8FB";
const wchar_t* guid = L"FC52A749-4BE9-4510-896E-966BA6525980";
UuidFromString((RPC_WSTR)guid, &key.fmtid);
key.pid = 3;
}
AudioProcessingState getAudioProcessing(AudioDevice& device)
{
return AudioProcessingState::Unknown;
LPWSTR pwstrEndpointId = NULL;
HRESULT hr = device.device->GetId(&pwstrEndpointId);
IPolicyConfig* pPolicyConfig;
hr = CoCreateInstance(__uuidof(CPolicyConfigClient), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pPolicyConfig));
if (SUCCEEDED(hr))
{
PROPVARIANT var;
PropVariantInit(&var);
PROPERTYKEY key{};
CreateLoudnessEqualizationKey(key);
hr = pPolicyConfig->GetPropertyValue(pwstrEndpointId, TRUE, key, &var);
pPolicyConfig->Release();
return var.boolVal ? AudioProcessingState::Disabled : AudioProcessingState::Enabled;
}
return AudioProcessingState::Unknown;
}
void setAudioProcessing(AudioDevice& device, bool newVal)
{
return;
LPWSTR pwstrEndpointId = NULL;
HRESULT hr = device.device->GetId(&pwstrEndpointId);
IPolicyConfig* pPolicyConfig;
hr = CoCreateInstance(__uuidof(CPolicyConfigClient), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pPolicyConfig));
if (SUCCEEDED(hr))
{
PROPVARIANT var;
PropVariantInit(&var);
var.vt = VT_UI4;
var.uintVal = newVal ? ENDPOINT_SYSFX_ENABLED : ENDPOINT_SYSFX_DISABLED;
PROPERTYKEY key{};
CreateLoudnessEqualizationKey(key);
hr = pPolicyConfig->SetPropertyValue(pwstrEndpointId, TRUE, key, &var);
pPolicyConfig->Release();
}
} }

View File

@@ -1,9 +1,14 @@
#pragma once #pragma once
#include <mmdeviceapi.h>
#include "ApplicationData.h" #include "ApplicationData.h"
enum class AudioProcessingState
{
Enabled,
Disabled,
Unknown
};
void initAudio(ApplicationData& appData); void initAudio(ApplicationData& appData);
void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType); void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType);
void reloadDeviceLists(AudioData& audioData); void reloadDeviceLists(AudioData& audioData);
@@ -14,4 +19,9 @@ void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole
float getVolume(IAudioEndpointVolume* volumeInterface); float getVolume(IAudioEndpointVolume* volumeInterface);
void setVolume(IAudioEndpointVolume* volumeInterface, float newVolume); void setVolume(IAudioEndpointVolume* volumeInterface, float newVolume);
float getMeterValue(IAudioMeterInformation* meterInterface); UINT getMeterValues(IAudioMeterInformation* meterInterface, std::array<float, 2>& levels);
void getVolumeLimit(IAudioEndpointVolume* volumeInterface, float* outMin, float* outMax);
bool isMuted(IAudioEndpointVolume* volumeInterface);
void setMuted(IAudioEndpointVolume* volumeInterface, bool newState);
AudioProcessingState getAudioProcessing(AudioDevice& device);
void setAudioProcessing(AudioDevice& device, bool newVal);

View File

@@ -34,7 +34,25 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceAdded(LPCWSTR pwstrDeviceId
HRESULT result = audioData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice); HRESULT result = audioData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice);
if (SUCCEEDED(result) && newDevice != nullptr) if (SUCCEEDED(result) && newDevice != nullptr)
{ {
// TODO: add to device list IMMEndpoint* endpoint;
result = newDevice->QueryInterface(&endpoint);
if (SUCCEEDED(result) && endpoint != nullptr)
{
EDataFlow dataFlow;
result = endpoint->GetDataFlow(&dataFlow);
if (SUCCEEDED(result))
{
AudioDevice audioDevice(newDevice, pwstrDeviceId);
if (dataFlow == EDataFlow::eCapture)
{
audioData->recordingDevices.push_back(std::move(audioDevice));
}
else
{
audioData->playbackDevices.push_back(std::move(audioDevice));
}
}
}
} }
return result; return result;
@@ -50,7 +68,9 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceRemoved(LPCWSTR pwstrDevice
if (wcscmp(deviceListIterator->id.c_str(), pwstrDeviceId) == 0) if (wcscmp(deviceListIterator->id.c_str(), pwstrDeviceId) == 0)
{ {
deviceListIterator = deviceList.erase(deviceListIterator); deviceListIterator = deviceList.erase(deviceListIterator);
continue;
} }
deviceListIterator++;
} }
}; };
@@ -126,7 +146,7 @@ HRESULT __stdcall AudioNotificationListener::QueryInterface(REFIID riid, void**
} }
else else
{ {
*ppvObject = NULL; *ppvObject = nullptr;
return E_NOINTERFACE; return E_NOINTERFACE;
} }

View File

@@ -1,8 +1,10 @@
#pragma once #pragma once
#include <memory> #include <initguid.h>
#include <mmdeviceapi.h> #include <mmdeviceapi.h>
#include <memory>
class AudioData; class AudioData;
class ApplicationData; class ApplicationData;
class AudioNotificationListener : public IMMNotificationClient { class AudioNotificationListener : public IMMNotificationClient {

View File

@@ -115,6 +115,9 @@ public:
PCWSTR, PCWSTR,
INT INT
); );
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(PCWSTR pszDeviceName, BOOL bFxStore, const PROPERTYKEY& pKey, PROPVARIANT* pv) = 0;
virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(PCWSTR pszDeviceName, BOOL bFxStore, const PROPERTYKEY& pKey, PROPVARIANT* pv) = 0;
}; };
interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") IPolicyConfigVista; interface DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") IPolicyConfigVista;

View File

@@ -3,6 +3,8 @@
#include "Util.h" #include "Util.h"
#include "Settings.h" #include "Settings.h"
#include <chrono>
extern bool justDocked; extern bool justDocked;
extern DrawData* gDrawData; extern DrawData* gDrawData;
extern ApplicationData* gAppData; extern ApplicationData* gAppData;
@@ -10,8 +12,8 @@ extern ApplicationData* gAppData;
void initSettings(DrawData& drawData, ApplicationData& appData) void initSettings(DrawData& drawData, ApplicationData& appData)
{ {
ImGuiSettingsHandler ini_handler; ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "ApplicationSettings"; ini_handler.TypeName = APPLICATION_SETTINGS_GROUP;
ini_handler.TypeHash = ImHashStr("ApplicationSettings"); ini_handler.TypeHash = ImHashStr(APPLICATION_SETTINGS_GROUP);
ini_handler.ReadOpenFn = settingsReadOpen; ini_handler.ReadOpenFn = settingsReadOpen;
ini_handler.ReadLineFn = settingsReadLine; ini_handler.ReadLineFn = settingsReadLine;
ini_handler.WriteAllFn = settingsWriteAll; ini_handler.WriteAllFn = settingsWriteAll;
@@ -29,6 +31,8 @@ void* settingsReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const c
void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line) void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line)
{ {
if (strlen(line) == 0) return;
ApplicationSettings* settings = (ApplicationSettings*)entry; ApplicationSettings* settings = (ApplicationSettings*)entry;
int docked; int docked;
@@ -36,19 +40,54 @@ void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* en
{ {
settings->docked = (bool)docked; settings->docked = (bool)docked;
} }
int autostart; int autostart;
if (sscanf_s(line, "autostart=%i", &autostart)) if (sscanf_s(line, "autostart=%i", &autostart))
{ {
settings->autostart = (bool)autostart; settings->autostart = (bool)autostart;
} }
std::string taskName{};
taskName.resize(MAX_TASK_NAME_LENGTH);
if (sscanf_s(line, "taskname=%s", &taskName[0], MAX_TASK_NAME_LENGTH))
{
settings->taskNames.push_back(taskName);
}
std::string task{};
task.resize(MAX_TASK_NAME_LENGTH);
time_t dayTimestamp;
if (sscanf_s(line, "task=%lld %s", &dayTimestamp, &task[0], MAX_TASK_NAME_LENGTH))
{
if (settings->tasks.contains(task))
{
settings->tasks[task].push_back(dayTimestamp);
}
else
{
settings->tasks.insert({ task, std::vector{ dayTimestamp } });
}
}
} }
void settingsWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* outBuf) void settingsWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* outBuf)
{ {
outBuf->appendf("[%s][%s]\n", "ApplicationSettings", "ApplicationSettings"); outBuf->appendf("[%s][%s]\n", APPLICATION_SETTINGS_GROUP, APPLICATION_SETTINGS_GROUP);
outBuf->appendf("docked=%i\n", (int)gAppData->settings.docked); outBuf->appendf("docked=%i\n", (int)gAppData->settings.docked);
outBuf->appendf("autostart=%i\n", (int)gAppData->settings.autostart); outBuf->appendf("autostart=%i\n", (int)gAppData->settings.autostart);
outBuf->append("\n");
for (std::string& taskName : gAppData->settings.taskNames)
{
outBuf->appendf("taskname=%s\n", taskName.c_str());
}
for (auto& task : gAppData->settings.tasks)
{
for (auto& date : task.second)
{
outBuf->appendf("task=%lld %s\n", date, task.first.c_str());
}
}
} }
void applySettings(DrawData& drawData, ApplicationData& appData) void applySettings(DrawData& drawData, ApplicationData& appData)
@@ -74,19 +113,16 @@ void setAutostart(bool newValue)
HRESULT hr; HRESULT hr;
HKEY runKey = NULL; HKEY runKey = nullptr;
hr = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &runKey); hr = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &runKey);
if (isError(hr, "Failed to find/create autostart run key: ")) return; if (isError(hr, "Failed to find/create autostart run key: ")) return;
if (newValue) if (newValue)
{ {
std::wstring appPath; std::wstring appPath;
appPath.resize(MAX_PATH_LENGTH); if (FAILED(getAppPath(appPath))) return;
hr = GetModuleFileName(NULL, &appPath[0], static_cast<DWORD>(appPath.size()));
if (isError(hr, "Failed to get executable name: ")) return;
appPath.resize(wcslen(appPath.data()));
hr = RegSetValueEx(runKey, KEY_APP_NAME, 0, REG_SZ, (BYTE*)appPath.c_str(), (appPath.size() + 1) * sizeof(wchar_t)); hr = RegSetValueEx(runKey, KEY_APP_NAME, 0, REG_SZ, (BYTE*)appPath.c_str(), static_cast<DWORD>((appPath.size() + 1) * sizeof(wchar_t)));
if (isError(hr, "Failed to write autostart key: ")) return; if (isError(hr, "Failed to write autostart key: ")) return;
} }
else else

View File

@@ -1,8 +1,11 @@
#pragma once #pragma once
#include "ApplicationData.h"
#include "ImguiBase.h" #include "ImguiBase.h"
#include <imgui_internal.h> #include <imgui_internal.h>
#include "ApplicationData.h" #define APPLICATION_SETTINGS_GROUP "ApplicationSettings"
#define MAX_TASK_NAME_LENGTH 1024
void initSettings(DrawData& drawData, ApplicationData& appData); void initSettings(DrawData& drawData, ApplicationData& appData);

View File

@@ -1,6 +1,7 @@
#include <iostream> #include <iostream>
#include "Util.h" #include "Util.h"
#include "pathcch.h"
bool isError(const HRESULT result, const std::stringstream message) bool isError(const HRESULT result, const std::stringstream message)
{ {
@@ -29,3 +30,24 @@ std::string utf8Encode(const std::wstring& wstr)
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &resultString[0], sizeNeeded, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &resultString[0], sizeNeeded, NULL, NULL);
return resultString; return resultString;
} }
HRESULT getAppPath(std::wstring& outPath)
{
const size_t MAX_PATH_LENGTH = 32767;
outPath.resize(MAX_PATH_LENGTH);
HRESULT hr = GetModuleFileName(NULL, &outPath[0], static_cast<DWORD>(outPath.size()));
if (isError(hr, "Failed to get executable name: ")) return hr;
outPath.resize(wcslen(outPath.data()));
return hr;
}
HRESULT getAppDir(std::wstring& outPath)
{
HRESULT hr = getAppPath(outPath);
if (FAILED(hr)) return hr;
hr = PathCchRemoveFileSpec(&outPath[0], static_cast<DWORD>(outPath.size()));
if (isError(hr, "Failed to get executable dir: ")) return hr;
outPath.resize(wcslen(outPath.data()));
return hr;
}

View File

@@ -1,8 +1,11 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <sstream> #include <sstream>
bool isError(const HRESULT result, const std::stringstream message); bool isError(const HRESULT result, const std::stringstream message);
bool isError(const HRESULT result, const char* message); bool isError(const HRESULT result, const char* message);
std::string utf8Encode(const std::wstring& wstr); std::string utf8Encode(const std::wstring& wstr);
HRESULT getAppPath(std::wstring& outPath);
HRESULT getAppDir(std::wstring& outPath);

102
AsuroTool/WindowsShell.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include "WindowsShell.h"
#include "resource.h"
#include "ApplicationData.h"
#include "Util.h"
#include <Windows.h>
#include <shellapi.h>
#include <commctrl.h>
#include <strsafe.h>
#include <iostream>
const UINT TRAY_ID = 420;
const UINT WMAPP_NOTIFYCALLBACK = WM_APP + 1;
extern DrawData* gDrawData;
extern ApplicationData* gAppData;
extern bool justDocked;
extern bool isHidden;
void initShell(DrawData& drawData)
{
// Set window icon
HINSTANCE instance = GetModuleHandle(NULL);
LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
HANDLE iconLarge = LoadImageW(instance, iconId, IMAGE_ICON, 64, 64, 0);
HANDLE iconSmall = LoadImageW(instance, iconId, IMAGE_ICON, 32, 32, 0);
SendMessage(drawData.window_handle, WM_SETICON, ICON_BIG, (LPARAM)iconLarge);
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL2, (LPARAM)iconSmall);
// Set tray icon
NOTIFYICONDATA nid = { sizeof(nid) };
nid.hWnd = drawData.window_handle;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP;
nid.uID = TRAY_ID;
nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK;
HRESULT iconResult;
iconResult = LoadIconMetric(instance, iconId, LIM_SMALL, &nid.hIcon);
isError(iconResult, "Failed to load tray icon image: ");
iconResult = LoadString(instance, IDS_STRING_TOOLTIP, nid.szTip, ARRAYSIZE(nid.szTip));
isError(iconResult, "Failed to load tray icon text: ");
Shell_NotifyIcon(NIM_ADD, &nid);
nid.uVersion = NOTIFYICON_VERSION_4;
Shell_NotifyIcon(NIM_SETVERSION, &nid);
if (!SetWindowsHookEx(WH_CALLWNDPROC, trayIconEventHandler, instance, GetCurrentThreadId()))
{
std::cout << "Failed to hook tray icon events: " << std::hex << GetLastError() << std::endl;
}
// Set window minimize behavior
glfwSetWindowIconifyCallback(drawData.window, [](GLFWwindow* window, int isIconified) {
if (isIconified && gAppData->settings.docked)
{
glfwHideWindow(window);
}
isHidden = isIconified;
});
glfwSetWindowFocusCallback(drawData.window, [](GLFWwindow* window, int isFocused) {
if (!isFocused && gAppData->settings.docked && !justDocked)
{
glfwIconifyWindow(window);
}
});
}
void cleanupShell(DrawData& drawData)
{
// Remove tray icon
NOTIFYICONDATA nid = { sizeof(nid) };
nid.hWnd = drawData.window_handle;
nid.uID = TRAY_ID;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
LRESULT CALLBACK trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam)
{
if (code >= 0)
{
CWPSTRUCT* data = (CWPSTRUCT*)lParam;
if (data->message == WMAPP_NOTIFYCALLBACK)
{
auto id = HIWORD(data->lParam);
auto trayEvent = LOWORD(data->lParam);
if (id == TRAY_ID && (trayEvent == WM_LBUTTONUP || trayEvent == WM_RBUTTONUP))
{
glfwShowWindow(gDrawData->window);
glfwRestoreWindow(gDrawData->window);
}
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}

8
AsuroTool/WindowsShell.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <ImguiBase.h>
void initShell(DrawData& drawData);
void cleanupShell(DrawData& drawData);
LRESULT trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam);

View File

@@ -9,6 +9,7 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "imgui.h" #include "imgui.h"
#include "remixicon.h"
class DrawData { class DrawData {
public: public:

View File

@@ -107,6 +107,8 @@
<Lib> <Lib>
<AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -130,6 +132,8 @@
<Lib> <Lib>
<AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -149,6 +153,8 @@
<Lib> <Lib>
<AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -172,6 +178,8 @@
<Lib> <Lib>
<AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>E:\Code\glfw-3.3.7.bin.WIN64\lib-vc2022;D:\Applications\VulkanSDK\1.2.182.0\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Lib> </Lib>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@@ -194,6 +202,7 @@
<ClInclude Include="imgui\headers\imstb_rectpack.h" /> <ClInclude Include="imgui\headers\imstb_rectpack.h" />
<ClInclude Include="imgui\headers\imstb_textedit.h" /> <ClInclude Include="imgui\headers\imstb_textedit.h" />
<ClInclude Include="imgui\headers\imstb_truetype.h" /> <ClInclude Include="imgui\headers\imstb_truetype.h" />
<ClInclude Include="remixicon.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Font Include="Montserrat-Regular.ttf" /> <Font Include="Montserrat-Regular.ttf" />

View File

@@ -74,6 +74,9 @@
<ClInclude Include="ImguiBase.h"> <ClInclude Include="ImguiBase.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="remixicon.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Font Include="Montserrat-Regular.ttf"> <Font Include="Montserrat-Regular.ttf">

2273
ImguiBase/remixicon.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -96,6 +96,8 @@
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -112,6 +114,8 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -124,6 +128,8 @@
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -140,6 +146,8 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>